diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9e3eed3..4447c13e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,9 @@ on: push: branches: - main + schedule: + - cron: "17 4 * * *" + workflow_dispatch: permissions: contents: read @@ -25,8 +28,50 @@ jobs: node-version: "24" cache: npm + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - run: npm ci + + - run: npm run check + + - run: npm test + + - name: Verify Bun can load the plugin + run: bun -e "await import('./src/index.js')" + + opencode-peer-compat: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + plugin-version: ["1.4.0", "latest"] + + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + with: + node-version: "24" + cache: npm + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - run: npm ci + - name: Install OpenCode plugin compatibility target + shell: bash + run: npm install --no-save --package-lock=false "@opencode-ai/plugin@${{ matrix.plugin-version }}" + + - name: Show tested OpenCode plugin version + run: node -p "require('./node_modules/@opencode-ai/plugin/package.json').version" + - run: npm run check - run: npm test + + - name: Verify Bun can load with this OpenCode plugin + run: bun -e "await import('./src/index.js')" diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a56ec3..792ecc5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.5.22 + +- Hardened compatibility with current OpenCode 1.18.15 while preserving the existing `>=1.4.0` peer range. +- Handled loop commands now also set `output.noReply = true`; OpenCode 1.18.x safely ignores the unknown field, while hosts that add the proposed `noReply` hook support can skip the acknowledgement model turn automatically. +- Added Bun runtime loading coverage so CI exercises the runtime OpenCode actually uses to load plugins, not only Node syntax/tests. +- Added explicit minimum-peer coverage against `@opencode-ai/plugin@1.4.0` and scheduled testing against the latest published OpenCode plugin package. +- Kept the v0.5.21 server-plugin acknowledgement fallback for current OpenCode versions where `command.execute.before` cannot cancel the prompt turn. + ## 0.5.21 - Verified server-plugin compatibility against OpenCode 1.18.15 and updated the development plugin dependency accordingly. diff --git a/README.md b/README.md index bba6783a..b3f172fb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ v0.5.11 includes a referenced heartbeat scheduler. This is important in OpenCode ## Current status -**v0.5.21 targets current OpenCode 1.18.x compatibility and safer releases.** Server-plugin control commands keep their locked-down acknowledgement prompt instead of creating an empty command message, `/compact` prefers the current `session.compact` TUI command, and CI now covers Ubuntu and Windows before publishing. **v0.5.20 fixes Windows TUI state writes.** Session job state is written through the OS temp directory with rename plus copy/unlink fallback and short retries, so antivirus locks and OpenCode snapshots no longer drop `/loop` jobs with `EPERM` on rename. **v0.5.19** hardens Goal Mode, package updates, and the background daemon: package installs are pinned to the installed version so OpenCode cannot keep loading an older cached release, scheduler-created goal messages no longer self-interrupt on delayed updates, finite daemon failures return nonzero, model/agent selection is supported, Windows scheduled tasks use a short launcher that stays below the `/TR` limit, and asynchronous release verification is reliable under load. +**v0.5.22 adds forward-compatible OpenCode command handling plus Bun and peer-range compatibility CI.** **v0.5.21 targets current OpenCode 1.18.x compatibility and safer releases.** Server-plugin control commands keep their locked-down acknowledgement prompt instead of creating an empty command message, `/compact` prefers the current `session.compact` TUI command, and CI now covers Ubuntu and Windows before publishing. **v0.5.20 fixes Windows TUI state writes.** Session job state is written through the OS temp directory with rename plus copy/unlink fallback and short retries, so antivirus locks and OpenCode snapshots no longer drop `/loop` jobs with `EPERM` on rename. **v0.5.19** hardens Goal Mode, package updates, and the background daemon: package installs are pinned to the installed version so OpenCode cannot keep loading an older cached release, scheduler-created goal messages no longer self-interrupt on delayed updates, finite daemon failures return nonzero, model/agent selection is supported, Windows scheduled tasks use a short launcher that stays below the `/TR` limit, and asynchronous release verification is reliable under load. The known update-related symptoms from older builds are fixed: diff --git a/package-lock.json b/package-lock.json index 09682528..b5f2871e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bybrawe/opencode-loop", - "version": "0.5.21", + "version": "0.5.22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bybrawe/opencode-loop", - "version": "0.5.21", + "version": "0.5.22", "license": "MIT", "bin": { "opencode-loop": "scripts/install-node.mjs", diff --git a/package.json b/package.json index 94a448c4..0635f110 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bybrawe/opencode-loop", - "version": "0.5.21", + "version": "0.5.22", "description": "Claude Code/Codex style /loop and experimental goal mode for OpenCode: heartbeat scheduler, idle-safe loops, scheduled commands, compact scheduling, verification, checkpoints, and persistent coding goals.", "type": "module", "main": "src/index.js", diff --git a/scripts/smoke-test.mjs b/scripts/smoke-test.mjs index 5d651f0f..59e781cd 100644 --- a/scripts/smoke-test.mjs +++ b/scripts/smoke-test.mjs @@ -94,6 +94,7 @@ try { }, output) assert.equal(output.parts.length, 1, "a locally handled slash command must keep a valid acknowledgement prompt") assert.equal(output.parts[0].text, "original command body") + assert.equal(output.noReply, true, "handled commands should request noReply for compatible OpenCode hosts") await hooks["command.execute.before"]({ command: "loop-now", sessionID, arguments: "goal" }, { parts: [] }) assert.equal( diff --git a/src/index.js b/src/index.js index 2c4a304a..6b744506 100644 --- a/src/index.js +++ b/src/index.js @@ -2220,9 +2220,10 @@ async function handleCommand(directory, client, input, fallbackName, fallbackArg if (isLoopCommandName(name)) guardLoopOwnedUserMessage(sessionID) const handled = () => { - // OpenCode server plugins cannot currently cancel the command prompt turn. - // Keep the command markdown acknowledgement intact so opencode-loop-local - // receives a valid, tool-denied message instead of an empty parts array. + // OpenCode 1.18.x ignores unknown hook output fields, while proposed/newer + // hosts can honor noReply to skip the otherwise unavoidable model turn. + // Keep acknowledgement parts intact as the compatibility fallback. + if (output && typeof output === "object") output.noReply = true return true }