Download src/plugins/compat/registry.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 12.3 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/plugins/compat/registry.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/plugins/compat/registry.test.ts
-
curl -L -o registry.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/plugins/compat/registry.test.ts
12.3 kB
| // Plugin compatibility registry tests cover compatibility metadata loading and validation. | |
| import fs from "node:fs"; | |
| import { describe, expect, it } from "vitest"; | |
| import { listPluginCompatRecords, type PluginCompatCode } from "./registry.js"; | |
| const datePattern = /^\d{4}-\d{2}-\d{2}$/u; | |
| const removalDatePendingCompatCodes = new Set<PluginCompatCode>([ | |
| "plugin-sdk-tool-plugin-public-demotion", | |
| "agent-harness-sdk-alias", | |
| "plugin-sdk-shipped-channel-setup-exports", | |
| ]); | |
| const retiredPluginSdkSubpathCodes = [ | |
| "plugin-sdk-channel-streaming-subpath", | |
| "plugin-sdk-text-runtime-subpath", | |
| "plugin-sdk-channel-secret-runtime-subpath", | |
| "plugin-sdk-agent-config-primitives-subpath", | |
| "plugin-sdk-matrix-subpath", | |
| "plugin-sdk-channel-logging-subpath", | |
| "plugin-sdk-group-access-subpath", | |
| "plugin-sdk-zod-subpath", | |
| ] as const satisfies readonly PluginCompatCode[]; | |
| const deprecationMarkingCodes = [ | |
| "plugin-sdk-channel-setup-input-fields", | |
| "plugin-sdk-broad-runtime-barrels", | |
| "plugin-sdk-provider-owned-helper-shims", | |
| "message-presentation-legacy-bridges", | |
| "plugin-sdk-focused-compat-aliases", | |
| "agent-harness-terminal-result-aliases", | |
| "official-plugin-export-aliases", | |
| "memory-host-compatibility-aliases", | |
| "plugin-runtime-api-compat-aliases", | |
| "plugin-provider-manifest-compat-aliases", | |
| ] as const; | |
| const deprecationMarkingSurfaceCounts: Record<(typeof deprecationMarkingCodes)[number], number> = { | |
| "plugin-sdk-channel-setup-input-fields": 22, | |
| "plugin-sdk-broad-runtime-barrels": 12, | |
| "plugin-sdk-provider-owned-helper-shims": 31, | |
| "message-presentation-legacy-bridges": 21, | |
| "plugin-sdk-focused-compat-aliases": 23, | |
| "agent-harness-terminal-result-aliases": 10, | |
| "official-plugin-export-aliases": 7, | |
| "memory-host-compatibility-aliases": 4, | |
| "plugin-runtime-api-compat-aliases": 27, | |
| "plugin-provider-manifest-compat-aliases": 9, | |
| }; | |
| function expectNonEmptyStringList(values: readonly string[], label: string) { | |
| expect(values, label).toEqual([expect.stringMatching(/\S/u), ...values.slice(1)]); | |
| for (const value of values) { | |
| expect(value, label).toMatch(/\S/u); | |
| } | |
| } | |
| describe("plugin compatibility registry", () => { | |
| it("keeps every record actionable", () => { | |
| for (const record of listPluginCompatRecords()) { | |
| expect(record.introduced, record.code).toMatch(datePattern); | |
| expect(record.docsPath, record.code).toMatch(/^\//u); | |
| if (record.status === "deprecated") { | |
| expect(record.deprecated, record.code).toMatch(datePattern); | |
| expect(record.warningStarts, record.code).toMatch(datePattern); | |
| if (record.removalGate !== undefined) { | |
| expect(record.removalGate, record.code).toBe("next-plugin-sdk-major"); | |
| expect(record.removeAfter, record.code).toBeUndefined(); | |
| } else if (removalDatePendingCompatCodes.has(record.code)) { | |
| expect(record.removeAfter, record.code).toBeUndefined(); | |
| } else { | |
| expect(record.removeAfter, record.code).toMatch(datePattern); | |
| } | |
| expect(record.replacement, record.code).toMatch(/\S/u); | |
| } | |
| expectNonEmptyStringList(record.surfaces, `${record.code}: surfaces`); | |
| expectNonEmptyStringList(record.diagnostics, `${record.code}: diagnostics`); | |
| expectNonEmptyStringList(record.tests, `${record.code}: tests`); | |
| for (const testPath of record.tests) { | |
| expect(fs.existsSync(testPath), `${record.code}: ${testPath}`).toBe(true); | |
| } | |
| } | |
| }); | |
| it("keeps blocked public SDK removals aligned with their actual gates", () => { | |
| const records = new Map(listPluginCompatRecords().map((record) => [record.code, record])); | |
| const staleRemovalWindows = [...records.values()].filter( | |
| (record) => | |
| record.status === "removal-pending" && | |
| record.removeAfter !== undefined && | |
| record.removeAfter <= "2026-09-02", | |
| ); | |
| expect(staleRemovalWindows).toEqual([]); | |
| for (const code of [ | |
| "plugin-sdk-config-runtime-subpath", | |
| "plugin-sdk-channel-reply-pipeline-subpath", | |
| "plugin-sdk-infra-runtime-subpath", | |
| "plugin-sdk-channel-lifecycle-subpath", | |
| "plugin-sdk-channel-message-subpath", | |
| ] as const satisfies readonly PluginCompatCode[]) { | |
| const record = records.get(code); | |
| expect(record).toMatchObject({ | |
| status: "removal-pending", | |
| deprecated: "2026-07-06", | |
| warningStarts: "2026-07-06", | |
| removeAfter: "2026-10-01", | |
| docsPath: "/plugins/sdk-migration", | |
| }); | |
| expect(record?.replacement).toMatch( | |
| /retain until supported external plugin migration is verified/u, | |
| ); | |
| } | |
| expect(records.get("plugin-sdk-media-understanding-public-demotion")).toMatchObject({ | |
| status: "removal-pending", | |
| removeAfter: "2026-09-30", | |
| }); | |
| expect(records.get("plugin-sdk-memory-host-core-public-demotion")).toMatchObject({ | |
| status: "removal-pending", | |
| removeAfter: "2026-09-30", | |
| }); | |
| expect(records.get("plugin-sdk-plugin-config-runtime-public-demotion")).toMatchObject({ | |
| status: "removal-pending", | |
| removeAfter: "2026-12-01", | |
| }); | |
| for (const code of removalDatePendingCompatCodes) { | |
| expect(records.get(code)).toMatchObject({ status: "deprecated" }); | |
| expect(records.get(code)?.removeAfter).toBeUndefined(); | |
| expect(records.get(code)?.replacement).toMatch(/retain/u); | |
| } | |
| expect(records.get("plugin-sdk-inbound-reply-dispatch-subpath")).toMatchObject({ | |
| status: "deprecated", | |
| removalGate: "next-plugin-sdk-major", | |
| removeAfter: undefined, | |
| }); | |
| expect(records.get("plugin-state-sync-keyed-store")).toMatchObject({ | |
| status: "deprecated", | |
| owner: "sdk", | |
| deprecated: "2026-09-11", | |
| warningStarts: "2026-09-11", | |
| removalGate: "next-plugin-sdk-major", | |
| docsPath: "/plugins/sdk-runtime/state-and-system#synchronous-keyed-store-migration", | |
| surfaces: [ | |
| "api.runtime.state.openSyncKeyedStore", | |
| "PluginStateSyncKeyedStore", | |
| "createPluginStateSyncKeyedStore", | |
| ], | |
| }); | |
| expect(records.get("plugin-state-sync-keyed-store")?.removeAfter).toBeUndefined(); | |
| expect(records.get("agent-harness-sdk-alias")?.surfaces).toEqual([ | |
| "openclaw/plugin-sdk/agent-harness", | |
| "openclaw/plugin-sdk/agent-harness-runtime", | |
| ]); | |
| }); | |
| it("keeps retired Plugin SDK subpaths as migration tombstones", () => { | |
| const records = new Map(listPluginCompatRecords().map((record) => [record.code, record])); | |
| for (const code of retiredPluginSdkSubpathCodes) { | |
| expect(records.get(code)).toMatchObject({ | |
| status: "removed", | |
| releaseNote: expect.stringMatching(/\S/u), | |
| }); | |
| expect(records.get(code)?.removeAfter, code).toBeUndefined(); | |
| } | |
| }); | |
| it("tracks the deprecation-marking families through the approved window", () => { | |
| const records = new Map(listPluginCompatRecords().map((record) => [record.code, record])); | |
| expect(deprecationMarkingCodes.map((code) => records.get(code)?.code)).toEqual( | |
| deprecationMarkingCodes, | |
| ); | |
| for (const code of deprecationMarkingCodes) { | |
| expect(records.get(code)).toMatchObject({ | |
| status: "deprecated", | |
| deprecated: "2026-07-25", | |
| warningStarts: "2026-07-25", | |
| removeAfter: "2026-10-01", | |
| }); | |
| expect(records.get(code)?.surfaces, code).toHaveLength(deprecationMarkingSurfaceCounts[code]); | |
| } | |
| expect(records.get("plugin-sdk-broad-runtime-barrels")?.surfaces).toEqual( | |
| expect.arrayContaining([ | |
| "openclaw/plugin-sdk/agent-runtime", | |
| "openclaw/plugin-sdk/agent-runtime loadModelCatalog params.useCache", | |
| "openclaw/plugin-sdk/agent-runtime loadModelCatalog params.cacheOnly", | |
| "openclaw/plugin-sdk/agent-runtime loadModelCatalog params.metadataSnapshot", | |
| "openclaw/plugin-sdk/agent-runtime loadModelCatalog", | |
| "openclaw/plugin-sdk/cli-runtime", | |
| "openclaw/plugin-sdk/conversation-runtime", | |
| "openclaw/plugin-sdk/hook-runtime", | |
| "openclaw/plugin-sdk/media-runtime", | |
| "openclaw/plugin-sdk/media-runtime buildAgentMediaPayload", | |
| "openclaw/plugin-sdk/plugin-runtime", | |
| "openclaw/plugin-sdk/security-runtime", | |
| ]), | |
| ); | |
| expect(records.get("deprecated-session-store-beta5-api")?.surfaces).toEqual( | |
| expect.arrayContaining([ | |
| "openclaw package root loadSessionStore", | |
| "openclaw package root saveSessionStore", | |
| ]), | |
| ); | |
| }); | |
| it("keeps the removed context-engine host-param default as a migration tombstone", () => { | |
| const record = listPluginCompatRecords().find( | |
| (candidate) => candidate.code === "context-engine-legacy-host-param-default", | |
| ); | |
| expect(record).toMatchObject({ | |
| status: "removed", | |
| replacement: | |
| "`ContextEngineInfo.acceptedHostParams` for restricted projection; omitted declarations receive full host params", | |
| }); | |
| expect(record?.removeAfter).toBeUndefined(); | |
| }); | |
| it("keeps the removed deactivate hook alias as a migration tombstone", () => { | |
| const record = listPluginCompatRecords().find( | |
| (candidate) => candidate.code === "legacy-deactivate-hook-alias", | |
| ); | |
| expect(record).toMatchObject({ | |
| status: "removed", | |
| replacement: "`gateway_stop` hook", | |
| }); | |
| expect(record?.removeAfter).toBeUndefined(); | |
| }); | |
| it("keeps the removed subagent spawning hook as a migration tombstone", () => { | |
| const record = listPluginCompatRecords().find( | |
| (candidate) => candidate.code === "legacy-subagent-spawning-hook", | |
| ); | |
| expect(record).toMatchObject({ | |
| status: "removed", | |
| replacement: | |
| "`subagent_spawned` for post-launch observation; core session-binding adapters for thread routing", | |
| }); | |
| expect(record?.removeAfter).toBeUndefined(); | |
| }); | |
| it("keeps the removed embedded Pi aliases as a migration tombstone", () => { | |
| const record = listPluginCompatRecords().find( | |
| (candidate) => candidate.code === "embedded-pi-agent-sdk-aliases", | |
| ); | |
| expect(record).toMatchObject({ | |
| status: "removed", | |
| replacement: "`runEmbeddedAgent` and `EmbeddedAgent*` SDK/runtime names", | |
| }); | |
| expect(record?.removeAfter).toBeUndefined(); | |
| }); | |
| it("keeps shipped channel setup exports until published packages migrate", () => { | |
| const record = listPluginCompatRecords().find( | |
| (candidate) => candidate.code === "plugin-sdk-shipped-channel-setup-exports", | |
| ); | |
| expect(record).toMatchObject({ | |
| status: "deprecated", | |
| replacement: | |
| "retain until supported published packages migrate to plugin-owned config schemas plus generic `openclaw/plugin-sdk/channel-config-schema` and `openclaw/plugin-sdk/setup-runtime` primitives", | |
| }); | |
| expect(record?.removeAfter).toBeUndefined(); | |
| }); | |
| it("keeps the removed memory embedding registrar as a migration tombstone", () => { | |
| const record = listPluginCompatRecords().find( | |
| (candidate) => candidate.code === "deprecated-memory-embedding-provider-api", | |
| ); | |
| expect(record).toMatchObject({ | |
| status: "removed", | |
| replacement: "`api.registerEmbeddingProvider(...)` and `contracts.embeddingProviders`", | |
| }); | |
| expect(record?.removeAfter).toBeUndefined(); | |
| }); | |
| it("keeps removed WhatsApp inbound aliases as migration tombstones", () => { | |
| const records = new Map(listPluginCompatRecords().map((record) => [record.code, record])); | |
| for (const code of [ | |
| "whatsapp-web-inbound-flat-message-aliases", | |
| "whatsapp-web-inbound-admission-top-level-fields", | |
| ] as const) { | |
| expect(records.get(code)).toMatchObject({ | |
| status: "removed", | |
| releaseNote: expect.stringMatching(/\S/u), | |
| }); | |
| expect(records.get(code)?.removeAfter).toBeUndefined(); | |
| } | |
| }); | |
| it("keeps removed channel target compatibility as migration tombstones", () => { | |
| const records = new Map(listPluginCompatRecords().map((record) => [record.code, record])); | |
| for (const code of [ | |
| "channel-explicit-target-parser", | |
| "channel-messaging-targets-subpath", | |
| ] as const) { | |
| expect(records.get(code)).toMatchObject({ | |
| status: "removed", | |
| releaseNote: expect.stringMatching(/\S/u), | |
| }); | |
| expect(records.get(code)?.removeAfter).toBeUndefined(); | |
| } | |
| }); | |
| }); | |