testSupervisedRestartsKeepTheBranch
A session's server the supervisor starts again goes on with the session's branch, the one it moved onto too: when tcm is replaced, and when the server crashes (what it hadn't answered is answered, to ask again).
import { okIn, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import { startedSession } from "#codebase/tcmts/cli/test/e2e/mcp"; import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; import { pathToFileURL } from "node:url"; export const testSupervisedRestartsKeepTheBranch = () => withChildren(async (keep) => { const dir = tempDir("mcp supervised restart"); const tcm = (...args: string[]) => okIn(dir, ...args); tcm("init"); fs.rmSync(path.join(dir, "scratch.ts"), { force: true }); tcm("branch", "agent/b"); const bin = path.join(dir, "tcm-bin.mjs"); fs.writeFileSync(bin, `import ${JSON.stringify(pathToFileURL(tcmBin()).href)};\n`); const s = await startedSession(dir, keep, {}, [bin, "mcp", "--branch", "agent/a"]); assert.equal(s.branch, "agent/a"); const moved = await s.call("tcm_cli", { args: ["switch", "agent/b"] }); assert.equal(moved.isError, false, moved.text); // (a named branch it leaves stays) assert.match(moved.text, /agent\/a, which it leaves, stays/); // (none, for a moment, between one stopping and the next starting) const server = () => { try { return execFileSync("pgrep", ["-n", "-P", String(s.pid)], { encoding: "utf8" }).trim(); } catch { return ""; } }; const first = server(); fs.writeFileSync(bin, `${fs.readFileSync(bin, "utf8")}// v2\n`); for ( const until = Date.now() + 30_000; !s.notes.some((n) => n.method === "notifications/tools/list_changed"); await new Promise((r) => setTimeout(r, 100)) ) if (Date.now() > until) assert.fail("the server wasn't started again"); assert.match((await s.call("tcm_status")).text, /^branch\s+agent\/b/m); const replaced = server(); assert.notEqual(replaced, first); process.kill(Number(replaced), "SIGKILL"); for ( const until = Date.now() + 30_000; ["", replaced].includes(server()); await new Promise((r) => setTimeout(r, 100)) ) if (Date.now() > until) assert.fail("the server wasn't started again after it crashed"); assert.match((await s.call("tcm_status")).text, /^branch\s+agent\/b/m); s.close(); })