From 25b673fbb707471636c5f6951cdba85e2e3fdb39 Mon Sep 17 00:00:00 2001 From: Ralph Chang Date: Mon, 27 Apr 2026 18:54:14 +0800 Subject: [PATCH] test: add opencode plugin compatibility checks --- .github/workflows/compatibility.yml | 34 +++++++++++++ package.json | 5 +- tests/plugin-capability.test.ts | 75 +++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/compatibility.yml create mode 100644 tests/plugin-capability.test.ts diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml new file mode 100644 index 0000000..7ace6ec --- /dev/null +++ b/.github/workflows/compatibility.yml @@ -0,0 +1,34 @@ +name: compatibility + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "0 9 * * 1" + +jobs: + locked: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - run: npm run typecheck + - run: npm test + + opencode-latest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - run: npm install --no-save @opencode-ai/plugin@latest + - run: npm run typecheck + - run: npm test \ No newline at end of file diff --git a/package.json b/package.json index 1034e5d..d1f4d7c 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "scripts": { "build": "node -e \"console.log('No build step required: OpenCode loads index.ts directly')\"", "typecheck": "tsc --noEmit", - "test": "node --test --experimental-strip-types tests/*.test.ts" + "test": "node --test --experimental-strip-types tests/*.test.ts", + "check:compat": "npm install --no-save @opencode-ai/plugin@latest && npm run typecheck && npm test" }, "keywords": [ "opencode", @@ -37,7 +38,7 @@ }, "homepage": "https://github.com/sdwolf4103/opencode-working-memory#readme", "peerDependencies": { - "@opencode-ai/plugin": "^1.2.0" + "@opencode-ai/plugin": ">=1.2.0 <2.0.0" }, "devDependencies": { "@types/node": "^24.3.0", diff --git a/tests/plugin-capability.test.ts b/tests/plugin-capability.test.ts new file mode 100644 index 0000000..78cdc6e --- /dev/null +++ b/tests/plugin-capability.test.ts @@ -0,0 +1,75 @@ +/** + * Plugin capability test. + * + * This is the loud alarm for OpenCode plugin API compatibility. + * It fails tests, not user runtime. + * + * If any required hook key disappears from MemoryV2Plugin output, + * this test will catch it before release. + */ + +import { describe, it } from "node:test"; +import assert from "node:assert"; +import { MemoryV2Plugin } from "../src/plugin.ts"; + +const REQUIRED_PLUGIN_HOOKS = [ + "experimental.chat.system.transform", + "tool.execute.after", + "experimental.session.compacting", + "event", +] as const; + +describe("plugin capability", () => { + it("MemoryV2Plugin has all required hooks", async () => { + // Create minimal mock client + const mockClient = { + session: { + get: async () => ({ data: { parentID: null } }), + }, + }; + + // Create minimal mock input + const mockInput = { + directory: "/tmp/test-workspace", + client: mockClient, + }; + + // Instantiate plugin + const plugin = await MemoryV2Plugin(mockInput); + + // Assert all required hooks exist and are functions + for (const hook of REQUIRED_PLUGIN_HOOKS) { + assert( + hook in plugin, + `Missing required hook: ${hook}` + ); + assert( + typeof plugin[hook] === "function", + `Hook ${hook} is not a function` + ); + } + }); + + it("MemoryV2Plugin returns exactly the expected hook keys", async () => { + const mockClient = { + session: { + get: async () => ({ data: { parentID: null } }), + }, + }; + + const mockInput = { + directory: "/tmp/test-workspace", + client: mockClient, + }; + + const plugin = await MemoryV2Plugin(mockInput); + const keys = Object.keys(plugin).sort(); + const expected = [...REQUIRED_PLUGIN_HOOKS].sort(); + + assert.deepStrictEqual( + keys, + expected, + `Plugin returned unexpected keys: ${keys.join(", ")}` + ); + }); +}); \ No newline at end of file