diff --git a/packages/server/src/terminal/worker-terminal-manager.test.ts b/packages/server/src/terminal/worker-terminal-manager.test.ts index ffc9b18a45..7d91ec180e 100644 --- a/packages/server/src/terminal/worker-terminal-manager.test.ts +++ b/packages/server/src/terminal/worker-terminal-manager.test.ts @@ -1742,6 +1742,7 @@ it.skipIf(isPlatform("win32"))( it("replays bounded ANSI chunks independently of live output and reconstructs the revision cut", async () => { const cwd = createTemporaryHome(); + const finishBefore = join(cwd, "finish-before"); manager = await startRealWorkerManager(); const session = trackTerminal( await manager.createTerminal({ @@ -1751,7 +1752,15 @@ it("replays bounded ANSI chunks independently of live output and reconstructs th cols: 120, ...nodeTerminalCommand(` for (let i = 0; i < 800; i++) process.stdout.write("\\x1b[31m" + String(i).padStart(4, "0") + ":" + "x".repeat(100) + "\\x1b[0m\\r\\n"); - require("node:readline").createInterface({ input: process.stdin }).on("line", line => process.stdout.write(line === "before" ? "PRE-CUT\\r\\n" : "LIVE-AFTER-REPLAY\\r\\n")); + require("node:readline").createInterface({ input: process.stdin }).on("line", line => { + if (line !== "before") { process.stdout.write("LIVE-AFTER-REPLAY\\r\\n"); return; } + process.stdout.write("PRE-CUT"); + const finish = setInterval(() => { + if (!require("node:fs").existsSync(${JSON.stringify(finishBefore)})) return; + clearInterval(finish); + process.stdout.write("\\r\\n"); + }, 5); + }); setInterval(() => {}, 1000); `), }), @@ -1775,6 +1784,13 @@ it("replays bounded ANSI chunks independently of live output and reconstructs th }); session.send({ type: "input", data: "before\r" }); await waitForCondition(() => live.includes("PRE-CUT"), 10000); + // A PTY may deliver the marker and its trailing newline separately. Finish + // that output before replay, so the two captures must describe the same cut. + writeFileSync(finishBefore, ""); + await waitForCondition(async () => { + const { lines } = await manager!.captureTerminal(session.id); + return lines.at(-2) === "PRE-CUT" && lines.at(-1) === ""; + }, 10000); const expected = await manager.captureTerminal(session.id); const metadata = await manager.replayTerminal(session.id, undefined, (event) => { events.push(event.type); diff --git a/packages/server/src/utils/test-fixtures/config-responsiveness.ts b/packages/server/src/utils/test-fixtures/config-responsiveness.ts index 9e151c805a..787ad88674 100644 --- a/packages/server/src/utils/test-fixtures/config-responsiveness.ts +++ b/packages/server/src/utils/test-fixtures/config-responsiveness.ts @@ -1,4 +1,5 @@ import { createHook, executionAsyncResource } from "node:async_hooks"; +import { stat } from "node:fs/promises"; import { MessagePort } from "node:worker_threads"; import assert from "node:assert/strict"; import { setImmediate as nextTurn } from "node:timers/promises"; @@ -10,6 +11,11 @@ import { readPaseoConfigForEdit } from "../paseo-config-file.js"; // Read the real file once, without warming the config snapshot or schema. const directory = process.argv[2]; assert.ok(directory, "Config directory is required"); +// The daemon has already used asynchronous filesystem APIs before reading a +// project config. Start libuv's filesystem worker pool outside the measurement: +// its first submission synchronously creates workers in a fresh Node process. +// Stat the probe itself so the config, snapshot and schemas remain cold. +await stat(process.argv[1]); await nextTurn(); let workerMessages = 0; const activity = createHook({