Compare commits

...

8 Commits

Author SHA1 Message Date
Peter Steinberger
4149dc0af1 fix: keep private SDK declarations local 2026-05-28 03:16:45 +01:00
Dallin Romney
39973675c5 test: guard private sdk declaration leaks
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-27 18:57:27 -07:00
Dallin Romney
a974fd2f77 fix(ci): stabilize sdk boundary checks 2026-05-27 18:34:17 -07:00
Dallin Romney
59a4ab4daa fix(canvas): use focused number runtime helpers 2026-05-27 18:34:17 -07:00
Dallin Romney
ca61f668d5 test: simplify packed sdk type smoke 2026-05-27 18:34:17 -07:00
Dallin Romney
3cda9be785 refactor: move packed sdk smoke to fixture 2026-05-27 18:34:17 -07:00
Dallin Romney
ed2c6bee69 fix: align package inventory with flat sdk declarations 2026-05-27 18:34:17 -07:00
Dallin Romney
2815ac066b refactor: flatten plugin sdk declarations 2026-05-27 18:34:17 -07:00
16 changed files with 523 additions and 123 deletions

View File

@@ -8,6 +8,10 @@ import {
resolveNodeFromNodeList,
type NodeMatchCandidate,
} from "openclaw/plugin-sdk/gateway-runtime";
import {
parseStrictFiniteNumber,
parseStrictPositiveInteger,
} from "openclaw/plugin-sdk/number-runtime";
import { defaultRuntime } from "openclaw/plugin-sdk/runtime";
import {
normalizeLowercaseStringOrEmpty,
@@ -70,41 +74,6 @@ export type CanvasCliDependencies = {
type CanvasNodeCandidate = NodeMatchCandidate;
type CanvasSnapshotRequestFormat = "png" | "jpeg";
function normalizeNumericString(value: string): string | undefined {
const trimmed = value.trim();
return trimmed ? trimmed : undefined;
}
function parseStrictPositiveInteger(value: unknown): number | undefined {
if (typeof value === "number") {
return Number.isSafeInteger(value) && value > 0 ? value : undefined;
}
if (typeof value !== "string") {
return undefined;
}
const normalized = normalizeNumericString(value);
if (!normalized || !/^\+?\d+$/.test(normalized)) {
return undefined;
}
const parsed = Number(normalized);
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
}
function parseStrictFiniteNumber(value: unknown): number | undefined {
if (typeof value === "number") {
return Number.isFinite(value) ? value : undefined;
}
if (typeof value !== "string") {
return undefined;
}
const normalized = normalizeNumericString(value);
if (!normalized || !/^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:e[+-]?\d+)?$/i.test(normalized)) {
return undefined;
}
const parsed = Number(normalized);
return Number.isFinite(parsed) ? parsed : undefined;
}
function parseCanvasSnapshotRequestFormat(raw: unknown): CanvasSnapshotRequestFormat {
const format = normalizeLowercaseStringOrEmpty(normalizeOptionalString(raw) ?? "jpg");
switch (format) {

View File

@@ -3,42 +3,97 @@
"compilerOptions": {
"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": ["../dist/plugin-sdk/index.d.ts"],
"openclaw/plugin-sdk/*": ["../dist/plugin-sdk/*.d.ts"],
"openclaw/plugin-sdk/reply-payload-testing": [
"../packages/plugin-sdk/dist/src/plugin-sdk/reply-payload-testing.d.ts"
],
"openclaw/plugin-sdk/ssrf-runtime-internal": [
"../packages/plugin-sdk/dist/src/plugin-sdk/ssrf-runtime-internal.d.ts"
],
"openclaw/plugin-sdk/codex-native-task-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/codex-native-task-runtime.d.ts"
],
"openclaw/plugin-sdk/agent-runtime-test-contracts": [
"../packages/plugin-sdk/dist/src/plugin-sdk/agent-runtime-test-contracts.d.ts"
],
"openclaw/plugin-sdk/channel-target-testing": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-target-testing.d.ts"
],
"openclaw/plugin-sdk/channel-test-helpers": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-test-helpers.d.ts"
],
"openclaw/plugin-sdk/plugin-test-api": [
"../packages/plugin-sdk/dist/src/plugin-sdk/plugin-test-api.d.ts"
],
"openclaw/plugin-sdk/plugin-test-contracts": [
"../packages/plugin-sdk/dist/src/plugin-sdk/plugin-test-contracts.d.ts"
],
"openclaw/plugin-sdk/plugin-test-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/plugin-test-runtime.d.ts"
],
"openclaw/plugin-sdk/provider-http-test-mocks": [
"../packages/plugin-sdk/dist/src/plugin-sdk/provider-http-test-mocks.d.ts"
],
"openclaw/plugin-sdk/provider-test-contracts": [
"../packages/plugin-sdk/dist/src/plugin-sdk/provider-test-contracts.d.ts"
],
"openclaw/plugin-sdk/test-env": [
"../packages/plugin-sdk/dist/src/plugin-sdk/test-env.d.ts"
],
"openclaw/plugin-sdk/test-fixtures": [
"../packages/plugin-sdk/dist/src/plugin-sdk/test-fixtures.d.ts"
],
"openclaw/plugin-sdk/test-node-mocks": [
"../packages/plugin-sdk/dist/src/plugin-sdk/test-node-mocks.d.ts"
],
"openclaw/plugin-sdk/testing": [
"../packages/plugin-sdk/dist/src/plugin-sdk/testing.d.ts"
],
"openclaw/plugin-sdk/channel-contract-testing": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-contract-testing.d.ts"
],
"openclaw/plugin-sdk/account-id": ["../dist/plugin-sdk/account-id.d.ts"],
"openclaw/plugin-sdk/channel-entry-contract": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-entry-contract.d.ts"
"../dist/plugin-sdk/channel-entry-contract.d.ts"
],
"openclaw/plugin-sdk/browser-maintenance": [
"../packages/plugin-sdk/dist/extensions/browser/browser-maintenance.d.ts"
],
"openclaw/plugin-sdk/channel-secret-basic-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-secret-basic-runtime.d.ts"
"../dist/plugin-sdk/channel-secret-basic-runtime.d.ts"
],
"openclaw/plugin-sdk/channel-secret-runtime": [
"../dist/plugin-sdk/src/plugin-sdk/channel-secret-runtime.d.ts"
"../dist/plugin-sdk/channel-secret-runtime.d.ts"
],
"openclaw/plugin-sdk/channel-secret-tts-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-secret-tts-runtime.d.ts"
"../dist/plugin-sdk/channel-secret-tts-runtime.d.ts"
],
"openclaw/plugin-sdk/error-runtime": ["../dist/plugin-sdk/src/plugin-sdk/error-runtime.d.ts"],
"openclaw/plugin-sdk/channel-streaming": [
"../dist/plugin-sdk/channel-streaming.d.ts"
],
"openclaw/plugin-sdk/error-runtime": ["../dist/plugin-sdk/error-runtime.d.ts"],
"openclaw/plugin-sdk/provider-catalog-shared": [
"../packages/plugin-sdk/dist/src/plugin-sdk/provider-catalog-shared.d.ts"
"../dist/plugin-sdk/provider-catalog-shared.d.ts"
],
"openclaw/plugin-sdk/provider-entry": [
"../packages/plugin-sdk/dist/src/plugin-sdk/provider-entry.d.ts"
"../dist/plugin-sdk/provider-entry.d.ts"
],
"openclaw/plugin-sdk/secret-ref-runtime": [
"../dist/plugin-sdk/src/plugin-sdk/secret-ref-runtime.d.ts"
"../dist/plugin-sdk/secret-ref-runtime.d.ts"
],
"openclaw/plugin-sdk/ssrf-runtime": ["../dist/plugin-sdk/src/plugin-sdk/ssrf-runtime.d.ts"],
"openclaw/plugin-sdk/ssrf-runtime": ["../dist/plugin-sdk/ssrf-runtime.d.ts"],
"@openclaw/qa-channel/api.js": ["../dist/plugin-sdk/extensions/qa-channel/api.d.ts"],
"@openclaw/discord/api.js": ["../dist/plugin-sdk/extensions/discord/api.d.ts"],
"@openclaw/slack/api.js": ["../dist/plugin-sdk/extensions/slack/api.d.ts"],
"@openclaw/whatsapp/api.js": ["../dist/plugin-sdk/extensions/whatsapp/api.d.ts"],
"@openclaw/*.js": ["../packages/plugin-sdk/dist/extensions/*.d.ts", "../extensions/*"],
"@openclaw/*": ["../packages/plugin-sdk/dist/extensions/*", "../extensions/*"],
"@openclaw/plugin-sdk/*": ["../dist/plugin-sdk/src/plugin-sdk/*.d.ts"]
"openclaw/plugin-sdk/qa-channel": ["../dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts"],
"openclaw/plugin-sdk/qa-channel-protocol": [
"../dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts"
],
"@openclaw/plugin-sdk/*": ["../dist/plugin-sdk/*.d.ts"]
}
}
}

