Skip to content

D-21: AgentSessionFeature — Presentation enum + ifCaseLet scope #271

@kirich1409

Description

@kirich1409

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

  • AgentSessionFeature.State refactored with presentation enum.
  • Reducer composes via ifCaseLet for both presentations.
  • Terminal regression: existing terminal sessions still work (unit tests pass).
  • Dialogue session can be created with correct initial Presentation and lifecycle hooks into underlying Dialogue session.
  • TestStore coverage for transitions: start → running → exit for both surfaces.
  • Swift 6 strict concurrency clean.

Relationships

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions