This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

fix(restart): preserve displayName across respawn (#61)

pty restart / attach-restart / interactive doRestart re-spawned the
daemon from stored metadata but dropped displayName, so a restarted
session read as its raw id (e.g. claude-203827) instead of its name —
breaking naming and the TUI peek. Forward meta.displayName at all three
restart call sites, matching the existing `run -a` re-create path.
Tags were already carried. Adds a driven regression test that fails
without the fix.

authored by

Nathan and committed by
GitHub
(Jul 8, 2026, 7:05 PM +0200) d0317498 4dd6f9f5

+53 -4
+13 -3
src/cli.ts
··· 1186 1186 } 1187 1187 } 1188 1188 1189 - // Restart 1189 + // Restart. Preserve displayName (and tags) so the respawned session keeps its 1190 + // name instead of falling back to the raw id. 1190 1191 cleanupAll(session.name); 1191 - await spawnDaemon({ name: session.name, command: meta.command, args: meta.args, displayCommand: meta.displayCommand, cwd: meta.cwd, tags: meta.tags }); 1192 + await spawnDaemon({ 1193 + name: session.name, command: meta.command, args: meta.args, displayCommand: meta.displayCommand, cwd: meta.cwd, tags: meta.tags, 1194 + ...(meta.displayName ? { displayName: meta.displayName } : {}), 1195 + }); 1192 1196 console.log(`Session "${session.name}" restarted.`); 1193 1197 doAttach(session.name); 1194 1198 } ··· 2751 2755 // command edit already clears these; this handles the operator- 2752 2756 // intervenes-without-edit case that gc otherwise can't infer. 2753 2757 const restartTags = clearFlappingBookkeeping(meta.tags); 2754 - await spawnDaemon({ name, command: meta.command, args: meta.args, displayCommand: meta.displayCommand, cwd: meta.cwd, tags: restartTags }); 2758 + // Preserve the human-friendly displayName across the respawn — without it the 2759 + // restarted session reads as its raw id (e.g. claude-203827) instead of its 2760 + // name, which breaks naming + the TUI peek. Tags are carried above. 2761 + await spawnDaemon({ 2762 + name, command: meta.command, args: meta.args, displayCommand: meta.displayCommand, cwd: meta.cwd, tags: restartTags, 2763 + ...(meta.displayName ? { displayName: meta.displayName } : {}), 2764 + }); 2755 2765 console.log(`Session "${name}" restarted.`); 2756 2766 2757 2767 // Nesting guard: restart itself is fine, but attaching would nest a client
+6 -1
src/tui/interactive.ts
··· 503 503 } 504 504 cleanupAll(session.name); 505 505 try { 506 - await spawnDaemon({ name: session.name, command: meta.command, args: meta.args, displayCommand: meta.displayCommand, cwd: meta.cwd, tags: meta.tags }); 506 + // Preserve displayName (and tags) so a restarted session keeps its name 507 + // rather than reverting to its raw id. 508 + await spawnDaemon({ 509 + name: session.name, command: meta.command, args: meta.args, displayCommand: meta.displayCommand, cwd: meta.cwd, tags: meta.tags, 510 + ...(meta.displayName ? { displayName: meta.displayName } : {}), 511 + }); 507 512 } catch { 508 513 // Refresh list to show updated state 509 514 const updated = await listSessions();
+34
tests/display-name.test.ts
··· 360 360 expect(running).toHaveLength(0); 361 361 }); 362 362 }); 363 + 364 + describe("pty restart preserves displayName + tags", () => { 365 + // Regression: `pty restart` re-spawned the daemon from stored metadata but 366 + // dropped `displayName`, so a restarted session read as its raw id (e.g. 367 + // claude-203827) instead of its name — breaking naming and the TUI peek. 368 + // Tags were already carried; this locks in both. 369 + it("keeps displayName and tags across a restart", () => { 370 + const dir = makeSessionDir(); 371 + const create = runCli( 372 + dir, {}, 373 + "run", "-d", "--id", "svc", "--name", "My Service", "--tag", "role=web", "--", "cat", 374 + ); 375 + expect(create.status).toBe(0); 376 + 377 + let s = listJson(dir).find((x: any) => x.name === "svc")!; 378 + expect(s).toBeDefined(); 379 + expect(s.displayName).toBe("My Service"); 380 + expect(s.tags?.role).toBe("web"); 381 + collectPid(dir, "svc"); 382 + 383 + // Restart. Setting PTY_SESSION makes the CLI take the "already inside a 384 + // session, not attaching" branch and return, instead of hanging on attach 385 + // in this non-TTY test process. 386 + const restart = runCli(dir, { PTY_SESSION: "outer" }, "restart", "-y", "svc"); 387 + expect(restart.status).toBe(0); 388 + expect(restart.stdout).toContain("restarted"); 389 + 390 + s = listJson(dir).find((x: any) => x.name === "svc")!; 391 + expect(s).toBeDefined(); 392 + expect(s.displayName).toBe("My Service"); 393 + expect(s.tags?.role).toBe("web"); 394 + collectPid(dir, "svc"); 395 + }); 396 + });