View File

@@ -4,44 +4,101 @@
"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": ["../../dist/plugin-sdk/index.d.ts"],
"openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/*.d.ts"],
"openclaw/plugin-sdk/reply-payload-testing": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/reply-payload-testing.d.ts"
],
"openclaw/plugin-sdk/ssrf-runtime-internal": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/ssrf-runtime-internal.d.ts"
],
"openclaw/plugin-sdk/codex-native-task-runtime": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/codex-native-task-runtime.d.ts"
],
"openclaw/plugin-sdk/agent-runtime-test-contracts": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/agent-runtime-test-contracts.d.ts"
],
"openclaw/plugin-sdk/channel-target-testing": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/channel-target-testing.d.ts"
],
"openclaw/plugin-sdk/channel-test-helpers": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/channel-test-helpers.d.ts"
],
"openclaw/plugin-sdk/plugin-test-api": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/plugin-test-api.d.ts"
],
"openclaw/plugin-sdk/plugin-test-contracts": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/plugin-test-contracts.d.ts"
],
"openclaw/plugin-sdk/plugin-test-runtime": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/plugin-test-runtime.d.ts"
],
"openclaw/plugin-sdk/provider-http-test-mocks": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/provider-http-test-mocks.d.ts"
],
"openclaw/plugin-sdk/provider-test-contracts": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/provider-test-contracts.d.ts"
],
"openclaw/plugin-sdk/test-env": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/test-env.d.ts"
],
"openclaw/plugin-sdk/test-fixtures": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/test-fixtures.d.ts"
],
"openclaw/plugin-sdk/test-node-mocks": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/test-node-mocks.d.ts"
],
"openclaw/plugin-sdk/testing": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/testing.d.ts"
],
"openclaw/plugin-sdk/channel-contract-testing": [
"../../packages/plugin-sdk/dist/src/plugin-sdk/channel-contract-testing.d.ts"
],
"openclaw/plugin-sdk/account-id": ["../../dist/plugin-sdk/account-id.d.ts"],
"openclaw/plugin-sdk/channel-entry-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-entry-contract.d.ts"
"../../dist/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/channel-secret-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-secret-runtime.d.ts"
"../../dist/plugin-sdk/channel-secret-runtime.d.ts"
],
"openclaw/plugin-sdk/cli-runtime": ["../../dist/plugin-sdk/src/plugin-sdk/cli-runtime.d.ts"],
"openclaw/plugin-sdk/channel-streaming": [
"../../dist/plugin-sdk/channel-streaming.d.ts"
],
"openclaw/plugin-sdk/cli-runtime": ["../../dist/plugin-sdk/cli-runtime.d.ts"],
"openclaw/plugin-sdk/error-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/error-runtime.d.ts"
"../../dist/plugin-sdk/error-runtime.d.ts"
],
"openclaw/plugin-sdk/provider-catalog-shared": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-catalog-shared.d.ts"
"../../dist/plugin-sdk/provider-catalog-shared.d.ts"
],
"openclaw/plugin-sdk/provider-env-vars": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-env-vars.d.ts"
"../../dist/plugin-sdk/provider-env-vars.d.ts"
],
"openclaw/plugin-sdk/provider-entry": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts"
"../../dist/plugin-sdk/provider-entry.d.ts"
],
"openclaw/plugin-sdk/provider-web-search-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-web-search-contract.d.ts"
"../../dist/plugin-sdk/provider-web-search-contract.d.ts"
],
"openclaw/plugin-sdk/secret-ref-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/secret-ref-runtime.d.ts"
"../../dist/plugin-sdk/secret-ref-runtime.d.ts"
],
"openclaw/plugin-sdk/ssrf-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/ssrf-runtime.d.ts"
"../../dist/plugin-sdk/ssrf-runtime.d.ts"
],
"@openclaw/qa-channel/api.js": ["../../dist/plugin-sdk/extensions/qa-channel/api.d.ts"],
"@openclaw/*.js": ["../../packages/plugin-sdk/dist/extensions/*.d.ts", "../*"],
"@openclaw/*": ["../*"],
"@openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/src/plugin-sdk/*.d.ts"],
"openclaw/plugin-sdk/qa-channel": [
"../../dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts"
],
"openclaw/plugin-sdk/qa-channel-protocol": [
"../../dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts"
],
"@openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/*.d.ts"],
"@openclaw/anthropic-vertex/api.js": ["./.boundary-stubs/anthropic-vertex-api.d.ts"],
"@openclaw/ollama/api.js": ["./.boundary-stubs/ollama-api.d.ts"],
"@openclaw/ollama/runtime-api.js": ["./.boundary-stubs/ollama-runtime-api.d.ts"],

View File

@@ -41,6 +41,8 @@
"!dist/plugin-sdk/channel-target-testing.d.ts",
"!dist/plugin-sdk/channel-test-helpers.js",
"!dist/plugin-sdk/channel-test-helpers.d.ts",
"!dist/plugin-sdk/codex-native-task-runtime.js",
"!dist/plugin-sdk/codex-native-task-runtime.d.ts",
"!dist/plugin-sdk/plugin-test-api.js",
"!dist/plugin-sdk/plugin-test-api.d.ts",
"!dist/plugin-sdk/plugin-test-contracts.js",
@@ -53,12 +55,16 @@
"!dist/plugin-sdk/provider-test-contracts.d.ts",
"!dist/plugin-sdk/reply-payload-testing.js",
"!dist/plugin-sdk/reply-payload-testing.d.ts",
"!dist/plugin-sdk/ssrf-runtime-internal.js",
"!dist/plugin-sdk/ssrf-runtime-internal.d.ts",
"!dist/plugin-sdk/test-env.js",
"!dist/plugin-sdk/test-env.d.ts",
"!dist/plugin-sdk/test-fixtures.js",
"!dist/plugin-sdk/test-fixtures.d.ts",
"!dist/plugin-sdk/test-node-mocks.js",
"!dist/plugin-sdk/test-node-mocks.d.ts",
"!dist/plugin-sdk/test-utils.js",
"!dist/plugin-sdk/test-utils.d.ts",
"!dist/plugin-sdk/testing.js",
"!dist/plugin-sdk/testing.d.ts",
"!dist/plugin-sdk/src/agents/test-helpers/**",
@@ -108,6 +114,7 @@
"!dist/plugin-sdk/qa-channel-protocol.*",
"!dist/plugin-sdk/qa-lab.*",
"!dist/plugin-sdk/qa-runtime.*",
"!dist/plugin-sdk/src/**",
"!dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts",
"!dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts",
"!dist/plugin-sdk/src/plugin-sdk/qa-lab.d.ts",

View File

@@ -0,0 +1,11 @@
type PublicPluginSdkModules = [
typeof import("openclaw/plugin-sdk"),
typeof import("openclaw/plugin-sdk/channel-entry-contract"),
typeof import("openclaw/plugin-sdk/config-contracts"),
typeof import("openclaw/plugin-sdk/provider-entry"),
typeof import("openclaw/plugin-sdk/runtime-env"),
];
const resolvedModules = null as unknown as PublicPluginSdkModules;
void resolvedModules;

View File

