diff --git a/docs/plugins/sdk-migration.md b/docs/plugins/sdk-migration.md index 2fc6b56c4e97..3b9e108097a0 100644 --- a/docs/plugins/sdk-migration.md +++ b/docs/plugins/sdk-migration.md @@ -1038,16 +1038,25 @@ apps own device capture/playback UX. | **Each compat record's `removeAfter` date** | That specific surface is eligible for removal; `pnpm plugins:boundary-report --fail-on-eligible-compat` fails CI once the date passes. | | **Next major release** | Any surfaces still not migrated are removed; plugins still using them will fail. | -The deprecated public SDK subpaths below have registry-backed removal windows. +The public SDK subpaths below have registry-backed removal or demotion windows. They do not currently emit a runtime warning when an external plugin imports -them; `scripts/check-deprecated-api-usage.mjs` only diagnoses imports from core -and bundled plugin source. +them. The repository deprecated-usage guard applies only to the fully unused +θ1 tier and the earlier compatibility tier; θ2 remains available to bundled +plugins during the window. -| `removeAfter` | Deprecated SDK subpaths | -| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `2026-07-30` | `agent-dir-compat`, `channel-envelope`, `channel-inbound-roots`, `channel-location`, `channel-message-runtime`, `channel-pairing-paths`, `channel-reply-options-runtime`, `config-schema`, `config-types`, `direct-dm`, `direct-dm-access`, `mattermost`, `media-generation-runtime-shared`, `memory-core`, `memory-core-engine-runtime`, `memory-core-host-events`, `memory-core-host-multimodal`, `memory-core-host-query`, `memory-host-files`, `memory-host-status`, `music-generation-core`, `outbound-runtime`, `outbound-send-deps`, `provider-auth-login`, `provider-zai-endpoint`, `reply-dedupe`, `runtime-logger`, `runtime-secret-resolution`, `self-hosted-provider-setup`, `setup-adapter-runtime`, `telegram-command-config`, `webhook-path`, `zalouser` | -| `2026-08-15` | `agent-config-primitives`, `channel-logging`, `channel-secret-runtime`, `channel-streaming`, `group-access`, `inbound-reply-dispatch`, `matrix`, `text-runtime`, `zod` | -| `2026-09-01` | `channel-lifecycle`, `channel-message`, `channel-reply-pipeline`, `config-runtime`, `infra-runtime` | +For the window introduced on 2026-07-15, θ1 has no known external or bundled +consumers and will be deleted after the window. θ2 has bundled consumers but no +known external consumers; only its public package export will be retired. Its +module will remain available to bundled plugins as a private-local-only +subpath. + +| `removeAfter` | Tier | SDK subpaths | +| ------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `2026-07-30` | Earlier compatibility deprecations | `agent-dir-compat`, `channel-envelope`, `channel-inbound-roots`, `channel-location`, `channel-message-runtime`, `channel-pairing-paths`, `channel-reply-options-runtime`, `config-schema`, `config-types`, `direct-dm`, `direct-dm-access`, `mattermost`, `media-generation-runtime-shared`, `memory-core`, `memory-core-engine-runtime`, `memory-core-host-events`, `memory-core-host-multimodal`, `memory-core-host-query`, `memory-host-files`, `memory-host-status`, `music-generation-core`, `outbound-runtime`, `outbound-send-deps`, `provider-auth-login`, `provider-zai-endpoint`, `reply-dedupe`, `runtime-logger`, `runtime-secret-resolution`, `self-hosted-provider-setup`, `setup-adapter-runtime`, `telegram-command-config`, `webhook-path`, `zalouser` | +| `2026-07-30` | θ1: fully unused; remove subpath | `command-gating`, `lmstudio`, `lmstudio-runtime`, `secret-provider-integration`, `skills-runtime` | +| `2026-07-30` | θ2: bundled-only; retire public export | `access-groups`, `account-resolution-runtime`, `acp-binding-resolve-runtime`, `acp-binding-runtime`, `acp-runtime`, `acp-runtime-backend`, `agent-core`, `agent-harness-exec-review-runtime`, `agent-harness-task-runtime`, `agent-harness-tool-runtime`, `agent-media-payload`, `agent-sessions`, `approval-reaction-runtime`, `approval-reference-runtime`, `async-lock-runtime`, `browser-config`, `bundled-channel-config-schema`, `channel-activity-runtime`, `channel-config-writes`, `channel-mention-gating`, `channel-route`, `channel-secret-tts-runtime`, `channel-targets`, `chat-channel-ids`, `cli-backend`, `cli-runtime`, `codex-mcp-projection`, `command-status-runtime`, `command-surface`, `concurrency-runtime`, `context-visibility-runtime`, `conversation-binding-runtime`, `cron-store-runtime`, `dangerous-name-runtime`, `delivery-queue-runtime`, `direct-dm-guard-policy`, `directory-config-runtime`, `document-extractor`, `embedding-providers`, `exec-approvals-runtime`, `expect-runtime`, `fetch-runtime`, `file-access-runtime`, `file-lock`, `global-singleton`, `group-activation`, `heartbeat-runtime`, `host-runtime`, `html-entity-runtime`, `image-generation`, `image-generation-core`, `image-generation-runtime`, `inline-image-data-url-runtime`, `json-schema-runtime`, `json-unsafe-integers`, `keyed-async-queue`, `llm`, `markdown-table-runtime`, `media-generation-runtime`, `media-understanding`, `memory-core-host-embedding-registry`, `memory-core-host-engine-embeddings`, `memory-core-host-engine-qmd`, `memory-core-host-engine-storage`, `memory-core-host-runtime-cli`, `memory-core-host-runtime-core`, `memory-core-host-runtime-files`, `memory-core-host-secret`, `memory-core-host-status`, `memory-host-core`, `memory-host-events`, `memory-host-markdown`, `memory-host-search`, `message-tool-delivery-hints`, `migration`, `migration-runtime`, `music-generation`, `node-host`, `number-runtime`, `outbound-media`, `pair-loop-guard-runtime`, `plugin-config-runtime`, `plugin-state-runtime`, `poll-runtime`, `process-runtime`, `provider-auth-api-key`, `provider-auth-login-flow-runtime`, `provider-auth-result`, `provider-auth-runtime`, `provider-catalog-live-runtime`, `provider-catalog-shared`, `provider-entry`, `provider-env-vars`, `provider-http`, `provider-model-shared`, `provider-model-types`, `provider-oauth-runtime`, `provider-onboard`, `provider-selection-runtime`, `provider-setup`, `provider-stream`, `provider-stream-family`, `provider-stream-shared`, `provider-tools`, `provider-transport-runtime`, `provider-usage`, `provider-web-fetch`, `provider-web-fetch-contract`, `provider-web-search`, `provider-web-search-config-contract`, `provider-web-search-contract`, `qa-live-transport-scenarios`, `qa-runner-runtime`, `realtime-bootstrap-context`, `realtime-transcription`, `realtime-voice`, `reply-reference`, `request-url`, `response-limit-runtime`, `retry-runtime`, `runtime-doctor`, `runtime-fetch`, `sandbox`, `secret-file-runtime`, `secure-random-runtime`, `session-binding-runtime`, `session-catalog`, `session-key-runtime`, `session-transcript-hit`, `session-transcript-runtime`, `session-visibility`, `simple-completion-runtime`, `speech`, `speech-core`, `sqlite-runtime`, `ssrf-dispatcher`, `string-normalization-runtime`, `system-event-runtime`, `talk-config-runtime`, `target-resolver-runtime`, `text-autolink-runtime`, `text-utility-runtime`, `thread-bindings-runtime`, `thread-bindings-session-runtime`, `time-runtime`, `tool-payload`, `tool-plugin`, `tool-results`, `transcripts`, `transport-ready-runtime`, `tts-runtime`, `types`, `video-generation`, `video-generation-core`, `video-generation-runtime`, `web-content-extractor`, `webhook-targets`, `windows-spawn` | +| `2026-08-15` | Earlier compatibility deprecations | `agent-config-primitives`, `channel-logging`, `channel-secret-runtime`, `channel-streaming`, `group-access`, `inbound-reply-dispatch`, `matrix`, `text-runtime`, `zod` | +| `2026-09-01` | Earlier compatibility deprecations | `channel-lifecycle`, `channel-message`, `channel-reply-pipeline`, `config-runtime`, `infra-runtime` | All core plugins have already migrated. External plugins should migrate before the next major release. Run `pnpm plugins:boundary-report` to see which diff --git a/scripts/lib/plugin-sdk-deprecated-public-subpaths.json b/scripts/lib/plugin-sdk-deprecated-public-subpaths.json index 235e6ff47616..9fb5f898a4c5 100644 --- a/scripts/lib/plugin-sdk-deprecated-public-subpaths.json +++ b/scripts/lib/plugin-sdk-deprecated-public-subpaths.json @@ -15,6 +15,7 @@ "channel-secret-runtime", "channel-streaming", "command-auth", + "command-gating", "compat", "config-runtime", "config-schema", @@ -25,6 +26,8 @@ "group-access", "inbound-reply-dispatch", "infra-runtime", + "lmstudio", + "lmstudio-runtime", "matrix", "mattermost", "media-generation-runtime-shared", @@ -44,8 +47,10 @@ "reply-dedupe", "runtime-logger", "runtime-secret-resolution", + "secret-provider-integration", "self-hosted-provider-setup", "setup-adapter-runtime", + "skills-runtime", "telegram-account", "telegram-command-config", "text-runtime", diff --git a/scripts/plugin-sdk-surface-report.mjs b/scripts/plugin-sdk-surface-report.mjs index 949cf9e47022..56590b55a15e 100644 --- a/scripts/plugin-sdk-surface-report.mjs +++ b/scripts/plugin-sdk-surface-report.mjs @@ -93,14 +93,18 @@ function readPluginSdkEntrypointBudgetEnv(name, fallback, env = process.env) { const defaultPublicDeprecatedExportsByEntrypointBudget = Object.freeze({ core: 2, health: 1, - lmstudio: 1, + "command-gating": 5, + lmstudio: 37, + "lmstudio-runtime": 27, "provider-setup": 1, "self-hosted-provider-setup": 14, routing: 1, runtime: 3, "runtime-logger": 3, "runtime-secret-resolution": 5, + "secret-provider-integration": 4, "setup-adapter-runtime": 1, + "skills-runtime": 5, "channel-streaming": 49, "approval-gateway-runtime": 1, "approval-handler-runtime": 1, @@ -233,7 +237,8 @@ export function readPluginSdkSurfaceBudgets(env = process.env) { "OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_DEPRECATED_EXPORTS", // +2: group scope encoder/key builder mirrored by deprecated compat. // Harvest: channel-ingress -8; dead channel-message dispatch aliases -23. - 3262, + // +77: five zero-consumer subpaths enter their removal window. + 3339, env, ), publicWildcardReexports: readPluginSdkSurfaceBudgetEnv( diff --git a/src/plugins/compat/registry.test.ts b/src/plugins/compat/registry.test.ts index 7a95f3cb973f..f71dcd35948d 100644 --- a/src/plugins/compat/registry.test.ts +++ b/src/plugins/compat/registry.test.ts @@ -22,6 +22,23 @@ const deprecatedTargetParserCompatFiles = new Set([ "src/infra/outbound/outbound-session.test-helpers.ts", "src/plugins/compat/registry.test.ts", ]); +const publicSdkContractNarrowingTiers = [ + { + name: "fully unused subpath", + codeSuffix: "-unused-subpath", + count: 5, + replacement: "none needed — no known consumers; the subpath is removed without successor", + releaseNote: /no known consumers.*removal without a successor/u, + }, + { + name: "bundled-only public export", + codeSuffix: "-public-demotion", + count: 158, + replacement: + "subpath becomes internal (private-local-only); no external successor — no known external consumers", + releaseNote: /public export.*module stays available for bundled plugins.*private-local-only/u, + }, +] as const; function expectNonEmptyStringList(values: readonly string[], label: string) { expect(values, label).toEqual([expect.stringMatching(/\S/u), ...values.slice(1)]); @@ -64,6 +81,31 @@ describe("plugin compatibility registry", () => { } }); + it.each(publicSdkContractNarrowingTiers)( + "keeps the $name tier on its registry-backed window", + ({ codeSuffix, count, replacement, releaseNote }) => { + const records = listPluginCompatRecords().filter((record) => + record.code.endsWith(codeSuffix), + ); + + expect(records).toHaveLength(count); + for (const record of records) { + expect(record).toMatchObject({ + status: "deprecated", + owner: "sdk", + introduced: "2026-07-15", + deprecated: "2026-07-15", + warningStarts: "2026-07-15", + removeAfter: "2026-07-30", + replacement, + docsPath: "/plugins/sdk-migration", + }); + expect(record.surfaces).toEqual([expect.stringMatching(/^openclaw\/plugin-sdk\//u)]); + expect(record.releaseNote).toMatch(releaseNote); + } + }, + ); + it("keeps loaded target compatibility surfaces exported during their removal windows", () => { const source = fs.readFileSync("src/channels/plugins/target-parsing-loaded.ts", "utf8"); expect(source).toMatch(/export type \{ ChannelRouteParsedTarget \}/u); diff --git a/src/plugins/compat/registry.ts b/src/plugins/compat/registry.ts index 250cb0e20b78..c04eb03563ac 100644 --- a/src/plugins/compat/registry.ts +++ b/src/plugins/compat/registry.ts @@ -375,8 +375,218 @@ const DEPRECATED_PLUGIN_SDK_SUBPATH_RECORDS = DEPRECATED_PLUGIN_SDK_SUBPATH_SEED }), ) satisfies readonly PluginCompatRecord[]; +const UNUSED_PUBLIC_PLUGIN_SDK_SUBPATHS = [ + "command-gating", + "lmstudio", + "lmstudio-runtime", + "secret-provider-integration", + "skills-runtime", +] as const; + +const BUNDLED_ONLY_PUBLIC_PLUGIN_SDK_SUBPATHS = [ + "access-groups", + "account-resolution-runtime", + "acp-binding-resolve-runtime", + "acp-binding-runtime", + "acp-runtime", + "acp-runtime-backend", + "agent-core", + "agent-harness-exec-review-runtime", + "agent-harness-task-runtime", + "agent-harness-tool-runtime", + "agent-media-payload", + "agent-sessions", + "approval-reaction-runtime", + "approval-reference-runtime", + "async-lock-runtime", + "browser-config", + "bundled-channel-config-schema", + "channel-activity-runtime", + "channel-config-writes", + "channel-mention-gating", + "channel-route", + "channel-secret-tts-runtime", + "channel-targets", + "chat-channel-ids", + "cli-backend", + "cli-runtime", + "codex-mcp-projection", + "command-status-runtime", + "command-surface", + "concurrency-runtime", + "context-visibility-runtime", + "conversation-binding-runtime", + "cron-store-runtime", + "dangerous-name-runtime", + "delivery-queue-runtime", + "direct-dm-guard-policy", + "directory-config-runtime", + "document-extractor", + "embedding-providers", + "exec-approvals-runtime", + "expect-runtime", + "fetch-runtime", + "file-access-runtime", + "file-lock", + "global-singleton", + "group-activation", + "heartbeat-runtime", + "host-runtime", + "html-entity-runtime", + "image-generation", + "image-generation-core", + "image-generation-runtime", + "inline-image-data-url-runtime", + "json-schema-runtime", + "json-unsafe-integers", + "keyed-async-queue", + "llm", + "markdown-table-runtime", + "media-generation-runtime", + "media-understanding", + "memory-core-host-embedding-registry", + "memory-core-host-engine-embeddings", + "memory-core-host-engine-qmd", + "memory-core-host-engine-storage", + "memory-core-host-runtime-cli", + "memory-core-host-runtime-core", + "memory-core-host-runtime-files", + "memory-core-host-secret", + "memory-core-host-status", + "memory-host-core", + "memory-host-events", + "memory-host-markdown", + "memory-host-search", + "message-tool-delivery-hints", + "migration", + "migration-runtime", + "music-generation", + "node-host", + "number-runtime", + "outbound-media", + "pair-loop-guard-runtime", + "plugin-config-runtime", + "plugin-state-runtime", + "poll-runtime", + "process-runtime", + "provider-auth-api-key", + "provider-auth-login-flow-runtime", + "provider-auth-result", + "provider-auth-runtime", + "provider-catalog-live-runtime", + "provider-catalog-shared", + "provider-entry", + "provider-env-vars", + "provider-http", + "provider-model-shared", + "provider-model-types", + "provider-oauth-runtime", + "provider-onboard", + "provider-selection-runtime", + "provider-setup", + "provider-stream", + "provider-stream-family", + "provider-stream-shared", + "provider-tools", + "provider-transport-runtime", + "provider-usage", + "provider-web-fetch", + "provider-web-fetch-contract", + "provider-web-search", + "provider-web-search-config-contract", + "provider-web-search-contract", + "qa-live-transport-scenarios", + "qa-runner-runtime", + "realtime-bootstrap-context", + "realtime-transcription", + "realtime-voice", + "reply-reference", + "request-url", + "response-limit-runtime", + "retry-runtime", + "runtime-doctor", + "runtime-fetch", + "sandbox", + "secret-file-runtime", + "secure-random-runtime", + "session-binding-runtime", + "session-catalog", + "session-key-runtime", + "session-transcript-hit", + "session-transcript-runtime", + "session-visibility", + "simple-completion-runtime", + "speech", + "speech-core", + "sqlite-runtime", + "ssrf-dispatcher", + "string-normalization-runtime", + "system-event-runtime", + "talk-config-runtime", + "target-resolver-runtime", + "text-autolink-runtime", + "text-utility-runtime", + "thread-bindings-runtime", + "thread-bindings-session-runtime", + "time-runtime", + "tool-payload", + "tool-plugin", + "tool-results", + "transcripts", + "transport-ready-runtime", + "tts-runtime", + "types", + "video-generation", + "video-generation-core", + "video-generation-runtime", + "web-content-extractor", + "webhook-targets", + "windows-spawn", +] as const; + +const UNUSED_PUBLIC_PLUGIN_SDK_SUBPATH_RECORDS = UNUSED_PUBLIC_PLUGIN_SDK_SUBPATHS.map( + (subpath) => ({ + code: `plugin-sdk-${subpath}-unused-subpath` as const, + status: "deprecated" as const, + owner: "sdk" as const, + introduced: "2026-07-15", + deprecated: "2026-07-15", + warningStarts: "2026-07-15", + removeAfter: "2026-07-30", + replacement: "none needed — no known consumers; the subpath is removed without successor", + docsPath: "/plugins/sdk-migration", + surfaces: [`openclaw/plugin-sdk/${subpath}`], + diagnostics: [ + "repository deprecated API usage guard for core and bundled plugins; no external runtime import warning", + ], + tests: ["src/plugins/compat/registry.test.ts"], + releaseNote: `The public \`openclaw/plugin-sdk/${subpath}\` subpath has no known consumers and is scheduled for removal without a successor.`, + }), +) satisfies readonly PluginCompatRecord[]; + +const BUNDLED_ONLY_PUBLIC_PLUGIN_SDK_SUBPATH_RECORDS = BUNDLED_ONLY_PUBLIC_PLUGIN_SDK_SUBPATHS.map( + (subpath) => ({ + code: `plugin-sdk-${subpath}-public-demotion` as const, + status: "deprecated" as const, + owner: "sdk" as const, + introduced: "2026-07-15", + deprecated: "2026-07-15", + warningStarts: "2026-07-15", + removeAfter: "2026-07-30", + replacement: + "subpath becomes internal (private-local-only); no external successor — no known external consumers", + docsPath: "/plugins/sdk-migration", + surfaces: [`openclaw/plugin-sdk/${subpath}`], + diagnostics: ["registry-backed public SDK demotion window; no external runtime import warning"], + tests: ["src/plugins/compat/registry.test.ts"], + releaseNote: `Only the public export for \`openclaw/plugin-sdk/${subpath}\` is retiring; the module stays available for bundled plugins as a private-local-only subpath.`, + }), +) satisfies readonly PluginCompatRecord[]; + const PLUGIN_COMPAT_RECORDS = [ ...DEPRECATED_PLUGIN_SDK_SUBPATH_RECORDS, + ...UNUSED_PUBLIC_PLUGIN_SDK_SUBPATH_RECORDS, + ...BUNDLED_ONLY_PUBLIC_PLUGIN_SDK_SUBPATH_RECORDS, { code: "legacy-before-agent-start", status: "deprecated",