diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4447c13e..1b81aefc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,13 @@ jobs: - name: Verify Bun can load the plugin run: bun -e "await import('./src/index.js')" + # Issue #2 happened in the installer-created .ts plugin shape, not the source .js file. + - name: "Regression #2 - verify local .ts plugin loads in Bun" + run: | + node -e "require('node:fs').copyFileSync('src/index.js', 'src/__opencode_loop_local_ci.ts')" + bun -e "await import('./src/__opencode_loop_local_ci.ts')" + node -e "require('node:fs').rmSync('src/__opencode_loop_local_ci.ts', { force: true })" + opencode-peer-compat: runs-on: ubuntu-latest strategy: @@ -75,3 +82,9 @@ jobs: - name: Verify Bun can load with this OpenCode plugin run: bun -e "await import('./src/index.js')" + + - name: "Regression #2 - verify local .ts plugin loads with this OpenCode plugin" + run: | + node -e "require('node:fs').copyFileSync('src/index.js', 'src/__opencode_loop_local_ci.ts')" + bun -e "await import('./src/__opencode_loop_local_ci.ts')" + node -e "require('node:fs').rmSync('src/__opencode_loop_local_ci.ts', { force: true })" diff --git a/scripts/smoke-test.mjs b/scripts/smoke-test.mjs index 59e781cd..f45bffce 100644 --- a/scripts/smoke-test.mjs +++ b/scripts/smoke-test.mjs @@ -122,6 +122,34 @@ try { assert.equal(completedState.jobs[0].paused, true) assert.equal(completedState.jobs[0].enabled, false) + await hooks.event({ event: { type: "session.idle", properties: { sessionID } } }) + await hooks["command.execute.before"]({ command: "loop-clear", sessionID, arguments: "" }, { parts: [] }) + + const promptCountBeforeAutoGoal = prompts.length + await hooks["command.execute.before"]({ + command: "loop-goal", + sessionID, + arguments: "--no-now --check \"node -e process.exitCode=0\" --complete-when-checks-pass make the configured checks pass", + }, { parts: [] }) + await hooks["command.execute.before"]({ command: "loop-now", sessionID, arguments: "goal" }, { parts: [] }) + assert.equal( + await waitFor(() => prompts.length === promptCountBeforeAutoGoal + 1), + true, + "a Goal Mode check-gated run must start when forced", + ) + await new Promise((resolve) => setTimeout(resolve, 25)) + await hooks.event({ event: { type: "session.idle", properties: { sessionID } } }) + let autoCompletedState + for (let attempt = 0; attempt < 400; attempt++) { + autoCompletedState = JSON.parse(await fs.readFile(stateFile, "utf8")) + if (autoCompletedState.jobs[0]?.goalStatus === "completed") break + await new Promise((resolve) => setTimeout(resolve, 10)) + } + assert.equal(autoCompletedState.jobs[0].goalStatus, "completed", "--complete-when-checks-pass must complete the goal after successful configured checks") + assert.equal(autoCompletedState.jobs[0].paused, true) + assert.equal(autoCompletedState.jobs[0].enabled, false) + assert.ok(autoCompletedState.jobs[0].lastGoalChecks?.every((item) => item.code === 0), "auto-completed Goal Mode must persist passing check evidence") + await hooks["command.execute.before"]({ command: "loop-clear", sessionID, arguments: "" }, { parts: [] }) const promptCountBeforeBackgroundTool = prompts.length