diff --git a/CHANGELOG.md b/CHANGELOG.md index 95039fd9..94edd1a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ new version heading in the same commit. ## [Unreleased] +## [0.446.1] - 2026-09-17 +### Fixed +- **The pause test raced the launcher and blocked the deploy.** `session-pause-test.cjs`'s HTTP section + asserted the row was `running` after unpause, but `launchAgentRuntime` hands the real launch to a + `setImmediate` whose `.catch` stamps the row `crashed` — and that deferred half does far more than the + stubbed `backend.spawn` (env files, skills, credentials). On a box where any of it throws, the status + flipped between the `await` and the read: instawp failed the assertion, expresstech passed it, and + `make-live.sh` correctly refused to restart anything. The section stubs the deferred launch (it is about + the route and the status transition, not the launcher) and both status assertions now report the value + they actually found. + ## [0.446.0] - 2026-09-17 ### Added - **Pause a session.** A new session status, `paused`, that is neither live nor finished: pausing kills the diff --git a/package-lock.json b/package-lock.json index b5a21f7a..fecf137a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "agent-os", - "version": "0.446.0", + "version": "0.446.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "agent-os", - "version": "0.446.0", + "version": "0.446.1", "license": "MIT", "bin": { "agent-os": "bin/agent-os" diff --git a/package.json b/package.json index 270b5902..62379607 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agent-os", - "version": "0.446.0", + "version": "0.446.1", "description": "A generic, governed operating system for running autonomous agents safely across brands. Ships with a local web console.", "license": "MIT", "type": "commonjs", diff --git a/scripts/session-pause-test.cjs b/scripts/session-pause-test.cjs index 1a037a95..0f853510 100644 --- a/scripts/session-pause-test.cjs +++ b/scripts/session-pause-test.cjs @@ -233,6 +233,13 @@ console.log('\n\x1b[1m10) end to end over real HTTP — the routes, the gate and htm.backend.spawn = (_s, o) => { live.add(o.tmuxName); }; htm.backend.capturePane = () => ''; htm.backend.hasClient = () => false; + // Neutralise the DEFERRED half of a launch. `launchAgentRuntime` stamps `launching` synchronously and + // hands the real work to a setImmediate whose `.catch` stamps the row `crashed` — and that work does far + // more than `backend.spawn` (env files, skills, credentials), so on a box where any of it throws the row + // flips out from under the assertion below between the `await` and the read. Live: instawp failed + // `the row is running again` on exactly that race while expresstech passed, which is the worst shape a + // test can have. This section is about the ROUTE and the status transition; the launcher has its own. + htm.launchAgentRuntimeNow = async () => {}; const post = (u, cookie) => fetch(base + u, { method: 'POST', headers: { 'content-type': 'application/json', ...(cookie ? { cookie } : {}) }, body: '{}' }); @@ -250,7 +257,8 @@ console.log('\n\x1b[1m10) end to end over real HTTP — the routes, the gate and const paused = await post(`/api/sessions/${sid}/pause`, cookie).then((r) => r.json()); assert(paused.ok === true, 'an authenticated owner can pause it over HTTP', paused); - assert(haos.db.prepare('SELECT status FROM term_sessions WHERE id = ?').get(sid).status === 'paused', 'the row is paused'); + const statusOf = () => haos.db.prepare('SELECT status FROM term_sessions WHERE id = ?').get(sid).status; + assert(statusOf() === 'paused', 'the row is paused', statusOf()); // The browser terminal must be refused while paused — this is the "readable, never usable" half. const attach = await fetch(base + `/api/sessions/${sid}/attach`, { headers: { cookie } }); @@ -264,7 +272,7 @@ console.log('\n\x1b[1m10) end to end over real HTTP — the routes, the gate and const back = await post(`/api/sessions/${sid}/unpause`, cookie).then((r) => r.json()); assert(back.ok === true, 'unpause succeeds over HTTP', back); - assert(haos.db.prepare('SELECT status FROM term_sessions WHERE id = ?').get(sid).status === 'running', 'and the row is running again'); + assert(statusOf() === 'running', 'and the row is running again', statusOf()); server.close(); try { registry.stopAll(); } catch { /* best effort */ }