testSessionsGoOnAfterARestart
A session's server started again for the same agent (from the same directory: the client reconnecting after a
pause, its server stopped or killed) goes on with its branch, and says so, as long as the branch holds work main
doesn't have. Another agent's (another directory: a worktree reaching the codebase through a link) doesn't take
it, nor does a second server from the same directory while the first is on it: two servers never share a branch.
A session moves onto a branch it owns with tcm_cli ["switch",
import { okIn, 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 fs from "node:fs"; import path from "node:path"; export const testSessionsGoOnAfterARestart = () => withChildren(async (keep) => { const dir = tempDir("mcp restart"); const tcm = (...args: string[]) => okIn(dir, ...args); tcm("init"); fs.rmSync(path.join(dir, "scratch.ts"), { force: true }); const a = await startedSession(dir, keep); assert.match(a.branch, /^session\//); assert.doesNotMatch(a.instructions, /last session left/); assert.equal( (await a.call("tcm_add", { code: "export const work = 1;\n", namespace: "lib" })).isError, false, ); a.close(); await a.exit; const a2 = await startedSession(dir, keep); assert.equal(a2.branch, a.branch); assert.match(a2.instructions, /this directory's last session left holding its work/); assert.match((await a2.call("tcm_view", { names: ["lib.work"] })).text, /work = 1/); // killed, rather than stopped: the same a2.kill(); await a2.exit; const a3 = await startedSession(dir, keep); assert.equal(a3.branch, a.branch); const link = path.join(tempDir("mcp worktree"), "codebase"); fs.symlinkSync(dir, link); const b = await startedSession(link, keep, { PWD: link }); assert.notEqual(b.branch, a.branch); // (the same directory, while a3 is on it: it waits a little for a3 to stop, as a server being replaced does) const c = await startedSession(dir, keep); assert.notEqual(c.branch, a.branch); assert.notEqual(c.branch, b.branch); const refused = await c.call("tcm_cli", { args: ["switch", a.branch] }); assert.equal(refused.isError, true, refused.text); assert.match(refused.text, /works on session\/\S+: two servers don't share a branch/); a3.kill(); await a3.exit; const moved = await c.call("tcm_cli", { args: ["switch", a.branch] }); assert.equal(moved.isError, false, moved.text); assert.match( moved.text, new RegExp(`works on ${a.branch} now[\\s\\S]*${c.branch}, which it leaves, is gone`), ); assert.match((await c.call("tcm_view", { names: ["lib.work"] })).text, /work = 1/); assert.match((await c.call("tcm_status")).text, new RegExp(`^branch\\s+${a.branch}`, "m")); assert.doesNotMatch(tcm("branch"), new RegExp(c.branch)); const main = await c.call("tcm_cli", { args: ["switch", "main"] }); assert.equal(main.isError, true, main.text); assert.match(main.text, /main is the codebase's own branch/); b.close(); c.close(); })