From edbe444901a4a1ad999cd9bcd9ac436287a52bd9 Mon Sep 17 00:00:00 2001 From: HeftyKoo Date: Thu, 29 Oct 2026 10:02:43 +0800 Subject: [PATCH] fix(ci): serialize host startup and upgrade to node 24 --- .github/workflows/ci.yml | 22 ++++++------ .github/workflows/release.yml | 10 +++--- AMO-BUILD.md | 4 +-- docs/development.md | 3 +- .../ci-host-readiness-2026-10-29.md | 30 ++++++++++++++++ packages/terminal-host/src/cli.ts | 2 +- .../src/host.integration.test.ts | 36 +++++++++++++++++++ 7 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 docs/verification/ci-host-readiness-2026-10-29.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0bb27d..cacee95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,15 +7,15 @@ on: jobs: verify: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 + - uses: actions/checkout@v7.0.1 + - uses: pnpm/action-setup@v6.1.0 with: version: 11.5.0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7.1.0 with: - node-version: 22.19.0 + node-version: 24.22.2 cache: pnpm - run: pnpm install --frozen-lockfile - name: Install shells for installer tests @@ -23,23 +23,23 @@ jobs: sudo apt-get update sudo apt-get install -y --no-install-recommends zsh fish - run: pnpm release:audit - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7.0.2 with: name: agentonweb-${{ github.sha }} path: release/ dsh-latest: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: DSH_TEST_PREFIX: /tmp/agentonweb-dsh-latest steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 + - uses: actions/checkout@v7.0.1 + - uses: pnpm/action-setup@v6.1.0 with: version: 11.5.0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7.1.0 with: - node-version: 22.19.0 + node-version: 24.22.2 cache: pnpm - run: pnpm install --frozen-lockfile - name: Build extension and pack the actual DSH plugin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de98e1d..2680ce9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,19 +16,19 @@ permissions: jobs: release: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: RELEASE_TAG: ${{ inputs.tag || github.ref_name }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.1 with: ref: ${{ inputs.tag || github.ref }} - - uses: pnpm/action-setup@v4 + - uses: pnpm/action-setup@v6.1.0 with: version: 11.5.0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v7.1.0 with: - node-version: 22.19.0 + node-version: 24.22.2 cache: pnpm registry-url: https://registry.npmjs.org - run: pnpm install --frozen-lockfile diff --git a/AMO-BUILD.md b/AMO-BUILD.md index 30d96b7..863fcde 100644 --- a/AMO-BUILD.md +++ b/AMO-BUILD.md @@ -1,7 +1,7 @@ # Reproduce the Firefox extension -This source archive contains the complete tracked source for AgentOnWeb 0.4.0. -Use Node.js 22.19.0 and pnpm 11.5.0 on Linux or macOS. No API keys, local +This source archive contains the complete tracked source for AgentOnWeb. +Use Node.js 24.22.2 and pnpm 11.5.0 on Linux or macOS. No API keys, local terminal service, model credentials or private signing configuration are needed. ```sh diff --git a/docs/development.md b/docs/development.md index 62d309f..9e1f762 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,6 +1,7 @@ # Development -Use Node.js 22.19+ and pnpm 11.5.0. +Use Node.js 24.22.2 and pnpm 11.5.0 for builds and CI. The installed terminal +host continues to support Node.js 22.19+. ```sh git clone https://github.com/HeftyKoo/AgentOnWeb.git diff --git a/docs/verification/ci-host-readiness-2026-10-29.md b/docs/verification/ci-host-readiness-2026-10-29.md new file mode 100644 index 0000000..0d433a8 --- /dev/null +++ b/docs/verification/ci-host-readiness-2026-10-29.md @@ -0,0 +1,30 @@ +# Host startup readiness and CI runtime + +The previous CI run 40326913684 failed while parsing the first terminal registry +response. Extension release run 40802248815 initially failed at the same stage +of the authorized-browser revocation test. Both tests first open the one-time +launch URL and reuse the cookies it returns. + +The host printed that URL before its initial `saveEndpoint()` completed. +Opening the URL immediately started another save to the same `endpoint.tmp`. +One rename could remove the other request's temporary file, causing `/launch` +to return HTTP 500 without cookies. The next protected API request returned +HTTP 403 with an empty body, producing `Unexpected end of JSON input`. + +The regression test delays the first two endpoint writes in an isolated child +host. Before the fix, the launch request returned HTTP 500 instead of 200. +After moving the initial endpoint save before the readiness log, the launch +returns HTTP 200 with its admin cookie, and both protected JSON APIs respond +successfully. All 27 host integration tests and the complete release audit +passed locally: 428 tests passed and two optional tests were skipped. + +CI and Release now use Node.js 24.22.2 on Ubuntu 24.04. Their actions are +checkout 7.0.1, setup-node 7.1.0, pnpm/action-setup 6.1.0 and upload-artifact +7.0.2; each upstream action manifest declares `runs.using: node24`. Pinning the +runner avoids the `ubuntu-latest` Ubuntu 26 migration notice. The terminal +runtime minimum remains Node.js 22.19. + +The previously created `ext-v0.4.2` tag remains unchanged. Its second Release +attempt succeeded, and Chrome/Firefox 0.4.2 were submitted from its audited +packages. This follow-up changes future builds and CI; it does not republish +the existing terminal-host 0.4.3 npm package. diff --git a/packages/terminal-host/src/cli.ts b/packages/terminal-host/src/cli.ts index 88a943a..34e8836 100644 --- a/packages/terminal-host/src/cli.ts +++ b/packages/terminal-host/src/cli.ts @@ -572,11 +572,11 @@ authority.onRevoke(() => { for (const socket of sockets.clients) socket.close(4401, "Authorization revoked"); connector.refreshSurfaces(); }); +await saveEndpoint(); console.log( `${terminalUi().banner('LOCAL SHELL')}\nExecutable: ${executable}\nInitial directory: ${cwd}\nConnector: ${connector.port}\nOpen once: ${origin}/launch?token=${launchToken}`, ); printStatus('info', 'Approve your browser through the private setup page.'); -await saveEndpoint(); const stopUpdateChecks = updates.start(status => { printStatus('warn', `AgentOnWeb ${status.latest} is available (running ${VERSION}). Run aow update after closing terminal sessions.`); }); diff --git a/packages/terminal-host/src/host.integration.test.ts b/packages/terminal-host/src/host.integration.test.ts index e3ec39d..14d1117 100644 --- a/packages/terminal-host/src/host.integration.test.ts +++ b/packages/terminal-host/src/host.integration.test.ts @@ -67,6 +67,42 @@ it('restricts update status to admins and maintenance to the local CLI, preservi await expect.poll(async () => (await (await control()).json()).activeTerminals).toBe(0); expect((await control({ action: 'prepare' })).status).toBe(200); }); +it("persists its initial endpoint before publishing the one-time launch URL", async () => { + directory = await mkdtemp(join(tmpdir(), "aow-startup-readiness-test-")); + const guard = join(directory, "slow-endpoint-writes.mjs"); + await writeFile(guard, ` + import fs from "node:fs"; + import { syncBuiltinESMExports } from "node:module"; + const writeFile = fs.promises.writeFile; + let endpointWrites = 0; + fs.promises.writeFile = async (path, ...args) => { + const delay = String(path).endsWith("endpoint.tmp") ? (++endpointWrites === 1 ? 100 : 250) : 0; + await writeFile(path, ...args); + if (delay) await new Promise(resolveDelay => setTimeout(resolveDelay, delay)); + }; + syncBuiltinESMExports(); + `); + host = spawn(process.execPath, ["--import", guard, resolve("packages/terminal-host/lib/cli.js"), "terminal"], { + env: { ...process.env, HOME: directory, SHELL: "/bin/sh", ENV: undefined, BASH_ENV: undefined, ZDOTDIR: undefined }, + stdio: ["pipe", "pipe", "pipe"], + }); + let output = ""; + host.stdout!.on("data", chunk => { output += chunk; }); + await expect.poll(() => output.includes("Open once:"), { timeout: 10000 }).toBe(true); + const launchUrl = /Open once: (http:\/\/[^\s]+)/u.exec(output)![1]!; + const origin = new URL(launchUrl).origin; + const launch = await fetch(launchUrl); + expect(launch.status, await launch.text()).toBe(200); + const cookies = launch.headers.getSetCookie().map(value => value.split(";")[0]!).join("; "); + expect(cookies).toContain("aow_admin_"); + const headers = { Cookie: cookies, "X-AgentOnWeb-Terminal": "1", Origin: origin }; + for (const path of ["/api/terminals", "/api/connections"]) { + const response = await fetch(origin + path, { headers }); + expect(response.status).toBe(200); + expect(await response.json()).toBeTruthy(); + } +}); + it("preserves Unicode terminal names split across HTTP body chunks and publishes terminal registry changes", async () => { directory = await mkdtemp(join(tmpdir(), "aow-unicode-test-")); host = spawn(process.execPath, [resolve("packages/terminal-host/lib/cli.js"), "terminal"], {