diff --git a/src/servers/api/chat/chat.ts b/src/servers/api/chat/chat.ts index 08c7d89e..d29113f5 100644 --- a/src/servers/api/chat/chat.ts +++ b/src/servers/api/chat/chat.ts @@ -122,9 +122,13 @@ chatRouter.get('/live', async (ctx) => { // OpenCode rows carry less, and the shape says so rather than faking parity. `isGenerating` is always // true because a subprocess exists only while it generates; `pendingTasks` is 0 because `opencode run` - // has no background-task concept. Title and cwd come from the session store, which is keyed on the - // `ses_…` id the runner reports — not on our sessionKey — so a turn whose id has not been reported yet - // shows unnamed rather than guessing. + // has no background-task concept. + // + // Title and cwd are ALWAYS null here, not merely null-until-known: naming a session means reading + // OpenCode's store, which is keyed on the `ses_…` id, and `LiveOpenCodeSession` does not carry one — + // the runner reports it separately over `opencode:session` and nothing correlates the two. So a + // running OpenCode turn shows up unnamed, every time. Giving it a title means widening that type + // first; guessing from `sessionKey` would be inventing one. const openCodeSessions = liveOpenCode.map((session) => ({ sessionKey: session.sessionKey, claudeSessionId: null, diff --git a/src/servers/sidecar/protocol.ts b/src/servers/sidecar/protocol.ts index ad05f5ae..198c9cac 100644 --- a/src/servers/sidecar/protocol.ts +++ b/src/servers/sidecar/protocol.ts @@ -11,14 +11,6 @@ export type SidecarMessage = SidecarCommand | SidecarEvent; * together with `isGenerating` it is exactly what the agent's own idle GC consults before deciding a * session may be collected, so a caller can tell "busy" from "merely open" the same way it does. */ -/** - * An OpenCode turn in flight. Only ever the generating ones — see `listRunningOpenCodeTurns` for why - * this carries neither `isGenerating` (it is always true) nor `pendingTasks` (no such concept). - */ -export type LiveOpenCodeSession = { - sessionKey: string; -}; - export type LiveClaudeSession = { sessionKey: string; /** @@ -33,6 +25,18 @@ export type LiveClaudeSession = { pendingTasks: number; }; +/** + * An OpenCode turn in flight. Only ever the generating ones — see `listRunningOpenCodeTurns` for why + * this carries neither `isGenerating` (it is always true) nor `pendingTasks` (no such concept). + * + * It also carries no id for OpenCode's own `ses_…` session, which is why a live OpenCode row cannot be + * named: the runner reports that id separately, over `opencode:session`, and nothing correlates the two + * back here. Adding it is what a titled OpenCode row in the Live panel would need. + */ +export type LiveOpenCodeSession = { + sessionKey: string; +}; + // ── Commands (API server → sidecar) ── export type SidecarCommand =