@@ -1,5 +1,6 @@
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { join, posix, resolve } from "node:path";
import { privateLocalOnlyPluginSdkEntrypoints } from "./plugin-sdk-entries.mjs";
export const EXTENSION_PACKAGE_BOUNDARY_INCLUDE = ["./*.ts", "./src/**/*.ts"] as const;
export const EXTENSION_PACKAGE_BOUNDARY_EXCLUDE = [
@@ -11,44 +12,50 @@ export const EXTENSION_PACKAGE_BOUNDARY_EXCLUDE = [
"./src/**/*test-harness.ts",
"./src/**/*test-support.ts",
] as const;
const privateLocalOnlyPluginSdkPackageDtsPaths = Object.fromEntries(
privateLocalOnlyPluginSdkEntrypoints.map((entrypoint) => [
`openclaw/plugin-sdk/${entrypoint}`,
[`../packages/plugin-sdk/dist/src/plugin-sdk/${entrypoint}.d.ts`],
]),
) as Record<string, readonly string[]>;
export const EXTENSION_PACKAGE_BOUNDARY_BASE_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/channel-entry-contract": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-entry-contract.d.ts",
],
"openclaw/plugin-sdk": ["../dist/plugin-sdk/index.d.ts"],
"openclaw/plugin-sdk/*": ["../dist/plugin-sdk/*.d.ts"],
...privateLocalOnlyPluginSdkPackageDtsPaths,
"openclaw/plugin-sdk/account-id": ["../dist/plugin-sdk/account-id.d.ts"],
"openclaw/plugin-sdk/channel-entry-contract": ["../dist/plugin-sdk/channel-entry-contract.d.ts"],
"openclaw/plugin-sdk/browser-maintenance": [
"../packages/plugin-sdk/dist/extensions/browser/browser-maintenance.d.ts",
],
"openclaw/plugin-sdk/channel-secret-basic-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-secret-basic-runtime.d.ts",
],
"openclaw/plugin-sdk/channel-secret-runtime": [
"../dist/plugin-sdk/src/plugin-sdk/channel-secret-runtime.d.ts",
"../dist/plugin-sdk/channel-secret-basic-runtime.d.ts",
],
"openclaw/plugin-sdk/channel-secret-runtime": ["../dist/plugin-sdk/channel-secret-runtime.d.ts"],
"openclaw/plugin-sdk/channel-secret-tts-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-secret-tts-runtime.d.ts",
"../dist/plugin-sdk/channel-secret-tts-runtime.d.ts",
],
"openclaw/plugin-sdk/error-runtime": ["../dist/plugin-sdk/src/plugin-sdk/error-runtime.d.ts"],
"openclaw/plugin-sdk/channel-streaming": ["../dist/plugin-sdk/channel-streaming.d.ts"],
"openclaw/plugin-sdk/error-runtime": ["../dist/plugin-sdk/error-runtime.d.ts"],
"openclaw/plugin-sdk/provider-catalog-shared": [
"../packages/plugin-sdk/dist/src/plugin-sdk/provider-catalog-shared.d.ts",
"../dist/plugin-sdk/provider-catalog-shared.d.ts",
],
"openclaw/plugin-sdk/provider-entry": [
"../packages/plugin-sdk/dist/src/plugin-sdk/provider-entry.d.ts",
],
"openclaw/plugin-sdk/secret-ref-runtime": [
"../dist/plugin-sdk/src/plugin-sdk/secret-ref-runtime.d.ts",
],
"openclaw/plugin-sdk/ssrf-runtime": ["../dist/plugin-sdk/src/plugin-sdk/ssrf-runtime.d.ts"],
"openclaw/plugin-sdk/provider-entry": ["../dist/plugin-sdk/provider-entry.d.ts"],
"openclaw/plugin-sdk/secret-ref-runtime": ["../dist/plugin-sdk/secret-ref-runtime.d.ts"],
"openclaw/plugin-sdk/ssrf-runtime": ["../dist/plugin-sdk/ssrf-runtime.d.ts"],
"@openclaw/qa-channel/api.js": ["../dist/plugin-sdk/extensions/qa-channel/api.d.ts"],
"@openclaw/discord/api.js": ["../dist/plugin-sdk/extensions/discord/api.d.ts"],
"@openclaw/slack/api.js": ["../dist/plugin-sdk/extensions/slack/api.d.ts"],
"@openclaw/whatsapp/api.js": ["../dist/plugin-sdk/extensions/whatsapp/api.d.ts"],
"@openclaw/*.js": ["../packages/plugin-sdk/dist/extensions/*.d.ts", "../extensions/*"],
"@openclaw/*": ["../packages/plugin-sdk/dist/extensions/*", "../extensions/*"],
"@openclaw/plugin-sdk/*": ["../dist/plugin-sdk/src/plugin-sdk/*.d.ts"],
"openclaw/plugin-sdk/qa-channel": ["../dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts"],
"openclaw/plugin-sdk/qa-channel-protocol": [
"../dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts",
],
"@openclaw/plugin-sdk/*": ["../dist/plugin-sdk/*.d.ts"],
} as const;
function prefixExtensionPackageBoundaryPaths(
@@ -76,28 +83,24 @@ export const EXTENSION_PACKAGE_BOUNDARY_XAI_PATHS = {
"../",
),
"openclaw/plugin-sdk/channel-entry-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-entry-contract.d.ts",
"../../dist/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/cli-runtime": ["../../dist/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",
"../../dist/plugin-sdk/provider-catalog-shared.d.ts",
],
"openclaw/plugin-sdk/provider-env-vars": ["../../dist/plugin-sdk/provider-env-vars.d.ts"],
"openclaw/plugin-sdk/provider-entry": ["../../dist/plugin-sdk/provider-entry.d.ts"],
"openclaw/plugin-sdk/provider-web-search-contract": [
"../../dist/plugin-sdk/src/plugin-sdk/provider-web-search-contract.d.ts",
"../../dist/plugin-sdk/provider-web-search-contract.d.ts",
],
"@openclaw/qa-channel/api.js": ["../../dist/plugin-sdk/extensions/qa-channel/api.d.ts"],
"@openclaw/*.js": ["../../packages/plugin-sdk/dist/extensions/*.d.ts", "../*"],
"@openclaw/*": ["../*"],
"@openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/src/plugin-sdk/*.d.ts"],
"@openclaw/plugin-sdk/*": ["../../dist/plugin-sdk/*.d.ts"],
"@openclaw/anthropic-vertex/api.js": ["./.boundary-stubs/anthropic-vertex-api.d.ts"],
"@openclaw/ollama/api.js": ["./.boundary-stubs/ollama-api.d.ts"],
"@openclaw/ollama/runtime-api.js": ["./.boundary-stubs/ollama-runtime-api.d.ts"],

View File

@@ -15,3 +15,4 @@ export function buildPluginSdkPackageExports(): Record<
}
>;
export function listPluginSdkDistArtifacts(): string[];
export function listPrivateLocalOnlyPluginSdkDistArtifacts(): string[];

View File

@@ -57,3 +57,10 @@ export function listPluginSdkDistArtifacts() {
`dist/plugin-sdk/${entry}.d.ts`,
]);
}
export function listPrivateLocalOnlyPluginSdkDistArtifacts() {
return privateLocalOnlyPluginSdkEntrypoints.flatMap((entry) => [
`dist/plugin-sdk/${entry}.js`,
`dist/plugin-sdk/${entry}.d.ts`,
]);
}

View File

