Compare commits

...
3 changed files with 49 additions and 4 deletions
@@ -1,10 +1,12 @@
import { execFile } from "node:child_process";
import { randomUUID } from "node:crypto";
import { readFile, readdir } from "node:fs/promises";
import { buildSelfNodeCommand } from "../server/paseo-env.js";
import { ensurePrivateDirectory } from "../server/private-files.js";
import {
readTerminalWorkerRecord,
terminalWorkerDirectory,
terminalWorkerLogPath,
terminalWorkerRecordPath,
type TerminalWorkerRecord,
} from "./terminal-worker-record.js";
@@ -56,13 +58,31 @@ export async function launchTerminalWorker(input: {
windowsHide: true,
encoding: "utf8",
},
(error, out, err) => {
async (error, out, err) => {
if (error) {
const detail = err.trim() || error.message;
// Temporary diagnostics: retain the last startup stage before test cleanup removes it.
let startup = "";
try {
startup = (await readFile(terminalWorkerLogPath(input.paseoHome), "utf8"))
.split("\n")
.filter((line) => line.startsWith('{"phase":'))
.slice(-12)
.join("\n");
const records = (await readdir(terminalWorkerDirectory(input.paseoHome))).filter(
(name) => name.endsWith(".json"),
).length;
startup += `\nWorker records at failure: ${records}`;
} catch {
startup += "\nStartup diagnostics unavailable";
}
reject(
new TerminalWorkerLaunchError(`Terminal worker failed to start: ${detail}`, {
cause: error,
}),
new TerminalWorkerLaunchError(
`Terminal worker failed to start: ${detail}\n${startup}`,
{
cause: error,
},
),
);
return;
}
@@ -169,6 +169,9 @@ function runLauncher(argv: string[]): void {
type TerminalCreateRequest = Extract<TerminalWorkerRequest, { type: "createTerminal" }>;
function runWorker(argv: string[]): void {
const startupPhase = (phase: string) =>
console.error(JSON.stringify({ phase, uptimeMs: Math.round(process.uptime() * 1000) }));
startupPhase("worker-modules-loaded");
const args = parseWorkerArgs(argv, TERMINAL_WORKER_MARKER_ARG);
const protocolVersion = reportedProtocolVersion();
const manager = createTerminalManager();
@@ -686,6 +689,7 @@ function runWorker(argv: string[]): void {
writeSync(READY_FD, `${line}\n`);
closeSync(READY_FD);
} catch {
startupPhase("ready-write-failed");
// Started without a launcher pipe (tests that spawn the worker directly).
}
}
@@ -707,11 +711,14 @@ function runWorker(argv: string[]): void {
});
});
server = listening;
startupPhase("socket-listening");
if (process.platform !== "win32") {
chmodSync(socketPath, PRIVATE_FILE_MODE);
}
startupPhase("identity-start");
const self = await inspector.inspect(process.pid);
startupPhase("identity-finished");
if (
self.status !== "alive" ||
!self.snapshot.startedAt ||
@@ -734,7 +741,9 @@ function runWorker(argv: string[]): void {
terminals: [],
};
writeTerminalWorkerRecord(args.paseoHome, record);
startupPhase("record-written");
reportReady(`ready ${socketPath}`);
startupPhase("ready-reported");
setTimeout(() => {
if (!everControlled && sessionsById.size === 0) exitWorker(0);
@@ -2671,3 +2671,19 @@ it.each([false, true])(
},
45000,
);
it.skipIf(process.platform !== "win32").each(Array.from({ length: 40 }, (_, i) => i + 1))(
"diagnostic: fresh terminal worker startup %i",
async () => {
const paseoHome = createTemporaryHome();
const started = Date.now();
try {
manager = await startRealWorkerManager({ paseoHome });
expect(manager).toBeDefined();
} finally {
console.log("terminal startup duration", Date.now() - started);
const workerLog = join(paseoHome, "terminal-worker.log");
if (existsSync(workerLog)) console.log(readFileSync(workerLog, "utf8"));
}
},
);