docs(interactive): ConPTY interactive sessions spec + plan
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# ConPTY Interactive Sessions — Design
|
||||
|
||||
Date: 2026-07-23
|
||||
Status: Approved (design), implementation not started
|
||||
|
||||
## Problem
|
||||
|
||||
The current in-app interactive session path streams `stream-json` from a
|
||||
`claude` process spawned **in the Worker** and renders it as a chat log with a
|
||||
composer. It does not surface permission requests, AskUser questions, and other
|
||||
TUI-native interactions well — the rendering is a partial reimplementation of
|
||||
what the real Claude Code TUI already does. We want full fidelity for
|
||||
interactive work without rebuilding the TUI.
|
||||
|
||||
## Decision
|
||||
|
||||
**Hybrid execution model:**
|
||||
|
||||
- **Autonomous queue tasks** (`Status=Queued`, picked by the queue): unchanged.
|
||||
Headless `stream-json`, full orchestration (status flow, diff, review, merge).
|
||||
- **Interactive sessions**: an **embedded ConPTY terminal** running the real
|
||||
`claude` CLI, rendered in the **UI process**. Full TUI fidelity (permission
|
||||
prompts, questions, colors, everything the standalone CLI does). Detached from
|
||||
the review/merge/status machinery — these are a manual cockpit.
|
||||
|
||||
This is the third direction for interactive (external `wt` terminal → streaming
|
||||
chat → embedded ConPTY). The streaming interactive stack is **removed**, not run
|
||||
in parallel — accepted as discarded work in exchange for one interactive path
|
||||
and full fidelity.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Process location
|
||||
|
||||
ConPTY terminal controls render in-process and spawn their child (`claude`) as a
|
||||
child of the host process. Therefore interactive sessions move **out of the
|
||||
Worker and into the UI process**. They no longer flow over SignalR. This mirrors
|
||||
the existing `ResumeTaskInTerminal` behavior (launch real `claude`), but embedded
|
||||
instead of via external `wt.exe`.
|
||||
|
||||
### Worktree preparation (task-based sessions)
|
||||
|
||||
Interactive task sessions get the **same worktree preparation as autonomous
|
||||
runs**: session-skills seeding, agent files, MCP config, environment. The Worker
|
||||
performs the prep and returns a launch spec to the UI:
|
||||
|
||||
```
|
||||
LaunchSpec {
|
||||
cwd: string // worktree path
|
||||
exe: string // resolved claude executable / shell
|
||||
args: string[] // e.g. --resume <sessionId>
|
||||
env: Dictionary<string,string>
|
||||
}
|
||||
```
|
||||
|
||||
The command construction reuses the existing logic in
|
||||
`WindowsTerminalLauncher.BuildResumeCommand`. Guards mirror
|
||||
`ResumeTaskInTerminal`: task not Running/Queued, a persisted SessionId exists,
|
||||
worktree exists and is Active/Kept.
|
||||
|
||||
### Free / ad-hoc sessions
|
||||
|
||||
In addition to task-based sessions, the user can open an ad-hoc terminal in a
|
||||
chosen directory (no task). These also get MCP config + env set up so the
|
||||
`claudedo` tools are available, but no per-level session-skills seeding tied to a
|
||||
task.
|
||||
|
||||
### Terminal host control
|
||||
|
||||
Embed a ConPTY-capable Avalonia terminal control in the UI. Candidates:
|
||||
|
||||
- **SvcSystems.UI.Terminal** (IvanJosipovic) — explicit ConPTY, full-screen TUI
|
||||
render + resize reflow, selection/mouse reporting.
|
||||
- **Iciclecreek.Avalonia.Terminal** — XTerm.NET + Porta.Pty, clean
|
||||
`TerminalControl` embed API.
|
||||
|
||||
Selection is resolved by a **spike** (first plan step): the acceptance criterion
|
||||
is that the real `claude` TUI renders correctly inside the control — colors,
|
||||
resize/reflow, and a live permission prompt are usable.
|
||||
|
||||
### Command Center layout
|
||||
|
||||
- `MonitorPaneView` keeps the streamed log for autonomous tasks.
|
||||
- Interactive panes host the terminal control instead of the log+composer.
|
||||
- Layout is **toggleable**: focus mode (tabs, one session large) ↔ overview mode
|
||||
(grid, several sessions at once).
|
||||
|
||||
## Removals
|
||||
|
||||
Worker:
|
||||
- `StreamingClaudeSession`, `InteractiveSessionService`
|
||||
- `WorkerHub` interactive methods: `OpenInteractiveTerminal`,
|
||||
`SendInteractiveMessage`, `RemoveQueuedInteractiveMessage`,
|
||||
`StopInteractiveSession`, `InterruptInteractiveSession`
|
||||
- Broadcast events: `InteractiveSessionStarted/Ended`, `InteractiveQueueChanged`,
|
||||
`InteractiveMessageSent`
|
||||
- `IdleSessionReaper` and `LiveSessionRegistry` **iff** unused elsewhere
|
||||
(verify during implementation — do not delete blindly).
|
||||
|
||||
UI:
|
||||
- Composer on `TaskMonitorViewModel`: `ComposerDraft`, `SubmitComposerCommand`,
|
||||
`InterruptInteractiveCommand`, `StopInteractiveCommand`, `QueuedMessages`,
|
||||
`IsInteractiveLive`.
|
||||
- The composer + queued-messages portion of `SessionTerminalView` (the log
|
||||
portion stays for autonomous panes).
|
||||
- `IWorkerClient` interactive methods.
|
||||
|
||||
## Open items (implementation time)
|
||||
|
||||
- Whether `LiveSessionRegistry` is referenced outside the interactive path.
|
||||
- Exact env dictionary handed to the ConPTY control (parity with the autonomous
|
||||
run environment).
|
||||
- Session-id availability for a never-run task (no `--resume` → start fresh).
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No screen-scraping of terminal output back into task status/diff/review.
|
||||
- No change to the autonomous queue execution path.
|
||||
Reference in New Issue
Block a user