Description
Integrate the ClaudeCodeJSONLSession adapter's lifecycle with the underlying TerminalSession — ensure the PTY / gRPC session is owned, started, reconnected, and terminated as a pair with the Dialogue session.
Spec: Epic #250 §4.3 (data flow).
Scope
Ownership model
ClaudeCodeJSONLSession owns a TerminalSession instance. Ownership implications:
- Creating a Dialogue session creates the underlying
TerminalSession; terminating Dialogue terminates the terminal.
TerminalFeature (the existing reducer) is not used for Dialogue sessions — the Dialogue session goes directly through TerminalEngine.makeSession(configuration:) → no reducer indirection.
- For
.agentDialogue surface, the TerminalSession is registered into sharedTerminalRegistry with a distinct tag so UI can differentiate (useful for Stream Inspector).
Reconnect semantics (remote sessions)
- When
RemoteTerminalSession.connectionState emits .reconnected, the VT-snapshot replay happens as usual. ClaudeCodeJSONLSession observes rawStdout — replay bytes flow in naturally and parser dedupes by session_id + event.index + uuid.
- If reconnect is impossible (runner drop, auth rotation) → status
.error(ReconnectFailed) + UI shows retry banner.
Subagent nesting
parent_tool_use_id ≠ null events — parser tags them, reducer routes them to the parent ToolCall.subagentTranscript sub-state (forward decision — nested reducer state inside ToolCall).
- Lifecycle of subagent is tied to parent tool call — subagent can't outlive parent.
Acceptance Criteria
Relationships
Description
Integrate the
ClaudeCodeJSONLSessionadapter's lifecycle with the underlyingTerminalSession— ensure the PTY / gRPC session is owned, started, reconnected, and terminated as a pair with the Dialogue session.Spec: Epic #250 §4.3 (data flow).
Scope
Ownership model
ClaudeCodeJSONLSessionowns aTerminalSessioninstance. Ownership implications:TerminalSession; terminating Dialogue terminates the terminal.TerminalFeature(the existing reducer) is not used for Dialogue sessions — the Dialogue session goes directly throughTerminalEngine.makeSession(configuration:)→ no reducer indirection..agentDialoguesurface, theTerminalSessionis registered intosharedTerminalRegistrywith a distinct tag so UI can differentiate (useful for Stream Inspector).Reconnect semantics (remote sessions)
RemoteTerminalSession.connectionStateemits.reconnected, the VT-snapshot replay happens as usual.ClaudeCodeJSONLSessionobservesrawStdout— replay bytes flow in naturally and parser dedupes bysession_id + event.index + uuid..error(ReconnectFailed)+ UI shows retry banner.Subagent nesting
parent_tool_use_id ≠ nullevents — parser tags them, reducer routes them to the parentToolCall.subagentTranscriptsub-state (forward decision — nested reducer state inside ToolCall).Acceptance Criteria
ClaudeCodeJSONLSession.start()spawns terminal process + starts parser consumption in one atomic step..terminate()cleanly closes terminal, cancels consumer tasks, finishes transcript stream.close()+ emits.error(UnexpectedExit)to transcript before finishing the stream.parent_tool_use_idrouting — unit test verifies nested events land in the correctToolCallsubagent sub-state.terminate()(verified by memory / task-counter tests).sharedTerminalRegistrycontains the underlying session during its lifetime, removed on terminate.Relationships