Compare commits

...

5 Commits

Author SHA1 Message Date
huntharo
1ec21f95af test: satisfy boundary lint rules 2026-04-08 21:32:16 -04:00
huntharo
6ad7b048df test: type extension boundary helper paths 2026-04-08 21:21:12 -04:00
huntharo
2d497c048c test: keep xai tests on scoped plugin sdk imports 2026-04-08 21:05:20 -04:00
huntharo
a895f2d276 test: type boundary path map contract 2026-04-08 20:46:17 -04:00
huntharo
5e72cfd2cb build: block legacy plugin sdk imports in xai 2026-04-08 20:27:43 -04:00
19 changed files with 168 additions and 88 deletions

View File

@@ -8,7 +8,7 @@ import {
applyXaiModelCompat,
resolveXaiModelCompatPatch,
} from "@openclaw/plugin-sdk/provider-tools";
import { readStringValue } from "openclaw/plugin-sdk/text-runtime";
import { readStringValue } from "@openclaw/plugin-sdk/text-runtime";
export { buildXaiProvider } from "./provider-catalog.js";
export { applyXaiConfig, applyXaiProviderConfig } from "./onboard.js";

View File

@@ -1,4 +1,4 @@
import { withFetchPreconnect } from "openclaw/plugin-sdk/testing";
import { withFetchPreconnect } from "@openclaw/plugin-sdk/testing";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createCodeExecutionTool } from "./code-execution.js";

View File

@@ -1,6 +1,6 @@
import { Type } from "@sinclair/typebox";
import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/config-runtime";
import { jsonResult, readStringParam } from "openclaw/plugin-sdk/provider-web-search";
import { getRuntimeConfigSnapshot } from "@openclaw/plugin-sdk/config-runtime";
import { jsonResult, readStringParam } from "@openclaw/plugin-sdk/provider-web-search";
import {
buildXaiCodeExecutionPayload,
requestXaiCodeExecution,

View File

@@ -1,7 +1,7 @@
import { Type } from "@sinclair/typebox";
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
import { jsonResult, readProviderEnvValue } from "openclaw/plugin-sdk/provider-web-search";
import { defineSingleProviderPluginEntry } from "@openclaw/plugin-sdk/provider-entry";
import { buildProviderReplayFamilyHooks } from "@openclaw/plugin-sdk/provider-model-shared";
import { jsonResult, readProviderEnvValue } from "@openclaw/plugin-sdk/provider-web-search";
import {
applyXaiModelCompat,
normalizeXaiModelId,

View File

@@ -1,5 +1,5 @@
import type { ModelDefinitionConfig } from "openclaw/plugin-sdk/provider-model-shared";
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
import type { ModelDefinitionConfig } from "@openclaw/plugin-sdk/provider-model-shared";
import { normalizeOptionalLowercaseString } from "@openclaw/plugin-sdk/text-runtime";
export const XAI_BASE_URL = "https://api.x.ai/v1";
export const XAI_DEFAULT_MODEL_ID = "grok-4";

View File

@@ -1,7 +1,7 @@
import {
resolveAgentModelFallbackValues,
resolveAgentModelPrimaryValue,
} from "openclaw/plugin-sdk/provider-onboard";
} from "@openclaw/plugin-sdk/provider-onboard";
import { describe, expect, it } from "vitest";
import {
createConfigWithFallbacks,

View File

@@ -1,9 +1,9 @@
import type {
ProviderResolveDynamicModelContext,
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-model-shared";
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
} from "@openclaw/plugin-sdk/plugin-entry";
import { normalizeModelCompat } from "@openclaw/plugin-sdk/provider-model-shared";
import { normalizeOptionalLowercaseString } from "@openclaw/plugin-sdk/text-runtime";
import { applyXaiModelCompat } from "./api.js";
import { resolveXaiCatalogEntry, XAI_BASE_URL } from "./model-definitions.js";

View File

@@ -1,4 +1,4 @@
import { NON_ENV_SECRETREF_MARKER } from "openclaw/plugin-sdk/provider-auth-runtime";
import { NON_ENV_SECRETREF_MARKER } from "@openclaw/plugin-sdk/provider-auth-runtime";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
isXaiToolEnabled,

View File

@@ -1,4 +1,4 @@
import { isRecord } from "openclaw/plugin-sdk/text-runtime";
import { isRecord } from "@openclaw/plugin-sdk/text-runtime";
import { normalizeXaiModelId } from "../model-id.js";
export { isRecord };

View File

@@ -4,54 +4,54 @@
"rootDir": ".",
"paths": {
"openclaw/extension-api": ["../../src/extensionAPI.ts"],
"openclaw/plugin-sdk": ["../../dist/plugin-sdk/src/plugin-sdk/index.d.ts"],
"openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/src/plugin-sdk/*.d.ts"],
"openclaw/plugin-sdk/account-id": ["../../dist/plugin-sdk/src/plugin-sdk/account-id.d.ts"],
"openclaw/plugin-sdk": ["./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"],
"openclaw/plugin-sdk/*": ["./.boundary-stubs/forbidden-openclaw-plugin-sdk-*.d.ts"],
"openclaw/plugin-sdk/account-id": ["./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"],
"openclaw/plugin-sdk/channel-entry-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-entry-contract.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/browser-maintenance": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-maintenance.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/browser-config-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-config-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/browser-node-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-node-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/browser-setup-tools": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-setup-tools.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/browser-security-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-security-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/channel-secret-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-secret-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/channel-streaming": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-streaming.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/cli-runtime": ["../../dist/plugin-sdk/src/plugin-sdk/cli-runtime.d.ts"],
"openclaw/plugin-sdk/cli-runtime": ["./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"],
"openclaw/plugin-sdk/error-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/error-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/provider-catalog-shared": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-catalog-shared.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/provider-env-vars": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-env-vars.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/provider-entry": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/provider-web-search-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-web-search-contract.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/secret-ref-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/secret-ref-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"openclaw/plugin-sdk/ssrf-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/ssrf-runtime.d.ts"
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts"
],
"@openclaw/*.js": ["../../packages/plugin-sdk/dist/extensions/*.d.ts", "../*"],
"@openclaw/*": ["../*"],

View File

@@ -1,17 +1,17 @@
import { isProviderApiKeyConfigured } from "openclaw/plugin-sdk/provider-auth";
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
import { isProviderApiKeyConfigured } from "@openclaw/plugin-sdk/provider-auth";
import { resolveApiKeyForProvider } from "@openclaw/plugin-sdk/provider-auth-runtime";
import {
assertOkOrThrowHttpError,
fetchWithTimeout,
postJsonRequest,
resolveProviderHttpRequestConfig,
} from "openclaw/plugin-sdk/provider-http";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
} from "@openclaw/plugin-sdk/provider-http";
import { normalizeOptionalString } from "@openclaw/plugin-sdk/text-runtime";
import type {
GeneratedVideoAsset,
VideoGenerationProvider,
VideoGenerationRequest,
} from "openclaw/plugin-sdk/video-generation";
} from "@openclaw/plugin-sdk/video-generation";
const DEFAULT_XAI_VIDEO_BASE_URL = "https://api.x.ai/v1";
const DEFAULT_XAI_VIDEO_MODEL = "grok-imagine-video";

View File

@@ -1,7 +1,7 @@
import {
createWebSearchProviderContractFields,
type WebSearchProviderPlugin,
} from "openclaw/plugin-sdk/provider-web-search-config-contract";
} from "@openclaw/plugin-sdk/provider-web-search-config-contract";
export function createXaiWebSearchProvider(): WebSearchProviderPlugin {
const credentialPath = "plugins.entries.xai.config.webSearch.apiKey";

View File

@@ -1,6 +1,6 @@
import { NON_ENV_SECRETREF_MARKER } from "openclaw/plugin-sdk/provider-auth-runtime";
import { createNonExitingRuntime } from "openclaw/plugin-sdk/runtime-env";
import { withEnv } from "openclaw/plugin-sdk/testing";
import { NON_ENV_SECRETREF_MARKER } from "@openclaw/plugin-sdk/provider-auth-runtime";
import { createNonExitingRuntime } from "@openclaw/plugin-sdk/runtime-env";
import { withEnv } from "@openclaw/plugin-sdk/testing";
import { describe, expect, it, vi } from "vitest";
import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js";
import { resolveXaiCatalogEntry } from "./model-definitions.js";

View File

@@ -18,7 +18,7 @@ import {
type WebSearchProviderSetupContext,
type WebSearchProviderPlugin,
writeCache,
} from "openclaw/plugin-sdk/provider-web-search";
} from "@openclaw/plugin-sdk/provider-web-search";
import {
buildXaiWebSearchPayload,
extractXaiWebSearchContent,

View File

@@ -1,4 +1,4 @@
import { withFetchPreconnect } from "openclaw/plugin-sdk/testing";
import { withFetchPreconnect } from "@openclaw/plugin-sdk/testing";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createXSearchTool } from "./x-search.js";

View File

@@ -1,4 +1,4 @@
import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/config-runtime";
import { getRuntimeConfigSnapshot } from "@openclaw/plugin-sdk/config-runtime";
import {
jsonResult,
readCache,
@@ -7,7 +7,7 @@ import {
resolveCacheTtlMs,
resolveTimeoutSeconds,
writeCache,
} from "openclaw/plugin-sdk/provider-web-search";
} from "@openclaw/plugin-sdk/provider-web-search";
import { isXaiToolEnabled, resolveXaiToolApiKey } from "./src/tool-auth-shared.js";
import { resolveEffectiveXSearchConfig } from "./src/x-search-config.js";
import {

View File

@@ -28,6 +28,9 @@ const COMPILE_INPUT_EXTENSIONS = new Set([".ts", ".tsx", ".mts", ".cts", ".js",
const ROOTDIR_BOUNDARY_CANARY_IMPORT_PATH =
"../../src/plugins/contracts/rootdir-boundary-canary.ts";
const ROOTDIR_BOUNDARY_CANARY_OUTPUT_HINT = "src/plugins/contracts/rootdir-boundary-canary.ts";
const LEGACY_PLUGIN_SDK_CANARY_IMPORT_PATH = "openclaw/plugin-sdk/provider-entry";
const LEGACY_PLUGIN_SDK_CANARY_OUTPUT_HINT = "openclaw/plugin-sdk/provider-entry";
const XAI_LEGACY_PLUGIN_SDK_FORBIDDEN_HINT = "forbidden-openclaw-plugin-sdk";
function parseMode(argv) {
const modeArg = argv.find((arg) => arg.startsWith("--mode="));
@@ -174,6 +177,16 @@ function readExtensionTsconfig(extensionId) {
return readJsonFile(resolveExtensionTsconfigPath(extensionId));
}
function hasLegacyPluginSdkPoison(tsconfig) {
const legacyPath = tsconfig?.compilerOptions?.paths?.["openclaw/plugin-sdk"];
return (
Array.isArray(legacyPath) &&
legacyPath.some(
(entry) => typeof entry === "string" && entry.includes(XAI_LEGACY_PLUGIN_SDK_FORBIDDEN_HINT),
)
);
}
function collectOptInExtensionIds() {
return collectBundledExtensionIds().filter((extensionId) => {
const tsconfigPath = resolveExtensionTsconfigPath(extensionId);
@@ -666,6 +679,7 @@ async function runCanaryCheck(extensionIds) {
await Promise.all(
extensionIds.map(async (extensionId, index) => {
const { canaryPath, tsconfigPath } = resolveCanaryArtifactPaths(extensionId);
const extensionTsconfig = readExtensionTsconfig(extensionId);
cleanupCanaryArtifacts(extensionId);
process.stdout.write(`[${index + 1}/${extensionIds.length}] ${extensionId} canary\n`);
@@ -710,6 +724,44 @@ async function runCanaryCheck(extensionIds) {
if (!output.includes("TS6059") || !output.includes(ROOTDIR_BOUNDARY_CANARY_OUTPUT_HINT)) {
throw error;
}
if (hasLegacyPluginSdkPoison(extensionTsconfig)) {
writeFileSync(
canaryPath,
[
`import { defineSingleProviderPluginEntry } from "${LEGACY_PLUGIN_SDK_CANARY_IMPORT_PATH}";`,
"void defineSingleProviderPluginEntry;",
"export {};",
"",
].join("\n"),
"utf8",
);
try {
const legacyResult = await runNodeStepAsync(
`${extensionId} legacy-plugin-sdk canary`,
[tscBin, "-p", tsconfigPath, "--noEmit"],
120_000,
);
throw new Error(
`${extensionId} legacy-plugin-sdk canary unexpectedly passed\n${legacyResult.stdout}${legacyResult.stderr}`,
{ cause: error },
);
} catch (legacyError) {
const legacyOutput =
legacyError instanceof Error && typeof legacyError.fullOutput === "string"
? legacyError.fullOutput
: String(legacyError);
if (
!legacyOutput.includes(LEGACY_PLUGIN_SDK_CANARY_OUTPUT_HINT) ||
(!legacyOutput.includes("TS2307") &&
!legacyOutput.includes("Cannot find module") &&
!legacyOutput.includes("TS2305"))
) {
throw legacyError;
}
}
}
} finally {
cleanupCanaryArtifacts(extensionId);
}

View File

@@ -1,5 +1,5 @@
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { join, posix, resolve } from "node:path";
import { join, resolve } from "node:path";
export const EXTENSION_PACKAGE_BOUNDARY_BASE_CONFIG =
"extensions/tsconfig.package-boundary.base.json" as const;
@@ -65,46 +65,36 @@ export const EXTENSION_PACKAGE_BOUNDARY_BASE_PATHS = {
"@openclaw/plugin-sdk/*": ["../dist/plugin-sdk/src/plugin-sdk/*.d.ts"],
} as const;
function prefixExtensionPackageBoundaryPaths(
paths: Record<string, readonly string[]>,
prefix: string,
): Record<string, readonly string[]> {
return Object.fromEntries(
Object.entries(paths).map(([key, values]) => [
key,
values.map((value) => posix.join(prefix, value)),
]),
);
}
const XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH = [
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts",
] as const;
const XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_WILDCARD_PATH = [
"./.boundary-stubs/forbidden-openclaw-plugin-sdk-*.d.ts",
] as const;
export const EXTENSION_PACKAGE_BOUNDARY_XAI_PATHS = {
...prefixExtensionPackageBoundaryPaths(
(({
"openclaw/plugin-sdk/channel-secret-basic-runtime": _omitBasic,
"openclaw/plugin-sdk/channel-secret-tts-runtime": _omitTts,
...rest
}) => rest)(EXTENSION_PACKAGE_BOUNDARY_BASE_PATHS),
"../",
),
"openclaw/plugin-sdk/channel-entry-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-entry-contract.d.ts",
],
"openclaw/plugin-sdk/browser-maintenance": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-maintenance.d.ts",
],
"openclaw/plugin-sdk/cli-runtime": ["../../dist/plugin-sdk/src/plugin-sdk/cli-runtime.d.ts"],
"openclaw/plugin-sdk/provider-catalog-shared": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-catalog-shared.d.ts",
],
"openclaw/plugin-sdk/provider-env-vars": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-env-vars.d.ts",
],
"openclaw/plugin-sdk/provider-entry": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts",
],
"openclaw/extension-api": ["../../src/extensionAPI.ts"],
"openclaw/plugin-sdk": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/*": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_WILDCARD_PATH],
"openclaw/plugin-sdk/account-id": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/channel-entry-contract": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/browser-maintenance": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/browser-config-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/browser-node-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/browser-setup-tools": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/browser-security-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/channel-secret-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/channel-streaming": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/cli-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/error-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/provider-catalog-shared": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/provider-env-vars": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/provider-entry": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/provider-web-search-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-web-search-contract.d.ts",
...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH,
],
"openclaw/plugin-sdk/secret-ref-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"openclaw/plugin-sdk/ssrf-runtime": [...XAI_FORBIDDEN_LEGACY_PLUGIN_SDK_EXACT_PATH],
"@openclaw/*.js": ["../../packages/plugin-sdk/dist/extensions/*.d.ts", "../*"],
"@openclaw/*": ["../*"],
"@openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/src/plugin-sdk/*.d.ts"],
@@ -118,7 +108,7 @@ export type ExtensionPackageBoundaryTsConfigJson = {
extends?: unknown;
compilerOptions?: {
rootDir?: unknown;
paths?: unknown;
paths?: Record<string, readonly string[]>;
};
include?: unknown;
exclude?: unknown;

View File

@@ -1,5 +1,5 @@
import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { join, resolve } from "node:path";
import { describe, expect, it } from "vitest";
import {
collectExtensionsWithTsconfig,
@@ -22,7 +22,7 @@ const EXTENSION_PACKAGE_BOUNDARY_BASE_CONFIG =
type TsConfigJson = {
extends?: unknown;
compilerOptions?: {
paths?: unknown;
paths?: Record<string, readonly string[]>;
rootDir?: unknown;
outDir?: unknown;
declaration?: unknown;
@@ -42,6 +42,23 @@ function readJsonFile<T>(relativePath: string): T {
return JSON.parse(readFileSync(resolve(REPO_ROOT, relativePath), "utf8")) as T;
}
function collectFilesBySuffix(rootPath: string, suffix: string): string[] {
const files: string[] = [];
for (const entry of readdirSync(rootPath, { withFileTypes: true })) {
const entryPath = join(rootPath, entry.name);
if (entry.isDirectory()) {
files.push(...collectFilesBySuffix(entryPath, suffix));
continue;
}
if (entry.isFile() && entry.name.endsWith(suffix)) {
files.push(entryPath);
}
}
return files.toSorted();
}
describe("opt-in extension package boundaries", () => {
it("keeps path aliases in a dedicated shared config", () => {
const pathsConfig = readJsonFile<TsConfigJson>(EXTENSION_PACKAGE_BOUNDARY_PATHS_CONFIG);
@@ -86,6 +103,27 @@ describe("opt-in extension package boundaries", () => {
it("keeps xai's boundary-specific path overrides derived from the shared package boundary map", () => {
const tsconfig = readExtensionPackageBoundaryTsconfig("xai", REPO_ROOT);
expect(tsconfig.compilerOptions?.paths).toEqual(EXTENSION_PACKAGE_BOUNDARY_XAI_PATHS);
expect(tsconfig.compilerOptions?.paths?.["openclaw/plugin-sdk"]).toEqual([
"./.boundary-stubs/forbidden-openclaw-plugin-sdk.d.ts",
]);
expect(tsconfig.compilerOptions?.paths?.["openclaw/plugin-sdk/*"]).toEqual([
"./.boundary-stubs/forbidden-openclaw-plugin-sdk-*.d.ts",
]);
expect(tsconfig.compilerOptions?.paths?.["@openclaw/plugin-sdk/*"]).toEqual([
"../../dist/plugin-sdk/src/plugin-sdk/*.d.ts",
]);
});
it("keeps xai tests on the scoped plugin-sdk package name", () => {
const xaiRoot = resolve(REPO_ROOT, "extensions/xai");
const testFiles = collectFilesBySuffix(xaiRoot, ".test.ts");
expect(testFiles.length).toBeGreaterThan(0);
for (const filePath of testFiles) {
const contents = readFileSync(filePath, "utf8");
expect(contents).not.toContain('"openclaw/plugin-sdk/');
}
});
it("keeps plugin-sdk package types generated from the package build, not a hand-maintained types bridge", () => {