@@ -7,6 +7,8 @@ const repoRoot = resolve(import.meta.dirname, "..");
const runTsgoScript = path.join(repoRoot, "scripts/run-tsgo.mjs");
const TYPE_INPUT_EXTENSIONS = new Set([".ts", ".tsx", ".d.ts", ".js", ".mjs", ".json"]);
const VALID_MODES = new Set(["all", "package-boundary"]);
const ROOT_SHIMS_NODE_OPTIONS =
`${process.env.NODE_OPTIONS ?? ""} --max-old-space-size=4096`.trim();
const PLUGIN_SDK_TYPE_INPUTS = [
"tsconfig.json",
@@ -23,10 +25,10 @@ const ROOT_DTS_REQUIRED_OUTPUTS = [
"dist/plugin-sdk/packages/memory-host-sdk/src/engine-embeddings.d.ts",
"dist/plugin-sdk/packages/memory-host-sdk/src/secret.d.ts",
"dist/plugin-sdk/packages/memory-host-sdk/src/status.d.ts",
"dist/plugin-sdk/src/plugin-sdk/error-runtime.d.ts",
"dist/plugin-sdk/src/plugin-sdk/plugin-entry.d.ts",
"dist/plugin-sdk/src/plugin-sdk/provider-auth.d.ts",
"dist/plugin-sdk/src/plugin-sdk/video-generation.d.ts",
"dist/plugin-sdk/error-runtime.d.ts",
"dist/plugin-sdk/plugin-entry.d.ts",
"dist/plugin-sdk/provider-auth.d.ts",
"dist/plugin-sdk/video-generation.d.ts",
];
const PACKAGE_DTS_INPUTS = ["packages/plugin-sdk/tsconfig.json", ...PLUGIN_SDK_TYPE_INPUTS];
const PACKAGE_DTS_STAMP = "packages/plugin-sdk/dist/.boundary-dts.stamp";
@@ -67,6 +69,7 @@ const WHATSAPP_DTS_INPUTS = [
const WHATSAPP_DTS_STAMP = "dist/plugin-sdk/extensions/whatsapp/.boundary-dts.stamp";
const WHATSAPP_DTS_REQUIRED_OUTPUTS = ["dist/plugin-sdk/extensions/whatsapp/api.d.ts"];
const ENTRY_SHIMS_INPUTS = [
"scripts/lib/plugin-sdk-private-local-only-subpaths.json",
"scripts/write-plugin-sdk-entry-dts.ts",
"scripts/lib/plugin-sdk-entrypoints.json",
"scripts/lib/plugin-sdk-entries.mjs",
@@ -505,6 +508,7 @@ async function main(argv = process.argv.slice(2)) {
"plugin-sdk boundary root shims",
["--import", "tsx", resolve(repoRoot, "scripts/write-plugin-sdk-entry-dts.ts")],
120_000,
{ env: { NODE_OPTIONS: ROOT_SHIMS_NODE_OPTIONS } },
);
} else if (mode === "all") {
process.stdout.write("[plugin-sdk boundary root shims] fresh; skipping\n");

View File

@@ -2,6 +2,7 @@
import { execFileSync } from "node:child_process";
import {
copyFileSync,
existsSync,
lstatSync,
mkdtempSync,
@@ -35,7 +36,10 @@ import {
} from "./lib/bundled-plugin-build-entries.mjs";
import { collectPackUnpackedSizeErrors as collectNpmPackUnpackedSizeErrors } from "./lib/npm-pack-budget.mjs";
import { collectBundledPluginPackageDependencySpecs } from "./lib/plugin-package-dependencies.mjs";
import { listPluginSdkDistArtifacts } from "./lib/plugin-sdk-entries.mjs";
import {
listPluginSdkDistArtifacts,
listPrivateLocalOnlyPluginSdkDistArtifacts,
} from "./lib/plugin-sdk-entries.mjs";
import {
runInstalledWorkspaceBootstrapSmoke,
WORKSPACE_TEMPLATE_PACK_PATHS,
@@ -99,10 +103,12 @@ const forbiddenPrefixes = [
"dist/plugin-sdk/qa-channel-protocol.",
"dist/plugin-sdk/qa-lab.",
"dist/plugin-sdk/qa-runtime.",
"dist/plugin-sdk/src/",
"dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts",
"dist/plugin-sdk/src/plugin-sdk/qa-channel-protocol.d.ts",
"dist/plugin-sdk/src/plugin-sdk/qa-lab.d.ts",
"dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
...listPrivateLocalOnlyPluginSdkDistArtifacts(),
"dist/qa-runtime-",
"dist/plugin-sdk/.tsbuildinfo",
"docs/.generated/",
@@ -117,6 +123,12 @@ const forbiddenPrivateQaContentMarkers = [
"qa-lab/cli.js",
"qa-lab/runtime-api.js",
] as const;
const forbiddenPrivatePluginSdkDeclarationMarkers = [
"//#region src/agents/test-helpers/",
"//#region src/plugin-sdk/test-helpers/",
"//#region src/test-helpers/",
"//#region src/test-utils/",
] as const;
const forbiddenPrivateQaContentScanPrefixes = ["dist/"] as const;
const forbiddenPluginSdkRootAliasMinifiedExportPattern = /\bmod\.[A-Za-z_$]\b/u;
const appcastPath = resolve("appcast.xml");
@@ -149,7 +161,9 @@ export const PACKED_COMPLETION_SMOKE_ARGS = [
"--shell",
"zsh",
] as const;
const PACKED_PLUGIN_SDK_TYPESCRIPT_SMOKE_FIXTURE = resolve(
"scripts/fixtures/packed-plugin-sdk-type-smoke.ts",
);
export function collectSkillShellScriptExecutableErrors(rootDir = resolve(".")): string[] {
if (process.platform === "win32") {
return [];
@@ -483,6 +497,78 @@ function verifyPackedInstalledPackage(params: {
}
}
export function createPackedPluginSdkTypescriptSmokeProject(params: {
consumerDir: string;
packageSpec: string;
}): void {
mkdirSync(join(params.consumerDir, "src"), { recursive: true });
writeFileSync(
join(params.consumerDir, "package.json"),
`${JSON.stringify(
{
name: "openclaw-plugin-sdk-type-smoke",
private: true,
type: "module",
dependencies: {
openclaw: params.packageSpec,
},
},
null,
2,
)}\n`,
"utf8",
);
writeFileSync(
join(params.consumerDir, "tsconfig.json"),
`${JSON.stringify(
{
compilerOptions: {
module: "NodeNext",
moduleResolution: "NodeNext",
noEmit: true,
strict: true,
skipLibCheck: true,
target: "ES2022",
},
include: ["src/index.ts"],
},
null,
2,
)}\n`,
"utf8",
);
copyFileSync(
PACKED_PLUGIN_SDK_TYPESCRIPT_SMOKE_FIXTURE,
join(params.consumerDir, "src", "index.ts"),
);
}
function runPackedPluginSdkTypescriptSmoke(tarballPath: string, tmpRoot: string): void {
const consumerDir = join(tmpRoot, "plugin-sdk-type-consumer");
createPackedPluginSdkTypescriptSmokeProject({
consumerDir,
packageSpec: `file:${tarballPath}`,
});
execNpm(["install", "--ignore-scripts", "--no-audit", "--no-fund"], {
cwd: consumerDir,
encoding: "utf8",
stdio: "inherit",
});
const installedOpenClawRoot = join(consumerDir, "node_modules", "openclaw");
const tscPath = [
join(consumerDir, "node_modules", "typescript", "bin", "tsc"),
join(installedOpenClawRoot, "node_modules", "typescript", "bin", "tsc"),
].find((candidate) => existsSync(candidate));
if (!tscPath) {
throw new Error("release-check: packed plugin SDK TypeScript smoke could not find tsc.");
}
execFileSync(process.execPath, [tscPath, "-p", "tsconfig.json", "--pretty", "false"], {
cwd: consumerDir,
stdio: "inherit",
});
}
export function writePackedBundledPluginActivationConfig(homeDir: string): void {
const configPath = join(homeDir, ".openclaw", "openclaw.json");
mkdirSync(join(homeDir, ".openclaw"), { recursive: true });
@@ -652,6 +738,7 @@ function runPackedBundledChannelEntrySmoke(): void {
runPackedBundledPluginPostinstall(packageRoot);
runPackedBundledPluginActivationSmoke(packageRoot, tmpRoot);
runPackedTaskRegistryControlRuntimeSmoke(packageRoot);
runPackedPluginSdkTypescriptSmoke(tarballPath, tmpRoot);
execFileSync(
process.execPath,
[
@@ -759,7 +846,10 @@ export function collectForbiddenPackContentPaths(
} catch {
return false;
}
return forbiddenPrivateQaContentMarkers.some((marker) => content.includes(marker));
return (
forbiddenPrivateQaContentMarkers.some((marker) => content.includes(marker)) ||
forbiddenPrivatePluginSdkDeclarationMarkers.some((marker) => content.includes(marker))
);
})
.toSorted((left, right) => left.localeCompare(right));
}

View File

@@ -1,6 +1,8 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { pluginSdkEntrypoints } from "./lib/plugin-sdk-entries.mjs";
import { build } from "tsdown";
import { buildPluginSdkEntrySources, pluginSdkEntrypoints } from "./lib/plugin-sdk-entries.mjs";
const RUNTIME_SHIMS: Partial<Record<string, string>> = {
"webhook-path": [
@@ -37,17 +39,63 @@ const RUNTIME_SHIMS: Partial<Record<string, string>> = {
].join("\n"),
};
// TypeScript declaration emit writes files under `dist/plugin-sdk/src/plugin-sdk/*` because the
// source lives at `src/plugin-sdk/*` and `rootDir` is `.` (repo root, to support
// cross-src/extensions refs).
//
// Our package export map points subpath `types` at `dist/plugin-sdk/<entry>.d.ts`, so we
// generate stable entry d.ts files that re-export the real declarations.
for (const entry of pluginSdkEntrypoints) {
const typeOut = path.join(process.cwd(), `dist/plugin-sdk/${entry}.d.ts`);
fs.mkdirSync(path.dirname(typeOut), { recursive: true });
fs.writeFileSync(typeOut, `export * from "./src/plugin-sdk/${entry}.js";\n`, "utf8");
function isBareImportSpecifier(id: string): boolean {
return !id.startsWith(".") && !id.startsWith("/") && !/^[A-Za-z]:[\\/]/u.test(id);
}
function removeExistingFlatDeclarations(outDir: string): void {
if (!fs.existsSync(outDir)) {
return;
}
for (const entry of fs.readdirSync(outDir, { withFileTypes: true })) {
if (!entry.isFile() || !entry.name.endsWith(".d.ts")) {
continue;
}
fs.rmSync(path.join(outDir, entry.name), { force: true });
}
}
function copyFlatDeclarations(fromDir: string, toDir: string): void {
fs.mkdirSync(toDir, { recursive: true });
for (const entry of fs.readdirSync(fromDir, { withFileTypes: true })) {
if (!entry.isFile() || !entry.name.endsWith(".d.ts")) {
continue;
}
fs.copyFileSync(path.join(fromDir, entry.name), path.join(toDir, entry.name));
}
}
const distPluginSdkDir = path.join(process.cwd(), "dist/plugin-sdk");
const flatDeclarationTempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-sdk-dts-"));
try {
await build({
clean: true,
config: false,
deps: { neverBundle: (id) => isBareImportSpecifier(id) },
dts: true,
entry: buildPluginSdkEntrySources(),
failOnWarn: false,
fixedExtension: false,
format: "esm",
logLevel: "error",
outDir: flatDeclarationTempDir,
outExtensions: () => ({ js: ".js", dts: ".d.ts" }),
platform: "node",
report: false,
tsconfig: "tsconfig.plugin-sdk.dts.json",
});
removeExistingFlatDeclarations(distPluginSdkDir);
copyFlatDeclarations(flatDeclarationTempDir, distPluginSdkDir);
} finally {
fs.rmSync(flatDeclarationTempDir, { recursive: true, force: true });
}
// The root npm package ships flat bundled declarations under `dist/plugin-sdk`.
// The private workspace package keeps source-shaped declaration paths for local
// package-boundary projects, so bridge them back to the packaged flat entries.
for (const entry of pluginSdkEntrypoints) {
const packageTypeOut = path.join(
process.cwd(),
`packages/plugin-sdk/dist/src/plugin-sdk/${entry}.d.ts`,

View File

@@ -85,6 +85,20 @@ describe("package dist inventory", () => {
"qa-lab",
"cli.d.ts",
);
const omittedDeepPluginSdkDeclaration = path.join(
packageRoot,
"dist",
"plugin-sdk",
"src",
"plugin-sdk",
"provider-entry.d.ts",
);
const flatPluginSdkDeclaration = path.join(
packageRoot,
"dist",
"plugin-sdk",
"provider-entry.d.ts",
);
const omittedQaRuntimeChunk = path.join(packageRoot, "dist", "qa-runtime-B9LDtssJ.js");
const [omittedBuildStamp, omittedRuntimePostBuildStamp] = LOCAL_BUILD_METADATA_DIST_PATHS.map(
(relativePath) => path.join(packageRoot, relativePath),
@@ -95,6 +109,7 @@ describe("package dist inventory", () => {
await fs.mkdir(path.dirname(omittedQaMatrixChunk), { recursive: true });
await fs.mkdir(path.dirname(omittedQaLabTypes), { recursive: true });
await fs.mkdir(path.join(packageRoot, "dist", "plugin-sdk"), { recursive: true });
await fs.mkdir(path.dirname(omittedDeepPluginSdkDeclaration), { recursive: true });
await fs.writeFile(packagedQaChannelRuntime, "export {};\n", "utf8");
await fs.writeFile(packagedQaLabRuntime, "export {};\n", "utf8");
await fs.writeFile(omittedQaChunk, "export {};\n", "utf8");
@@ -104,12 +119,16 @@ describe("package dist inventory", () => {
await fs.writeFile(omittedQaChannelPluginSdk, "export {};\n", "utf8");
await fs.writeFile(omittedQaChannelProtocolPluginSdk, "export {};\n", "utf8");
await fs.writeFile(omittedQaLabTypes, "export {};\n", "utf8");
await fs.writeFile(omittedDeepPluginSdkDeclaration, "export {};\n", "utf8");
await fs.writeFile(flatPluginSdkDeclaration, "export {};\n", "utf8");
await fs.writeFile(omittedQaRuntimeChunk, "export {};\n", "utf8");
await fs.writeFile(omittedBuildStamp, "{}\n", "utf8");
await fs.writeFile(omittedRuntimePostBuildStamp, "{}\n", "utf8");
await fs.writeFile(omittedMap, "{}", "utf8");
await expect(writePackageDistInventory(packageRoot)).resolves.toStrictEqual([]);
await expect(writePackageDistInventory(packageRoot)).resolves.toStrictEqual([
"dist/plugin-sdk/provider-entry.d.ts",
]);
});
});

View File

@@ -33,6 +33,9 @@ const OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES = new Set([
`dist/plugin-sdk/src/plugin-sdk/${LEGACY_QA_LAB_DIR}.d.ts`,
"dist/plugin-sdk/src/plugin-sdk/qa-runtime.d.ts",
]);
// The build keeps source-shaped SDK declarations for local boundary projects,
// but the npm package ships flat declarations and must not inventory the old tree.
const OMITTED_DEEP_PLUGIN_SDK_DECLARATION_PREFIX = "dist/plugin-sdk/src/";
const OMITTED_PRIVATE_QA_DIST_PREFIXES = ["dist/qa-runtime-"];
const OMITTED_PLUGIN_SDK_TEST_FILES = new Set([
"dist/plugin-sdk/agent-runtime-test-contracts.d.ts",
@@ -72,6 +75,7 @@ const OMITTED_DIST_SUBTREE_PATTERNS = [
/^dist\/extensions\/node_modules(?:\/|$)/u,
/^dist\/extensions\/[^/]+\/node_modules(?:\/|$)/u,
/^dist\/extensions\/qa-matrix(?:\/|$)/u,
/^dist\/plugin-sdk\/src(?:\/|$)/u,
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_CHANNEL_DIR}(?:/|$)`, "u"),
new RegExp(`^dist/plugin-sdk/extensions/${LEGACY_QA_LAB_DIR}(?:/|$)`, "u"),
] as const;
@@ -275,10 +279,7 @@ function isPackageFilesExcludedDistPath(
);
}
function isPackagedDistPath(
relativePath: string,
rules: PackageDistInventoryRules,
): boolean {
function isPackagedDistPath(relativePath: string, rules: PackageDistInventoryRules): boolean {
if (!relativePath.startsWith("dist/")) {
return false;
}
@@ -306,6 +307,9 @@ function isPackagedDistPath(
if (isOmittedPluginSdkTestPath(relativePath)) {
return false;
}
if (relativePath.startsWith(OMITTED_DEEP_PLUGIN_SDK_DECLARATION_PREFIX)) {
return false;
}
if (
OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) ||
OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES.has(relativePath) ||
@@ -319,10 +323,7 @@ function isPackagedDistPath(
return true;
}
function isOmittedDistSubtree(
relativePath: string,
rules: PackageDistInventoryRules,
): boolean {
function isOmittedDistSubtree(relativePath: string, rules: PackageDistInventoryRules): boolean {
return (
isExternalizedBundledExtensionDistPath(relativePath, rules.externalizedExtensionIds) ||
isLegacyPluginDependencyDirPath(relativePath) ||

View File

@@ -1,3 +1,7 @@
// Numeric coercion helpers for plugin runtime inputs.
export { parseFiniteNumber } from "../infra/parse-finite-number.js";
export {
parseFiniteNumber,
parseStrictFiniteNumber,
parseStrictPositiveInteger,
} from "../infra/parse-finite-number.js";

View File

@@ -4,7 +4,10 @@ import { dirname, join, win32 } from "node:path";
import { bundledDistPluginFile, bundledPluginFile } from "openclaw/plugin-sdk/test-fixtures";
import { describe, expect, it } from "vitest";
import { listBundledPluginPackArtifacts } from "../scripts/lib/bundled-plugin-build-entries.mjs";
import { listPluginSdkDistArtifacts } from "../scripts/lib/plugin-sdk-entries.mjs";
import {
listPluginSdkDistArtifacts,
listPrivateLocalOnlyPluginSdkDistArtifacts,
} from "../scripts/lib/plugin-sdk-entries.mjs";
import {
WORKSPACE_TEMPLATE_PACK_PATHS,
createWorkspaceBootstrapSmokeEnv,
@@ -20,6 +23,7 @@ import {
collectSkillShellScriptExecutableErrors,
collectPackUnpackedSizeErrors,
collectPackedInstalledPackageVerificationErrors,
createPackedPluginSdkTypescriptSmokeProject,
createPackedCompletionSmokeEnv,
createPackedCliSmokeEnv,
createPackedBundledPluginPostinstallEnv,
@@ -46,6 +50,7 @@ function makePackResult(filename: string, unpackedSize: number) {
}
const requiredPluginSdkPackPaths = [...listPluginSdkDistArtifacts(), "dist/plugin-sdk/compat.js"];
const privateLocalOnlyPluginSdkPackPaths = listPrivateLocalOnlyPluginSdkDistArtifacts();
const requiredBundledPluginPackPaths = listBundledPluginPackArtifacts();
describe("collectAppcastSparkleVersionErrors", () => {
@@ -442,6 +447,21 @@ describe("collectForbiddenPackPaths", () => {
]);
});
it("blocks the old deep plugin SDK declaration tree from npm pack output", () => {
expect(
collectForbiddenPackPaths([
"dist/index.js",
"dist/plugin-sdk/index.d.ts",
"dist/plugin-sdk/types-abc123.d.ts",
"dist/plugin-sdk/src/channels/plugins/types.public.d.ts",
"dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts",
]),
).toEqual([
"dist/plugin-sdk/src/channels/plugins/types.public.d.ts",
"dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts",
]);
});
it("blocks local build metadata from npm pack output", () => {
expect(
collectForbiddenPackPaths(["dist/index.js", ...LOCAL_BUILD_METADATA_DIST_PATHS]),
@@ -453,6 +473,21 @@ describe("collectForbiddenPackPaths", () => {
for (const entry of LOCAL_BUILD_METADATA_DIST_PATHS) {
expect(pkg.files).toContain(`!${entry}`);
}
expect(pkg.files).toContain("!dist/plugin-sdk/src/**");
});
it("blocks private local-only plugin SDK artifacts from npm pack output", () => {
expect(
collectForbiddenPackPaths(["dist/index.js", ...privateLocalOnlyPluginSdkPackPaths]),
).toEqual([...privateLocalOnlyPluginSdkPackPaths].toSorted());
});
it("keeps private local-only plugin SDK artifacts excluded by package files", () => {
const pkg = JSON.parse(readFileSync("package.json", "utf8")) as { files?: string[] };
for (const entry of privateLocalOnlyPluginSdkPackPaths) {
expect(pkg.files).toContain(`!${entry}`);
}
});
it("blocks legacy runtime dependency stamps from npm pack output", () => {
@@ -539,6 +574,25 @@ describe("collectForbiddenPackPaths", () => {
rmSync(tempRoot, { recursive: true, force: true });
}
});
it("blocks root plugin SDK declarations that still reference private test helpers", () => {
const tempRoot = mkdtempSync(join(tmpdir(), "openclaw-release-private-sdk-"));
try {
mkdirSync(join(tempRoot, "dist", "plugin-sdk"), { recursive: true });
writeFileSync(
join(tempRoot, "dist", "plugin-sdk", "testing.d.ts"),
"//#region src/plugin-sdk/test-helpers/session.ts\n",
"utf8",
);
expect(collectForbiddenPackContentPaths(["dist/plugin-sdk/testing.d.ts"], tempRoot)).toEqual([
"dist/plugin-sdk/testing.d.ts",
]);
} finally {
rmSync(tempRoot, { recursive: true, force: true });
}
});
});
describe("collectMissingPackPaths", () => {
@@ -699,6 +753,46 @@ describe("resolveMissingPackBuildHint", () => {
});
});
describe("createPackedPluginSdkTypescriptSmokeProject", () => {
it("writes a consumer project that imports representative public SDK subpaths", () => {
const root = mkdtempSync(join(tmpdir(), "release-check-plugin-sdk-types-"));
try {
const consumerDir = join(root, "consumer");
const packageRoot = join(root, "openclaw");
createPackedPluginSdkTypescriptSmokeProject({
consumerDir,
packageSpec: `file:${packageRoot}`,
});
const packageJson = JSON.parse(readFileSync(join(consumerDir, "package.json"), "utf8")) as {
dependencies?: Record<string, string>;
};
const tsconfig = JSON.parse(readFileSync(join(consumerDir, "tsconfig.json"), "utf8")) as {
compilerOptions?: Record<string, unknown>;
};
const source = readFileSync(join(consumerDir, "src", "index.ts"), "utf8");
const fixtureSource = readFileSync(
"scripts/fixtures/packed-plugin-sdk-type-smoke.ts",
"utf8",
);
expect(packageJson.dependencies?.openclaw).toBe(`file:${packageRoot}`);
expect(tsconfig.compilerOptions?.skipLibCheck).toBe(true);
expect(source).toBe(fixtureSource);
expect(source).toContain('"openclaw/plugin-sdk"');
expect(source).toContain('"openclaw/plugin-sdk/provider-entry"');
expect(source).toContain('"openclaw/plugin-sdk/channel-entry-contract"');
expect(source).toContain('"openclaw/plugin-sdk/config-contracts"');
expect(source).toContain('"openclaw/plugin-sdk/runtime-env"');
expect(source).toContain("type PublicPluginSdkModules = [");
expect(source).not.toContain("TelegramAccountConfig");
expect(source).not.toContain("openclaw/plugin-sdk/channel-contract-testing");
} finally {
rmSync(root, { recursive: true, force: true });
}
});
});
describe("collectPackUnpackedSizeErrors", () => {
it("accepts pack results within the unpacked size budget", () => {
expect(

View File

@@ -6,6 +6,8 @@ import { describe, expect, it } from "vitest";
import { LOCAL_BUILD_METADATA_DIST_PATHS } from "../../scripts/lib/local-build-metadata-paths.mjs";
const CHECK_SCRIPT = "scripts/check-openclaw-package-tarball.mjs";
const FLAT_PLUGIN_SDK_DECLARATION = "dist/plugin-sdk/provider-entry.d.ts";
const DEEP_PLUGIN_SDK_DECLARATION = "dist/plugin-sdk/src/plugin-sdk/provider-entry.d.ts";
function withTarball(
inventory: string[],
@@ -110,6 +112,34 @@ describe("check-openclaw-package-tarball", () => {
);
});
it("rejects stale deep plugin SDK declaration inventory entries", () => {
withTarball(
[FLAT_PLUGIN_SDK_DECLARATION, DEEP_PLUGIN_SDK_DECLARATION],
{ [FLAT_PLUGIN_SDK_DECLARATION]: "export {};\n" },
(tarball) => {
const result = spawnSync("node", [CHECK_SCRIPT, tarball], { encoding: "utf8" });
expect(result.status).not.toBe(0);
expect(result.stderr).toContain(
`inventory references missing tar entry ${DEEP_PLUGIN_SDK_DECLARATION}`,
);
},
);
});
it("accepts flat plugin SDK declaration inventory without the old deep tree", () => {
withTarball(
[FLAT_PLUGIN_SDK_DECLARATION],
{ [FLAT_PLUGIN_SDK_DECLARATION]: "export {};\n" },
(tarball) => {
const result = spawnSync("node", [CHECK_SCRIPT, tarball], { encoding: "utf8" });
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toContain("OpenClaw package tarball integrity passed.");
},
);
});
it("rejects dist files that import missing relative chunks", () => {
withTarball(
["dist/cli/run-main.js"],