From 0b13ddf582487c7280ebeb3364a19faa6ab03f70 Mon Sep 17 00:00:00 2001 From: deepagent-ai Date: Sat, 1 Aug 2026 10:27:38 +0800 Subject: [PATCH 1/2] fix(desktop): externalize server bundle from renderer build --- .github/workflows/desktop-build.yml | 8 ++--- bun.lock | 3 +- packages/deepagent-code/script/build-node.ts | 8 ++++- packages/desktop/electron.vite.config.ts | 33 ++++++++--------- packages/desktop/package.json | 5 +-- .../desktop/scripts/audit-server-bundle.ts | 35 +++++++++++++++++++ 6 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 packages/desktop/scripts/audit-server-bundle.ts diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 7db7924a..74f35a64 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -116,16 +116,12 @@ jobs: p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - - name: Prebuild - working-directory: packages/desktop - env: - DEEPAGENT_CODE_CHANNEL: ${{ github.event_name == 'push' && 'prod' || (github.event.inputs.channel || 'prod') }} - run: bun run prebuild - + # bun run build invokes the package prebuild lifecycle before electron-vite. - name: Build renderer working-directory: packages/desktop env: DEEPAGENT_CODE_CHANNEL: ${{ github.event_name == 'push' && 'prod' || (github.event.inputs.channel || 'prod') }} + NODE_OPTIONS: --max-old-space-size=4096 run: bun run build - name: Package diff --git a/bun.lock b/bun.lock index 02af02fa..bbbb4deb 100644 --- a/bun.lock +++ b/bun.lock @@ -350,6 +350,7 @@ "version": "1.4.4", "dependencies": { "@deepagent-code/core": "workspace:*", + "@lydell/node-pty": "catalog:", "@zip.js/zip.js": "2.7.62", "effect": "catalog:", "electron-context-menu": "4.1.2", @@ -357,6 +358,7 @@ "electron-store": "^10", "electron-updater": "^6", "electron-window-state": "^5.0.3", + "jsonc-parser": "3.3.1", "marked": "^15", }, "devDependencies": { @@ -364,7 +366,6 @@ "@deepagent-code/app": "workspace:*", "@deepagent-code/ui": "workspace:*", "@jridgewell/trace-mapping": "0.3.31", - "@lydell/node-pty": "catalog:", "@playwright/test": "catalog:", "@sentry/solid": "catalog:", "@sentry/vite-plugin": "catalog:", diff --git a/packages/deepagent-code/script/build-node.ts b/packages/deepagent-code/script/build-node.ts index e5dbf12a..fe65391e 100755 --- a/packages/deepagent-code/script/build-node.ts +++ b/packages/deepagent-code/script/build-node.ts @@ -18,7 +18,7 @@ const result = await Bun.build({ outdir: "./dist/node", format: "esm", sourcemap: "linked", - external: ["jsonc-parser", "@lydell/node-pty"], + external: ["@lydell/node-pty", "jsonc-parser"], define: { DEEPAGENT_CODE_MODELS_DEV: generated.modelsData, DEEPAGENT_CODE_CHANNEL: `'${Script.channel}'`, @@ -43,6 +43,12 @@ const unsupportedBunAPIs = [...new Set(source.match(/\bBun\.[A-Za-z_$][A-Za-z0-9 if (unsupportedBunAPIs.length > 0) { throw new Error(`Node server bundle contains Bun-only runtime APIs: ${unsupportedBunAPIs.join(", ")}`) } +if (!source.includes('from "@lydell/node-pty"')) { + throw new Error("Node server bundle does not import the node-pty platform selector") +} +if (!source.includes('from "jsonc-parser"')) { + throw new Error("Node server bundle does not import the external jsonc-parser runtime dependency") +} await Bun.write( bundle, source diff --git a/packages/desktop/electron.vite.config.ts b/packages/desktop/electron.vite.config.ts index 287d2a15..9045594d 100644 --- a/packages/desktop/electron.vite.config.ts +++ b/packages/desktop/electron.vite.config.ts @@ -1,7 +1,7 @@ import { sentryVitePlugin } from "@sentry/vite-plugin" import { defineConfig } from "electron-vite" import appPlugin from "@deepagent-code/app/vite" -import * as fs from "node:fs/promises" +import { copyFile, cp, mkdir, readdir, rm } from "node:fs/promises" const DEEPAGENT_CODE_SERVER_DIST = "../deepagent-code/dist/node" const DOMAIN_PACKS_DIST = "../domain-packs" @@ -13,8 +13,6 @@ const channel = (() => { return "dev" })() -const nodePtyPkg = `@lydell/node-pty-${process.platform}-${process.arch}` - const sentry = process.env.SENTRY_AUTH_TOKEN && process.env.SENTRY_ORG && process.env.SENTRY_PROJECT ? sentryVitePlugin({ @@ -32,7 +30,7 @@ const sentry = }) : false -export default defineConfig({ +export default defineConfig(({ command }) => ({ main: { define: { "import.meta.env.DEEPAGENT_CODE_CHANNEL": JSON.stringify(channel), @@ -41,32 +39,29 @@ export default defineConfig({ rollupOptions: { input: { index: "src/main/index.ts", sidecar: "src/main/sidecar.ts" }, }, - externalizeDeps: { include: [nodePtyPkg] }, + externalizeDeps: { include: ["@lydell/node-pty"] }, }, plugins: [ - { - name: "deepagent-code:node-pty-narrower", - enforce: "pre", - resolveId(s) { - if (s === "@lydell/node-pty") return nodePtyPkg - }, - }, { name: "deepagent-code:virtual-server-module", enforce: "pre", resolveId(id) { - if (id === "virtual:deepagent-code-server") return this.resolve(`${DEEPAGENT_CODE_SERVER_DIST}/node.js`) + if (id !== "virtual:deepagent-code-server") return + if (command === "build") return { id: "./chunks/node.js", external: true } + return this.resolve(`${DEEPAGENT_CODE_SERVER_DIST}/node.js`) }, }, { name: "deepagent-code:copy-server-assets", async writeBundle() { - for (const l of await fs.readdir(DEEPAGENT_CODE_SERVER_DIST)) { - if (!l.endsWith(".wasm")) continue - await fs.writeFile(`./out/main/chunks/${l}`, await fs.readFile(`${DEEPAGENT_CODE_SERVER_DIST}/${l}`)) + await mkdir("./out/main/chunks", { recursive: true }) + for (const file of await readdir(DEEPAGENT_CODE_SERVER_DIST)) { + if (!file.endsWith(".wasm") && (command !== "build" || (file !== "node.js" && file !== "node.js.map"))) + continue + await copyFile(`${DEEPAGENT_CODE_SERVER_DIST}/${file}`, `./out/main/chunks/${file}`) } - await fs.rm("./out/main/domain-packs", { recursive: true, force: true }) - await fs.cp(DOMAIN_PACKS_DIST, "./out/main/domain-packs", { recursive: true }) + await rm("./out/main/domain-packs", { recursive: true, force: true }) + await cp(DOMAIN_PACKS_DIST, "./out/main/domain-packs", { recursive: true }) }, }, ], @@ -95,4 +90,4 @@ export default defineConfig({ }, }, }, -}) +})) diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 5cacf69f..9c7497bb 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -14,7 +14,7 @@ "predev": "bun ./scripts/predev.ts", "dev": "electron-vite dev", "prebuild": "bun ./scripts/prebuild.ts", - "build": "electron-vite build", + "build": "electron-vite build && bun ./scripts/audit-server-bundle.ts", "preview": "electron-vite preview", "test": "bun test ./src", "test:ci": "mkdir -p .artifacts/unit && bun test ./src --reporter=junit --reporter-outfile=.artifacts/unit/junit.xml", @@ -37,6 +37,7 @@ "main": "./out/main/index.js", "dependencies": { "@deepagent-code/core": "workspace:*", + "@lydell/node-pty": "catalog:", "@zip.js/zip.js": "2.7.62", "effect": "catalog:", "electron-context-menu": "4.1.2", @@ -44,11 +45,11 @@ "electron-store": "^10", "electron-updater": "^6", "electron-window-state": "^5.0.3", + "jsonc-parser": "3.3.1", "marked": "^15" }, "devDependencies": { "@actions/artifact": "4.0.0", - "@lydell/node-pty": "catalog:", "@deepagent-code/app": "workspace:*", "@deepagent-code/ui": "workspace:*", "@jridgewell/trace-mapping": "0.3.31", diff --git a/packages/desktop/scripts/audit-server-bundle.ts b/packages/desktop/scripts/audit-server-bundle.ts new file mode 100644 index 00000000..da8e9043 --- /dev/null +++ b/packages/desktop/scripts/audit-server-bundle.ts @@ -0,0 +1,35 @@ +#!/usr/bin/env bun + +import { strict as assert } from "node:assert" +import { readdir } from "node:fs/promises" +import path from "node:path" + +const chunks = path.resolve("out/main/chunks") +const sidecar = await Bun.file(path.resolve("out/main/sidecar.js")).text() +const server = Bun.file(path.join(chunks, "node.js")) +const sourceMap = Bun.file(path.join(chunks, "node.js.map")) +const files = await readdir(chunks) + +assert.match(sidecar, /import\(["']\.\/chunks\/node\.js["']\)/, "sidecar must load the external server bundle") +assert.equal(await server.exists(), true, "external server bundle is missing") +assert.equal(await sourceMap.exists(), true, "external server source map is missing") +assert.deepEqual( + files.filter((file) => /^node-.+\.js$/.test(file)), + [], + "Rollup must not emit a transformed copy of the server bundle", +) + +const source = await server.text() +assert.match(source, /sourceMappingURL=node\.js\.map/, "external server bundle is not linked to its source map") +assert.equal( + source.includes('from "@lydell/node-pty"'), + true, + "external server bundle does not use the packaged node-pty platform selector", +) +assert.equal( + source.includes('from "jsonc-parser"') || source.includes("from 'jsonc-parser'"), + true, + "external server bundle does not declare its packaged jsonc-parser dependency", +) + +console.log(`External server bundle verified: ${Math.ceil(server.size / 1024 / 1024)} MiB`) From 647b66a33786c59e4b079c66b4544d3d4aaa3199 Mon Sep 17 00:00:00 2001 From: deepagent-ai Date: Sat, 1 Aug 2026 16:44:50 +0800 Subject: [PATCH 2/2] fix(desktop): restore packaged app startup --- .github/workflows/desktop-build.yml | 8 ++++ bun.lock | 2 +- packages/core/src/deepagent/atomic-write.ts | 26 ++++++++++++- packages/core/src/deepagent/document-store.ts | 36 +++++++++++++++++- .../src/deepagent/durable-knowledge-store.ts | Bin 18479 -> 18387 bytes .../test/deepagent/document-store.test.ts | 20 ++++++++++ packages/desktop/electron-builder.config.ts | 1 + packages/desktop/electron.vite.config.ts | 2 +- packages/desktop/package.json | 2 +- .../desktop/scripts/audit-server-bundle.ts | 21 +++++++++- packages/desktop/scripts/subagents-smoke.ts | 24 ++++++++---- 11 files changed, 128 insertions(+), 14 deletions(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 74f35a64..96a877ee 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -142,6 +142,14 @@ jobs: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: npx electron-builder ${{ matrix.platform_flag }} --publish never --config electron-builder.config.ts + - name: Smoke test packaged macOS app + if: matrix.group == 'mac' + working-directory: packages/desktop + run: | + executable=$(find dist/mac-arm64 -maxdepth 4 -type f -path '*/Contents/MacOS/DeepAgent Code*' -perm +111 -print -quit) + test -n "$executable" + DEEPAGENT_CODE_DESKTOP_EXECUTABLE="$executable" bun run test:subagents-cold-start + - name: Upload package artifacts uses: actions/upload-artifact@v4 with: diff --git a/bun.lock b/bun.lock index bbbb4deb..20cbf817 100644 --- a/bun.lock +++ b/bun.lock @@ -349,7 +349,6 @@ "name": "@deepagent-code/desktop", "version": "1.4.4", "dependencies": { - "@deepagent-code/core": "workspace:*", "@lydell/node-pty": "catalog:", "@zip.js/zip.js": "2.7.62", "effect": "catalog:", @@ -364,6 +363,7 @@ "devDependencies": { "@actions/artifact": "4.0.0", "@deepagent-code/app": "workspace:*", + "@deepagent-code/core": "workspace:*", "@deepagent-code/ui": "workspace:*", "@jridgewell/trace-mapping": "0.3.31", "@playwright/test": "catalog:", diff --git a/packages/core/src/deepagent/atomic-write.ts b/packages/core/src/deepagent/atomic-write.ts index 861bf101..d038ebb9 100644 --- a/packages/core/src/deepagent/atomic-write.ts +++ b/packages/core/src/deepagent/atomic-write.ts @@ -1,4 +1,14 @@ -import { closeSync, fsyncSync, mkdirSync, openSync, renameSync, rmSync, writeSync } from "node:fs" +import { + closeSync, + fsyncSync, + linkSync, + mkdirSync, + openSync, + renameSync, + rmSync, + writeFileSync, + writeSync, +} from "node:fs" import { randomUUID } from "node:crypto" import path from "node:path" @@ -69,6 +79,20 @@ export const writeFileExclusive = (file: string, content: string): void => { } } +// Built-in domain-pack seeds are immutable packaged inputs and can be regenerated after a crash. +// Keep each visible file atomic, but avoid two fsyncs per seed during first-run corpus installation. +export const writeRecoverableFileExclusive = (file: string, content: string): void => { + const dir = path.dirname(file) + mkdirSync(dir, { recursive: true }) + const tmp = path.join(dir, `.${path.basename(file)}.seed-${process.pid}-${randomUUID()}`) + try { + writeFileSync(tmp, content, "utf8") + linkSync(tmp, file) + } finally { + rmSync(tmp, { force: true }) + } +} + // Best-effort directory fsync so a rename/create is durable. Not all platforms/filesystems permit // opening a directory for fsync (Windows throws EPERM/EISDIR, some FUSE mounts reject it); a failure // here does not compromise the file body (already fsync'd) so it is intentionally swallowed. diff --git a/packages/core/src/deepagent/document-store.ts b/packages/core/src/deepagent/document-store.ts index 0376a683..1f9e9e45 100644 --- a/packages/core/src/deepagent/document-store.ts +++ b/packages/core/src/deepagent/document-store.ts @@ -1,7 +1,7 @@ import { mkdirSync, readdirSync, readFileSync, existsSync } from "node:fs" import { createHash } from "node:crypto" import path from "node:path" -import { writeFileAtomic, writeFileExclusive } from "./atomic-write" +import { writeFileAtomic, writeFileExclusive, writeRecoverableFileExclusive } from "./atomic-write" // V3 Document System (docs/28): the bedrock. All persistent state is a typed-document // graph — small files, content-addressed, append-only with a supersede chain, bidirectional @@ -368,6 +368,26 @@ export class DocumentStore { return next } + // Trusted built-in corpus files are recoverable from the packaged domain packs. New seeds can + // therefore skip per-file fsync while retaining atomic visibility; updates still use the normal + // append-only durable path so shipped corpus revisions preserve version history. + seedActive(input: CreateDocInput): Doc { + const cur = this.findLogical(input) + if (cur) { + const doc = this.upsert(input) + if (doc.status !== "active") this.setStatus(doc.id, "active") + return this.get(doc.id)! + } + + const id = this.allocateId(input.type, input.domain ?? null, input.idSlug, input.description) + let doc = { ...this.docFromInput(id, 1, input), status: "active" as const } + this.assertKnowledgeConfidence(doc) + this.assertLinkTargets(doc.links) + doc = { ...doc, hash: computeHash(doc) } + this.persistRecoverable(doc) + return doc + } + update(id: string, body: string, links?: readonly DocLink[]): Doc { const cur = this.get(id) if (!cur) throw new Error(`update: unknown doc ${id}`) @@ -607,6 +627,20 @@ export class DocumentStore { } this.indexDoc(doc) } + private persistRecoverable(doc: Doc): void { + const dir = path.join(this.root, "docs", doc.type) + mkdirSync(dir, { recursive: true }) + const file = path.join(dir, `${idToFile(doc.id)}@v${doc.version}.json`) + try { + writeRecoverableFileExclusive(file, JSON.stringify(doc, null, 2)) + } catch (error) { + if ((error as NodeJS.ErrnoException)?.code !== "EEXIST") throw error + const existing = this.readVersionFile(file) + if (!existing || existing.hash !== doc.hash) + throw new DocumentConflictError(doc.id, doc.version, existing?.hash ?? "", doc.hash) + } + this.indexDoc(doc) + } private replace(doc: Doc): void { // rewrites the SAME version in place with new status/superseded_by; rehash so INV-2 holds. This // is an intentional overwrite (not a new version), so it uses the crash-safe atomic OVERWRITE diff --git a/packages/core/src/deepagent/durable-knowledge-store.ts b/packages/core/src/deepagent/durable-knowledge-store.ts index ab364124e6318476ec971591cb50ffbcfb5c9448..b237e8d2d204c4d0f9a2e70c35cfc96f97e6c781 100644 GIT binary patch delta 87 zcmZ2Kf$?%bJ_J^rZ^^-WR^`*39moIx diff --git a/packages/core/test/deepagent/document-store.test.ts b/packages/core/test/deepagent/document-store.test.ts index 45c004a1..4532bed0 100644 --- a/packages/core/test/deepagent/document-store.test.ts +++ b/packages/core/test/deepagent/document-store.test.ts @@ -174,6 +174,26 @@ describe("V3 DocumentStore", () => { // overwrites the same version atomically (temp+fsync+rename). These tests pin the CAS + durability // behavior that H32-1 (v4.0.4) builds on. describe("F30-1 DocumentStore CAS + atomic durability", () => { + test("recoverable built-in seeds retain active status and exclusive-create CAS", () => { + const h1 = new DocumentStore(root) + const h2 = new DocumentStore(root) + const input = { + type: "strategy" as const, + scope: "durable", + body: "trusted built-in strategy", + description: "built-in strategy", + idSlug: "built-in-strategy", + confidence: { evidence_strength: "strong" as const, support_count: 1 }, + provenance: { source: "human" as const }, + } + const first = h1.seedActive(input) + const concurrent = h2.seedActive(input) + expect(first.status).toBe("active") + expect(concurrent.hash).toBe(first.hash) + expect(new DocumentStore(root).get(first.id)).toEqual(first) + expect(readdirSync(path.join(root, "docs", "strategy"))).toEqual([`${first.id.replaceAll(":", "__")}@v1.json`]) + }) + test("normal single-writer flow is unchanged (create + updates land byte-identically)", () => { const a = store.create(design("v1")) const a2 = store.update(a.id, "v2") diff --git a/packages/desktop/electron-builder.config.ts b/packages/desktop/electron-builder.config.ts index ba308c7e..a177fdaf 100644 --- a/packages/desktop/electron-builder.config.ts +++ b/packages/desktop/electron-builder.config.ts @@ -62,6 +62,7 @@ const getBase = (): Configuration => ({ "resources/*.metainfo.xml", "resources/deepagent-code-cli*", ], + asarUnpack: ["out/main/chunks/node.js"], beforePack: () => auditPackageInputs(path.dirname(fileURLToPath(import.meta.url))), extraResources: [ { diff --git a/packages/desktop/electron.vite.config.ts b/packages/desktop/electron.vite.config.ts index 9045594d..cc911e5a 100644 --- a/packages/desktop/electron.vite.config.ts +++ b/packages/desktop/electron.vite.config.ts @@ -39,7 +39,7 @@ export default defineConfig(({ command }) => ({ rollupOptions: { input: { index: "src/main/index.ts", sidecar: "src/main/sidecar.ts" }, }, - externalizeDeps: { include: ["@lydell/node-pty"] }, + externalizeDeps: { exclude: ["@deepagent-code/core"], include: ["@lydell/node-pty"] }, }, plugins: [ { diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 9c7497bb..ee695d87 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -36,7 +36,6 @@ }, "main": "./out/main/index.js", "dependencies": { - "@deepagent-code/core": "workspace:*", "@lydell/node-pty": "catalog:", "@zip.js/zip.js": "2.7.62", "effect": "catalog:", @@ -51,6 +50,7 @@ "devDependencies": { "@actions/artifact": "4.0.0", "@deepagent-code/app": "workspace:*", + "@deepagent-code/core": "workspace:*", "@deepagent-code/ui": "workspace:*", "@jridgewell/trace-mapping": "0.3.31", "@playwright/test": "catalog:", diff --git a/packages/desktop/scripts/audit-server-bundle.ts b/packages/desktop/scripts/audit-server-bundle.ts index da8e9043..c732fdb6 100644 --- a/packages/desktop/scripts/audit-server-bundle.ts +++ b/packages/desktop/scripts/audit-server-bundle.ts @@ -4,8 +4,9 @@ import { strict as assert } from "node:assert" import { readdir } from "node:fs/promises" import path from "node:path" -const chunks = path.resolve("out/main/chunks") -const sidecar = await Bun.file(path.resolve("out/main/sidecar.js")).text() +const main = path.resolve("out/main") +const chunks = path.join(main, "chunks") +const sidecar = await Bun.file(path.join(main, "sidecar.js")).text() const server = Bun.file(path.join(chunks, "node.js")) const sourceMap = Bun.file(path.join(chunks, "node.js.map")) const files = await readdir(chunks) @@ -18,6 +19,22 @@ assert.deepEqual( [], "Rollup must not emit a transformed copy of the server bundle", ) +assert.deepEqual( + ( + await Promise.all( + [path.join(main, "index.js"), path.join(main, "sidecar.js"), ...files.map((file) => path.join(chunks, file))] + .filter((file) => file.endsWith(".js")) + .map(async (file) => + new Bun.Transpiler({ loader: "js" }) + .scanImports(await Bun.file(file).text()) + .filter((item) => item.path.startsWith("@deepagent-code/")) + .map((item) => `${path.relative(main, file)} -> ${item.path}`), + ), + ) + ).flat(), + [], + "Packaged main process must not import TypeScript workspace packages", +) const source = await server.text() assert.match(source, /sourceMappingURL=node\.js\.map/, "external server bundle is not linked to its source map") diff --git a/packages/desktop/scripts/subagents-smoke.ts b/packages/desktop/scripts/subagents-smoke.ts index ae971119..b7af0644 100644 --- a/packages/desktop/scripts/subagents-smoke.ts +++ b/packages/desktop/scripts/subagents-smoke.ts @@ -8,6 +8,7 @@ import { _electron as electron, type ElectronApplication, type Page } from "@pla const root = await realpath(await mkdtemp(join(tmpdir(), "deepagent-code-subagents-smoke-"))) const workspace = join(root, "workspace") const main = resolve("out/main/index.js") +const packagedExecutable = process.env.DEEPAGENT_CODE_DESKTOP_EXECUTABLE await mkdir(workspace, { recursive: true }) const env = Object.fromEntries( @@ -40,7 +41,13 @@ const api = (page: Page) => page.evaluate(() => (window as unknown as { api: Des let activeApp: ElectronApplication | undefined async function launch() { - const app = await electron.launch({ args: [main], env, timeout: 30_000 }) + const started = performance.now() + const app = await electron.launch({ + args: packagedExecutable ? [] : [main], + ...(packagedExecutable ? { executablePath: packagedExecutable } : {}), + env, + timeout: 30_000, + }) activeApp = app console.log( "Electron main launched", @@ -51,7 +58,11 @@ async function launch() { ) const page = await app.firstWindow({ timeout: 30_000 }) await page.waitForFunction(() => Boolean((window as unknown as { api?: DesktopAPI }).api)) - return { app, page } + const server = await api(page) + const startupMs = Math.round(performance.now() - started) + console.log("Electron startup ready", { packaged: Boolean(packagedExecutable), startupMs }) + if (packagedExecutable) assert.equal(startupMs < 20_000, true, `packaged startup took ${startupMs}ms`) + return { app, page, server } } async function close(app: ElectronApplication) { @@ -87,9 +98,8 @@ async function listSessions(server: Awaited>) { try { const first = await launch() - const server = await api(first.page) - const parent = await createSession(server, { title: "Cold-start parent" }) - const child = await createSession(server, { + const parent = await createSession(first.server, { title: "Cold-start parent" }) + const child = await createSession(first.server, { title: "Cold-start researcher", parentID: parent.id, metadata: { @@ -104,7 +114,7 @@ try { }, }, }) - const firstSessions = await listSessions(server) + const firstSessions = await listSessions(first.server) assert.equal( firstSessions.some((session) => session.id === parent.id), true, @@ -146,7 +156,7 @@ try { second.page.on("console", (message) => { if (message.type() === "error") consoleErrors.push(message.text()) }) - const sessions = await listSessions(await api(second.page)) + const sessions = await listSessions(second.server) assert.equal( sessions.some((session) => session.id === parent.id), true,