diff --git a/docs/superpowers/specs/2026-07-23-conpty-interactive-sessions-design.md b/docs/superpowers/specs/2026-07-23-conpty-interactive-sessions-design.md index 1078f00e..39079403 100644 --- a/docs/superpowers/specs/2026-07-23-conpty-interactive-sessions-design.md +++ b/docs/superpowers/specs/2026-07-23-conpty-interactive-sessions-design.md @@ -65,18 +65,40 @@ 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 +### Terminal host control — RESOLVED by spike (2026-07-23) -Embed a ConPTY-capable Avalonia terminal control in the UI. Candidates: +**Library: `Iciclecreek.Avalonia.Terminal` 2.0.3** (namespace `Iciclecreek.Terminal`). +It needs Avalonia >= 12.0.2; the repo is on 12.0.4 → compatible, no bump. +`SvcSystems.UI.Terminal` (latest) needs Avalonia 12.1+ → rejected. -- **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. +Visual pass (user, 2026-07-23): the real `claude` TUI renders correctly inside +the embedded control — Claude Code opened and was usable. -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. +**Binding approach — drive Porta.Pty ourselves, reuse Iciclecreek's VT engine.** +The convenience `TerminalControl.LaunchProcess()` spawns the child itself and +never sets `PtyOptions.Environment`, and there is no settable pty/env seam on +`TerminalControl`/`TerminalView` (env-building lives in the non-virtual +`TerminalView.LaunchProcess()` using private fields). But the VT parser/renderer +is the public `XTerm.Terminal` object exposed via `TerminalControl.Terminal`, so +we reuse it without forking: + +- `Porta.Pty.PtyProvider.SpawnAsync(new PtyOptions { Name, App, Cwd, CommandLine, + Environment = }, ct)` → `IPtyConnection`. +- Do **not** call `TerminalControl.LaunchProcess()` (leaves its `_ptyConnection` + null). +- Get `TerminalControl.Terminal` (public, `XTerm.Terminal`) after template apply. +- Pump `IPtyConnection.ReaderStream` → `Terminal.Write(text)`; subscribe + `Terminal.DataReceived` → `IPtyConnection.WriterStream`; mirror + `Terminal.Resized` ↔ `IPtyConnection.Resize(cols, rows)`. +- Implement our **own** exit-code / kill / wait-for-exit against our + `IPtyConnection` — do NOT touch `TerminalControl.ExitCode`/`Pid`/`Kill()`/ + `WaitForExit()`, they NRE on the null `_ptyConnection`. + +Note on environment: `Porta.Pty.SpawnAsync` already seeds the child from the +current (ClaudeDo) process environment (PATH/APPDATA/etc.) and merges +`PtyOptions.Environment` on top — so we only need to ADD our custom vars (MCP +config path, `MAX_THINKING_TOKENS`, …), not rebuild the whole environment. (The +earlier spike's "child gets zero env vars" claim was wrong.) ### Command Center layout @@ -108,10 +130,11 @@ UI: ## 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). +Resolved: env approach (see Terminal host control — add custom vars on top of the +inherited process env via `PtyOptions.Environment`); library + binding seam. + ## Non-goals - No screen-scraping of terminal output back into task status/diff/review.