a spawned session says who started it

The other half of making a spawned agent visible. The commander's pane now lists
its children; opening one gave no way back — no link to the conversation that owns
it, and nothing to tell it apart from a chat somebody had started themselves and
forgotten.

`parentCommanderOf` is the row `ingestSpawnedChildren` already writes, read from
the other end. So this needed no table and no write path: a commander's children
were recorded because deleting one has to take them with it, and that record
answers "who is my parent" for free. Nothing had asked.

`GET /chat/sessions/:id` carries `spawnedBy`, and the chat panel renders one line
above the transcript linking back to the commander. Null for almost every session,
which is the normal case rather than a miss — a chat somebody opened has no parent
— so the bar renders nothing at all rather than saying so. Never fatal: a session
must open when this lookup will not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 05:09:28 +00:00
co-authored by Claude Opus 5
parent 44f5246e38
commit f6b9ddc877
5 changed files with 85 additions and 0 deletions
@@ -104,6 +104,14 @@ export type ClaudeSessionDetail = {
* to decide it from the route, so the same commander opened in /chat quietly lost it.
*/
isCommander?: boolean;
/**
* The commander that spawned this session, if one did.
*
* Read from the row a commander already keeps of its children — so this is the parent side of a link that
* existed for a different reason (deleting a commander has to take its children with it). Absent for
* almost every conversation, and absence means "nobody spawned this", never "the lookup failed".
*/
spawnedBy?: { sessionId: string; name: string | null; firstSeenAt: string; finishedAt: string | null } | null;
};
export type ClaudePwd = { cwd: string; sessionCount: number; updatedAt: string; isDefault: boolean };