Skip to content

feat(ui): slash-command and manual-shell routing in the full-screen app#14

Merged
lavindeep merged 1 commit into
ui-reworkfrom
feat/ui-slash-routing
Jun 28, 2026
Merged

feat(ui): slash-command and manual-shell routing in the full-screen app#14
lavindeep merged 1 commit into
ui-reworkfrom
feat/ui-slash-routing

Conversation

@lavindeep

Copy link
Copy Markdown
Owner

Branch 8 of the full-screen TUI rework (UI v2, design §31.17).

What

A typed /... or !... line is a harness control, not a model turn. The dock routes it to a SlashRouter (cli/app_slash.py) instead of the model. The router splits work by what would hang the loop (the invariant is "never hang", not "never run synchronous code"):

  • Loop thread + pane-capture — fast in-memory / small-local-file display commands (/help, /status, /context, /logs, /memory show, …) run against a capturing rich.Console; output rendered into the pane via AppUI.show_slash_output.
  • run_in_terminal (needs_terminal) — interactive / own-stdout commands (confirm(), cloud consent, /doctor, /model use preload) and the manual shell (!, /shell) suspend the app and use the real terminal.
  • Worker thread — model-invoking /plan revise (needs_worker, runs like a turn via TurnRunner.start_action, approvals via the §31.16 focus-swap gate) and blocking-network commands /model list / /attach <path> (needs_background, captured output marshaled to the pane). Neither can run on the loop thread (model call would deadlock the approval gate; a hung Ollama would freeze the TUI for the client timeout).

One SlashDispatcher drives all paths; the dispatch closure swaps its console + confirm per call, with a _decline loop-path confirm so a misclassified command can never block the loop. /exit stays a direct quit; a normal line still starts a turn. The default (non-app) REPL is untouched.

Tests

needs_terminal / needs_worker / needs_background classifiers (exhaustive); SlashRouter routing across all lanes with injected effects; AppUI.show_slash_output; and real-thread TurnRunner.start_action coverage (worker execution + marshaled busy-clear). Phase gate green: ruff + format clean, mypy --strict clean (80 files), 1417 passed.

Live validation (gemma4:31b-cloud)

/help + /status render in the pane; /model list runs its /api/tags call off-loop and renders the table in the pane (no freeze/flicker); /clear suspends → confirm → resumes; !ls runs the manual shell; a normal line still starts a model turn.

DESIGN §31.17 added.

…n app

A typed /... or !... line is a harness control, not a model turn. The dock
routes it to a SlashRouter instead of the model: fast display commands run on
the loop thread against a pane-capturing console (output rendered into the
pane); interactive/slow/own-stdout commands (confirm, cloud consent, /doctor,
/model use) and the manual shell suspend the app via run_in_terminal; and a
model-invoking /plan revise runs on the worker thread like a turn. needs_terminal
and needs_worker classify deterministically, with a _decline loop-path confirm
safety net so a misclassified command can never block the event loop.

Adds DESIGN section 31.17.
@lavindeep lavindeep merged commit dcbcd4b into ui-rework Jun 28, 2026
2 checks passed
@lavindeep lavindeep deleted the feat/ui-slash-routing branch June 28, 2026 10:37
lavindeep added a commit that referenced this pull request Jul 2, 2026
feat(ui): slash-command and manual-shell routing in the full-screen app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant