fix(plugin-sdk): back every workspace facade export with a real src facade (#121404)

* fix(plugin-sdk): back every workspace facade export with a real src facade

packages/plugin-sdk declared 59 export subpaths but only 24 had src facade
files; the other 35 defaults pointed at nonexistent ./src/<name>.ts targets
that typecheck (types resolve via boundary dist) but fail runtime resolution.
Create the 35 missing facades (each mirrors the sibling 3-line re-export of
the core src/plugin-sdk entrypoint; all verified live, none retired), and
extend scripts/sync-plugin-sdk-exports.mts to own the facade package too:
exports are regenerated from the src directory, every facade must name a
canonical SDK entrypoint, and --check fails on dangling keys or orphan
facades. The check-changed Plugin SDK surface lane now also triggers on
packages/plugin-sdk/** so the guard actually runs when the map changes.

* fix(plugin-sdk): validate facades before any exports write

ClawSweeper P2: write mode reported a stale facade but still exited 0,
after syncRootPackageExports had already rewritten the root manifest.
Hoist facade validation ahead of all writes and exit nonzero in both
modes; an invalid facade now fails closed with no partial manifest
update (proven: hash-identical manifests plus exit 1 in write mode).
This commit is contained in:
Peter Steinberger
2026-08-09 22:20:28 -07:00
committed by GitHub
parent 3a114678f9
commit 44ffb65bee
38 changed files with 344 additions and 155 deletions
+123 -123
View File
@@ -28,74 +28,6 @@
"types": "./dist/src/plugin-sdk/channel-activity-runtime.d.ts",
"default": "./src/channel-activity-runtime.ts"
},
"./concurrency-runtime": {
"types": "./dist/src/plugin-sdk/concurrency-runtime.d.ts",
"default": "./src/concurrency-runtime.ts"
},
"./dedupe-runtime": {
"types": "./dist/src/plugin-sdk/dedupe-runtime.d.ts",
"default": "./src/dedupe-runtime.ts"
},
"./delivery-queue-runtime": {
"types": "./dist/src/plugin-sdk/delivery-queue-runtime.d.ts",
"default": "./src/delivery-queue-runtime.ts"
},
"./file-access-runtime": {
"types": "./dist/src/plugin-sdk/file-access-runtime.d.ts",
"default": "./src/file-access-runtime.ts"
},
"./heartbeat-runtime": {
"types": "./dist/src/plugin-sdk/heartbeat-runtime.d.ts",
"default": "./src/heartbeat-runtime.ts"
},
"./number-runtime": {
"types": "./dist/src/plugin-sdk/number-runtime.d.ts",
"default": "./src/number-runtime.ts"
},
"./outbound-media": {
"types": "./dist/src/plugin-sdk/outbound-media.d.ts",
"default": "./src/outbound-media.ts"
},
"./secure-random-runtime": {
"types": "./dist/src/plugin-sdk/secure-random-runtime.d.ts",
"default": "./src/secure-random-runtime.ts"
},
"./system-event-runtime": {
"types": "./dist/src/plugin-sdk/system-event-runtime.d.ts",
"default": "./src/system-event-runtime.ts"
},
"./time-runtime": {
"types": "./dist/src/plugin-sdk/time-runtime.d.ts",
"default": "./src/time-runtime.ts"
},
"./transport-ready-runtime": {
"types": "./dist/src/plugin-sdk/transport-ready-runtime.d.ts",
"default": "./src/transport-ready-runtime.ts"
},
"./exec-approvals-runtime": {
"types": "./dist/src/plugin-sdk/exec-approvals-runtime.d.ts",
"default": "./src/exec-approvals-runtime.ts"
},
"./core": {
"types": "./dist/src/plugin-sdk/core.d.ts",
"default": "./src/core.ts"
},
"./config-runtime": {
"types": "./dist/src/plugin-sdk/config-runtime.d.ts",
"default": "./src/config-runtime.ts"
},
"./plugin-config-runtime": {
"types": "./dist/src/plugin-sdk/plugin-config-runtime.d.ts",
"default": "./src/plugin-config-runtime.ts"
},
"./config-mutation": {
"types": "./dist/src/plugin-sdk/config-mutation.d.ts",
"default": "./src/config-mutation.ts"
},
"./cron-store-runtime": {
"types": "./dist/src/plugin-sdk/cron-store-runtime.d.ts",
"default": "./src/cron-store-runtime.ts"
},
"./channel-secret-runtime": {
"types": "./dist/src/plugin-sdk/channel-secret-runtime.d.ts",
"default": "./src/channel-secret-runtime.ts"
@@ -108,14 +40,78 @@
"types": "./dist/src/plugin-sdk/cli-runtime.d.ts",
"default": "./src/cli-runtime.ts"
},
"./gateway-method-runtime": {
"types": "./dist/src/plugin-sdk/gateway-method-runtime.d.ts",
"default": "./src/gateway-method-runtime.ts"
"./concurrency-runtime": {
"types": "./dist/src/plugin-sdk/concurrency-runtime.d.ts",
"default": "./src/concurrency-runtime.ts"
},
"./config-contracts": {
"types": "./dist/src/plugin-sdk/config-contracts.d.ts",
"default": "./src/config-contracts.ts"
},
"./config-mutation": {
"types": "./dist/src/plugin-sdk/config-mutation.d.ts",
"default": "./src/config-mutation.ts"
},
"./config-runtime": {
"types": "./dist/src/plugin-sdk/config-runtime.d.ts",
"default": "./src/config-runtime.ts"
},
"./core": {
"types": "./dist/src/plugin-sdk/core.d.ts",
"default": "./src/core.ts"
},
"./cron-store-runtime": {
"types": "./dist/src/plugin-sdk/cron-store-runtime.d.ts",
"default": "./src/cron-store-runtime.ts"
},
"./dedupe-runtime": {
"types": "./dist/src/plugin-sdk/dedupe-runtime.d.ts",
"default": "./src/dedupe-runtime.ts"
},
"./delivery-queue-runtime": {
"types": "./dist/src/plugin-sdk/delivery-queue-runtime.d.ts",
"default": "./src/delivery-queue-runtime.ts"
},
"./error-runtime": {
"types": "./dist/src/plugin-sdk/error-runtime.d.ts",
"default": "./src/error-runtime.ts"
},
"./exec-approvals-runtime": {
"types": "./dist/src/plugin-sdk/exec-approvals-runtime.d.ts",
"default": "./src/exec-approvals-runtime.ts"
},
"./file-access-runtime": {
"types": "./dist/src/plugin-sdk/file-access-runtime.d.ts",
"default": "./src/file-access-runtime.ts"
},
"./gateway-method-runtime": {
"types": "./dist/src/plugin-sdk/gateway-method-runtime.d.ts",
"default": "./src/gateway-method-runtime.ts"
},
"./heartbeat-runtime": {
"types": "./dist/src/plugin-sdk/heartbeat-runtime.d.ts",
"default": "./src/heartbeat-runtime.ts"
},
"./infra-runtime": {
"types": "./dist/src/plugin-sdk/infra-runtime.d.ts",
"default": "./src/infra-runtime.ts"
},
"./model-session-runtime": {
"types": "./dist/src/plugin-sdk/model-session-runtime.d.ts",
"default": "./src/model-session-runtime.ts"
},
"./number-runtime": {
"types": "./dist/src/plugin-sdk/number-runtime.d.ts",
"default": "./src/number-runtime.ts"
},
"./outbound-media": {
"types": "./dist/src/plugin-sdk/outbound-media.d.ts",
"default": "./src/outbound-media.ts"
},
"./plugin-config-runtime": {
"types": "./dist/src/plugin-sdk/plugin-config-runtime.d.ts",
"default": "./src/plugin-config-runtime.ts"
},
"./plugin-entry": {
"types": "./dist/src/plugin-sdk/plugin-entry.d.ts",
"default": "./src/plugin-entry.ts"
@@ -128,45 +124,33 @@
"types": "./dist/src/plugin-sdk/provider-auth.d.ts",
"default": "./src/provider-auth.ts"
},
"./provider-auth-runtime": {
"types": "./dist/src/plugin-sdk/provider-auth-runtime.d.ts",
"default": "./src/provider-auth-runtime.ts"
},
"./provider-auth-login-flow-runtime": {
"types": "./dist/src/plugin-sdk/provider-auth-login-flow-runtime.d.ts",
"default": "./src/provider-auth-login-flow-runtime.ts"
},
"./provider-env-vars": {
"types": "./dist/src/plugin-sdk/provider-env-vars.d.ts",
"default": "./src/provider-env-vars.ts"
"./provider-auth-runtime": {
"types": "./dist/src/plugin-sdk/provider-auth-runtime.d.ts",
"default": "./src/provider-auth-runtime.ts"
},
"./provider-entry": {
"types": "./dist/src/plugin-sdk/provider-entry.d.ts",
"default": "./src/provider-entry.ts"
},
"./provider-usage": {
"types": "./dist/src/plugin-sdk/provider-usage.d.ts",
"default": "./src/provider-usage.ts"
"./provider-env-vars": {
"types": "./dist/src/plugin-sdk/provider-env-vars.d.ts",
"default": "./src/provider-env-vars.ts"
},
"./provider-http": {
"types": "./dist/src/plugin-sdk/provider-http.d.ts",
"default": "./src/provider-http.ts"
},
"./provider-model-types": {
"types": "./dist/src/plugin-sdk/provider-model-types.d.ts",
"default": "./src/provider-model-types.ts"
},
"./provider-model-shared": {
"types": "./dist/src/plugin-sdk/provider-model-shared.d.ts",
"default": "./src/provider-model-shared.ts"
},
"./model-session-runtime": {
"types": "./dist/src/plugin-sdk/model-session-runtime.d.ts",
"default": "./src/model-session-runtime.ts"
},
"./talk-config-runtime": {
"types": "./dist/src/plugin-sdk/talk-config-runtime.d.ts",
"default": "./src/talk-config-runtime.ts"
"./provider-model-types": {
"types": "./dist/src/plugin-sdk/provider-model-types.d.ts",
"default": "./src/provider-model-types.ts"
},
"./provider-onboard": {
"types": "./dist/src/plugin-sdk/provider-onboard.d.ts",
@@ -180,62 +164,78 @@
"types": "./dist/src/plugin-sdk/provider-tools.d.ts",
"default": "./src/provider-tools.ts"
},
"./provider-usage": {
"types": "./dist/src/plugin-sdk/provider-usage.d.ts",
"default": "./src/provider-usage.ts"
},
"./provider-web-search": {
"types": "./dist/src/plugin-sdk/provider-web-search.d.ts",
"default": "./src/provider-web-search.ts"
},
"./provider-web-search-contract": {
"types": "./dist/src/plugin-sdk/provider-web-search-contract.d.ts",
"default": "./src/provider-web-search-contract.ts"
},
"./provider-web-search-config-contract": {
"types": "./dist/src/plugin-sdk/provider-web-search-config-contract.d.ts",
"default": "./src/provider-web-search-config-contract.ts"
},
"./provider-web-search-contract": {
"types": "./dist/src/plugin-sdk/provider-web-search-contract.d.ts",
"default": "./src/provider-web-search-contract.ts"
},
"./runtime-env": {
"types": "./dist/src/plugin-sdk/runtime-env.d.ts",
"default": "./src/runtime-env.ts"
},
"./infra-runtime": {
"types": "./dist/src/plugin-sdk/infra-runtime.d.ts",
"default": "./src/infra-runtime.ts"
},
"./security-runtime": {
"types": "./dist/src/plugin-sdk/security-runtime.d.ts",
"default": "./src/security-runtime.ts"
},
"./secret-ref-runtime": {
"types": "./dist/src/plugin-sdk/secret-ref-runtime.d.ts",
"default": "./src/secret-ref-runtime.ts"
},
"./ssrf-runtime": {
"types": "./dist/src/plugin-sdk/ssrf-runtime.d.ts",
"default": "./src/ssrf-runtime.ts"
},
"./secret-input": {
"types": "./dist/src/plugin-sdk/secret-input.d.ts",
"default": "./src/secret-input.ts"
},
"./tts-runtime": {
"types": "./dist/src/plugin-sdk/tts-runtime.d.ts",
"default": "./src/tts-runtime.ts"
"./secret-ref-runtime": {
"types": "./dist/src/plugin-sdk/secret-ref-runtime.d.ts",
"default": "./src/secret-ref-runtime.ts"
},
"./secure-random-runtime": {
"types": "./dist/src/plugin-sdk/secure-random-runtime.d.ts",
"default": "./src/secure-random-runtime.ts"
},
"./security-runtime": {
"types": "./dist/src/plugin-sdk/security-runtime.d.ts",
"default": "./src/security-runtime.ts"
},
"./ssrf-runtime": {
"types": "./dist/src/plugin-sdk/ssrf-runtime.d.ts",
"default": "./src/ssrf-runtime.ts"
},
"./system-event-runtime": {
"types": "./dist/src/plugin-sdk/system-event-runtime.d.ts",
"default": "./src/system-event-runtime.ts"
},
"./talk-config-runtime": {
"types": "./dist/src/plugin-sdk/talk-config-runtime.d.ts",
"default": "./src/talk-config-runtime.ts"
},
"./text-runtime": {
"types": "./dist/src/plugin-sdk/text-runtime.d.ts",
"default": "./src/text-runtime.ts"
},
"./video-generation": {
"types": "./dist/src/plugin-sdk/video-generation.d.ts",
"default": "./src/video-generation.ts"
},
"./config-contracts": {
"types": "./dist/src/plugin-sdk/config-contracts.d.ts",
"default": "./src/config-contracts.ts"
},
"./text-utility-runtime": {
"types": "./dist/src/plugin-sdk/text-utility-runtime.d.ts",
"default": "./src/text-utility-runtime.ts"
},
"./time-runtime": {
"types": "./dist/src/plugin-sdk/time-runtime.d.ts",
"default": "./src/time-runtime.ts"
},
"./transport-ready-runtime": {
"types": "./dist/src/plugin-sdk/transport-ready-runtime.d.ts",
"default": "./src/transport-ready-runtime.ts"
},
"./tts-runtime": {
"types": "./dist/src/plugin-sdk/tts-runtime.d.ts",
"default": "./src/tts-runtime.ts"
},
"./video-generation": {
"types": "./dist/src/plugin-sdk/video-generation.d.ts",
"default": "./src/video-generation.ts"
},
"./zod": {
"types": "./dist/src/plugin-sdk/zod.d.ts",
"default": "./src/zod.ts"
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for account id normalization helpers.
export * from "../../../src/plugin-sdk/account-id.js";
@@ -0,0 +1,3 @@
// Public package facade for ACP runtime backend helpers.
export * from "../../../src/plugin-sdk/acp-runtime-backend.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for ACP runtime helpers.
export * from "../../../src/plugin-sdk/acp-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for async lock runtime helpers.
export * from "../../../src/plugin-sdk/async-lock-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for channel activity runtime helpers.
export * from "../../../src/plugin-sdk/channel-activity-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for channel secret runtime helpers.
export * from "../../../src/plugin-sdk/channel-secret-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for channel streaming helpers.
export * from "../../../src/plugin-sdk/channel-streaming.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for CLI runtime helpers.
export * from "../../../src/plugin-sdk/cli-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for concurrency runtime helpers.
export * from "../../../src/plugin-sdk/concurrency-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for config contracts.
export * from "../../../src/plugin-sdk/config-contracts.js";
@@ -0,0 +1,3 @@
// Public package facade for config mutation helpers.
export * from "../../../src/plugin-sdk/config-mutation.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for core plugin SDK contracts.
export * from "../../../src/plugin-sdk/core.js";
@@ -0,0 +1,3 @@
// Public package facade for cron store runtime helpers.
export * from "../../../src/plugin-sdk/cron-store-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for dedupe runtime helpers.
export * from "../../../src/plugin-sdk/dedupe-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for delivery queue runtime helpers.
export * from "../../../src/plugin-sdk/delivery-queue-runtime.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for error runtime helpers.
export * from "../../../src/plugin-sdk/error-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for file access runtime helpers.
export * from "../../../src/plugin-sdk/file-access-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for heartbeat runtime helpers.
export * from "../../../src/plugin-sdk/heartbeat-runtime.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for infra runtime helpers.
export * from "../../../src/plugin-sdk/infra-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for model session runtime helpers.
export * from "../../../src/plugin-sdk/model-session-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for number runtime helpers.
export * from "../../../src/plugin-sdk/number-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for plugin config runtime helpers.
export * from "../../../src/plugin-sdk/plugin-config-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for provider environment variable contracts.
export * from "../../../src/plugin-sdk/provider-env-vars.js";
@@ -0,0 +1,3 @@
// Public package facade for provider usage contracts.
export * from "../../../src/plugin-sdk/provider-usage.js";
@@ -0,0 +1,3 @@
// Public package facade for provider web search contracts.
export * from "../../../src/plugin-sdk/provider-web-search-contract.js";
@@ -0,0 +1,3 @@
// Public package facade for secret ref runtime helpers.
export * from "../../../src/plugin-sdk/secret-ref-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for secure random runtime helpers.
export * from "../../../src/plugin-sdk/secure-random-runtime.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for SSRF runtime helpers.
export * from "../../../src/plugin-sdk/ssrf-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for system event runtime helpers.
export * from "../../../src/plugin-sdk/system-event-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for talk config runtime helpers.
export * from "../../../src/plugin-sdk/talk-config-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for text utility runtime helpers.
export * from "../../../src/plugin-sdk/text-utility-runtime.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for time runtime helpers.
export * from "../../../src/plugin-sdk/time-runtime.js";
@@ -0,0 +1,3 @@
// Public package facade for transport ready runtime helpers.
export * from "../../../src/plugin-sdk/transport-ready-runtime.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for TTS runtime helpers.
export * from "../../../src/plugin-sdk/tts-runtime.js";
+3
View File
@@ -0,0 +1,3 @@
// Public package facade for the shared zod re-export.
export * from "../../../src/plugin-sdk/zod.js";
+1 -1
View File
@@ -98,7 +98,7 @@ const SQLITE_SESSION_SCHEMA_BASELINE_PATH_RE =
const PLUGIN_SDK_API_BASELINE_PATH_RE =
/^(?:src\/|packages\/|extensions\/|pnpm-lock\.yaml$|tsconfig\.json$|scripts\/(?:generate-plugin-sdk-api-baseline\.ts|lib\/plugin-sdk-(?:doc-metadata\.ts|entries\.mts|entrypoints\.json|private-local-only-subpaths\.json))|docs\/\.generated\/plugin-sdk-api-baseline\.sha256$)/u;
const PLUGIN_SDK_SURFACE_PATH_RE =
/^(?:package\.json$|src\/plugin-sdk\/|scripts\/(?:plugin-sdk-surface-report\.mts|sync-plugin-sdk-exports\.mts|lib\/plugin-sdk-(?:declaration-budget\.mts|deprecated-barrel-subpaths\.json|deprecated-public-subpaths\.json|entries\.mts|entrypoints\.json|private-local-only-subpaths\.json)))/u;
/^(?:package\.json$|src\/plugin-sdk\/|packages\/plugin-sdk\/|scripts\/(?:plugin-sdk-surface-report\.mts|sync-plugin-sdk-exports\.mts|lib\/plugin-sdk-(?:declaration-budget\.mts|deprecated-barrel-subpaths\.json|deprecated-public-subpaths\.json|entries\.mts|entrypoints\.json|private-local-only-subpaths\.json)))/u;
const DEPRECATION_HYGIENE_PATH_RE =
/^(?:package\.json$|src\/|extensions\/|packages\/|scripts\/(?:check-deprecated-api-usage\.mts$|plugin-boundary-report\.ts$|lib\/plugin-sdk))/u;
const CANVAS_A2UI_NATIVE_RESOURCE_PATH_RE =
+115 -31
View File
@@ -1,49 +1,133 @@
#!/usr/bin/env node
// Regenerates package.json plugin-sdk export entries from the canonical entry list.
// Regenerates package.json plugin-sdk export entries from the canonical entry list
// and keeps the workspace facade package (@openclaw/plugin-sdk) exports aligned
// with its src facade files.
import fs from "node:fs";
import path from "node:path";
import { buildPluginSdkPackageExports } from "./lib/plugin-sdk-entries.mts";
import { buildPluginSdkPackageExports, pluginSdkEntrypoints } from "./lib/plugin-sdk-entries.mts";
const checkOnly = process.argv.includes("--check");
const packageJsonPath = path.join(process.cwd(), "package.json");
const packageJson: Record<string, unknown> & { exports?: Record<string, unknown> } = JSON.parse(
fs.readFileSync(packageJsonPath, "utf8"),
);
const currentExports = packageJson.exports ?? {};
const syncedPluginSdkExports = buildPluginSdkPackageExports();
const repoRoot = process.cwd();
let failed = false;
const nextExports: typeof currentExports = {};
let insertedPluginSdkExports = false;
for (const [key, value] of Object.entries(currentExports)) {
if (key.startsWith("./plugin-sdk")) {
if (!insertedPluginSdkExports) {
function syncRootPackageExports() {
const packageJsonPath = path.join(repoRoot, "package.json");
const packageJson: Record<string, unknown> & { exports?: Record<string, unknown> } = JSON.parse(
fs.readFileSync(packageJsonPath, "utf8"),
);
const currentExports = packageJson.exports ?? {};
const syncedPluginSdkExports = buildPluginSdkPackageExports();
const nextExports: typeof currentExports = {};
let insertedPluginSdkExports = false;
for (const [key, value] of Object.entries(currentExports)) {
if (key.startsWith("./plugin-sdk")) {
if (!insertedPluginSdkExports) {
Object.assign(nextExports, syncedPluginSdkExports);
insertedPluginSdkExports = true;
}
continue;
}
nextExports[key] = value;
if (key === "." && !insertedPluginSdkExports) {
Object.assign(nextExports, syncedPluginSdkExports);
insertedPluginSdkExports = true;
}
continue;
}
nextExports[key] = value;
if (key === "." && !insertedPluginSdkExports) {
if (!insertedPluginSdkExports) {
Object.assign(nextExports, syncedPluginSdkExports);
insertedPluginSdkExports = true;
}
}
if (!insertedPluginSdkExports) {
Object.assign(nextExports, syncedPluginSdkExports);
}
const nextExportsJson = JSON.stringify(nextExports);
const currentExportsJson = JSON.stringify(currentExports);
if (checkOnly) {
if (currentExportsJson !== nextExportsJson) {
if (JSON.stringify(currentExports) === JSON.stringify(nextExports)) {
return;
}
if (checkOnly) {
console.error("plugin-sdk exports out of sync. Run `pnpm plugin-sdk:sync-exports`.");
process.exit(1);
failed = true;
return;
}
console.log("plugin-sdk exports synced.");
process.exit(0);
packageJson.exports = nextExports;
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8");
}
packageJson.exports = nextExports;
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8");
// The workspace facade package mirrors a subset of plugin SDK entrypoints for
// package-name resolution inside the monorepo. Every export key must have a src
// facade file (its runtime `default` target) and name a canonical SDK entrypoint;
// dangling keys typecheck via prebuilt dist d.ts but fail on runtime resolution.
// Validation runs before any manifest write so an invalid facade cannot leave a
// partially rewritten export map behind a zero exit status.
function collectFacadeSubpaths(): string[] | null {
const facadeSubpaths = fs
.readdirSync(path.join(repoRoot, "packages", "plugin-sdk", "src"))
.filter((file) => file.endsWith(".ts"))
.map((file) => file.slice(0, -".ts".length))
.toSorted();
const entrypointSet = new Set(pluginSdkEntrypoints);
const staleFacades = facadeSubpaths.filter((subpath) => !entrypointSet.has(subpath));
if (staleFacades.length === 0) {
return facadeSubpaths;
}
for (const subpath of staleFacades) {
console.error(
`packages/plugin-sdk/src/${subpath}.ts does not match any plugin SDK entrypoint. ` +
"Delete the facade or add the entrypoint to scripts/lib/plugin-sdk-entrypoints.json.",
);
}
return null;
}
function syncFacadePackageExports(facadeSubpaths: string[]) {
const facadePackageJsonPath = path.join(repoRoot, "packages", "plugin-sdk", "package.json");
const facadePackageJson: Record<string, unknown> & { exports?: Record<string, unknown> } =
JSON.parse(fs.readFileSync(facadePackageJsonPath, "utf8"));
const nextExports = Object.fromEntries(
facadeSubpaths.map((subpath) => [
`./${subpath}`,
{
types: `./dist/src/plugin-sdk/${subpath}.d.ts`,
default: `./src/${subpath}.ts`,
},
]),
);
if (JSON.stringify(facadePackageJson.exports ?? {}) === JSON.stringify(nextExports)) {
return;
}
if (checkOnly) {
const currentKeys = new Set(Object.keys(facadePackageJson.exports ?? {}));
const expectedKeys = new Set(Object.keys(nextExports));
for (const key of currentKeys) {
if (!expectedKeys.has(key)) {
console.error(`packages/plugin-sdk exports ${key} has no src facade file.`);
}
}
for (const key of expectedKeys) {
if (!currentKeys.has(key)) {
console.error(`packages/plugin-sdk src facade ${key} is missing from exports.`);
}
}
console.error("packages/plugin-sdk exports out of sync. Run `pnpm plugin-sdk:sync-exports`.");
failed = true;
return;
}
facadePackageJson.exports = nextExports;
fs.writeFileSync(
facadePackageJsonPath,
`${JSON.stringify(facadePackageJson, null, 2)}\n`,
"utf8",
);
}
const facadeSubpaths = collectFacadeSubpaths();
if (facadeSubpaths === null) {
process.exit(1);
}
syncRootPackageExports();
syncFacadePackageExports(facadeSubpaths);
if (failed) {
process.exit(1);
}
if (checkOnly) {
console.log("plugin-sdk exports synced.");
}