Description
Refactor AgentSessionFeature.State to hold an immutable Presentation enum wrapping either TerminalFeature.State or AgentChatFeature.State. Switch reducer composition from Scope to ifCaseLet accordingly.
Spec: Epic #250 §5 (session surface model — Presentation enum).
Scope
File
MacApp/Packages/AgentOrchestrator/Sources/AgentOrchestrator/AgentSessionFeature.swift
Before / after
Before:
```swift
public struct State {
public var session: AgentSession
public var terminal: TerminalFeature.State
public var kind: SessionKind
...
}
```
After:
```swift
public struct State {
public var session: AgentSession // contains immutable surface
public var presentation: Presentation
public var kind: SessionKind
...
public enum Presentation: Equatable {
case terminal(TerminalFeature.State)
case dialogue(AgentChatFeature.State)
}
}
public enum Action {
case startAgent(workingDirectory: URL)
case stopAgent
case restartAgent
case terminal(TerminalFeature.Action)
case dialogue(AgentChatFeature.Action)
case _claudeDetected(ClaudeInstallation, shellPATH: String?)
case _agentStarted
case _agentStopped(exitCode: Int32)
}
public var body: some ReducerOf {
Reduce { state, action in /* lifecycle */ }
.ifCaseLet(.presentation.terminal, action: .terminal) {
TerminalFeature()
}
.ifCaseLet(.presentation.dialogue, action: .dialogue) {
AgentChatFeature()
}
}
```
Initialization
.agentTerminal(.claudeCode) — initial Presentation.terminal(.init()).
.agentDialogue(.claudeCode) — initial Presentation.dialogue(.init(sessionID:, agentKind:)).
- Initialization happens at AgentOrchestratorFeature when creating a new session (surface chosen by caller).
Lifecycle routing
startAgent action builds the correct command via ClaudeCommandBuilder (D-20), starts the underlying TerminalSession via the appropriate sub-feature:
- Terminal surface: delegates to
TerminalFeature start action.
- Dialogue surface: creates
ClaudeCodeJSONLSession (D-9), dispatches .dialogue(._startSession(...)).
Acceptance Criteria
Relationships
Description
Refactor
AgentSessionFeature.Stateto hold an immutablePresentationenum wrapping eitherTerminalFeature.StateorAgentChatFeature.State. Switch reducer composition fromScopetoifCaseLetaccordingly.Spec: Epic #250 §5 (session surface model — Presentation enum).
Scope
File
MacApp/Packages/AgentOrchestrator/Sources/AgentOrchestrator/AgentSessionFeature.swiftBefore / after
Before:
```swift
public struct State {
public var session: AgentSession
public var terminal: TerminalFeature.State
public var kind: SessionKind
...
}
```
After:
```swift
public struct State {
public var session: AgentSession // contains immutable
surfacepublic var presentation: Presentation
public var kind: SessionKind
...
}
public enum Action {
case startAgent(workingDirectory: URL)
case stopAgent
case restartAgent
case terminal(TerminalFeature.Action)
case dialogue(AgentChatFeature.Action)
case _claudeDetected(ClaudeInstallation, shellPATH: String?)
case _agentStarted
case _agentStopped(exitCode: Int32)
}
public var body: some ReducerOf {
Reduce { state, action in /* lifecycle */ }
.ifCaseLet(.presentation.terminal, action: .terminal) {
TerminalFeature()
}
.ifCaseLet(.presentation.dialogue, action: .dialogue) {
AgentChatFeature()
}
}
```
Initialization
.agentTerminal(.claudeCode)— initialPresentation.terminal(.init())..agentDialogue(.claudeCode)— initialPresentation.dialogue(.init(sessionID:, agentKind:)).Lifecycle routing
startAgentaction builds the correct command viaClaudeCommandBuilder(D-20), starts the underlying TerminalSession via the appropriate sub-feature:TerminalFeaturestart action.ClaudeCodeJSONLSession(D-9), dispatches.dialogue(._startSession(...)).Acceptance Criteria
AgentSessionFeature.Staterefactored withpresentationenum.ifCaseLetfor both presentations.Relationships