main
md 108 lines 5.16 KB
Rendered Raw
1 # siGit Code TUI features: tabs and thinking display
2
3 Status: shipped, pending merge (sigit #25 and #26, 2026-07-05). Owner: product/eng.
4 Audience: internal (private repo). Scope: the **siGit Code** interactive terminal
5 UI (`src/chat.rs`, Unix-only). These two features were built from direct requests
6 rather than the parity roadmaps; this document records their specs after the
7 fact so the behavior has a source of truth alongside
8 [sigit-code-parity-roadmap.md](sigit-code-parity-roadmap.md) and
9 [sigit-code-copilot-cli-parity.md](sigit-code-copilot-cli-parity.md).
10
11 ---
12
13 ## 1. Spec: tabbed TUI (sigit #25)
14
15 Inspired by GitHub Copilot CLI's June 2026 terminal redesign (Session, Gists,
16 Issues, and PR tabs switched with the Tab key).
17
18 ### Behavior
19
20 Three tabs, rendered as a bar at the top of the screen on every view:
21
22 - **Session** (default): the chat exactly as before, messages, input, footer.
23 - **History**: the saved sessions from the session store
24 (`$SIGIT_CONFIG_DIR/sessions/*.jsonl`), listed newest first with id, coarse
25 age ("2m ago"), and message count. Up/Down selects. Enter restores the
26 selected session into the live backend, pushes a system message saying how
27 many messages were restored, and returns to the Session tab. `d` starts a
28 delete; a second `d` on the same selection confirms, any other key cancels.
29 The pending delete is keyed by session id, not list index, so a refresh can
30 never redirect the confirmation. `r` refreshes. An empty store shows "No
31 saved sessions yet."
32 - **Cloud**: siGit Code Cloud status and settings. Shows the signed-in account,
33 on-device vs remote inference, current model and engine state, the Local
34 Inference setting, the permission policy summary, and the config dir. `l`
35 toggles Local Inference, with a note that the toggle takes effect at the next
36 model selection because the running backend is not swapped. `r` refreshes.
37
38 ### Interaction rules
39
40 - Tab cycles Session, History, Cloud. It only cycles when the input buffer is
41 empty, so pasted text containing tabs cannot hijack navigation; on non-Session
42 tabs the input is inactive so Tab always cycles. Esc on a non-Session tab
43 returns to Session.
44 - Inference keeps streaming while the user is on another tab. Restoring history
45 sits behind the busy gate so the conversation cannot be swapped mid-turn.
46 - A tool approval prompt arriving while on another tab auto-switches to the
47 Session tab: a y/a/n prompt must never be invisible.
48 - The Cloud status fetch runs as a spawned task feeding the render loop over a
49 oneshot, because `account::status_line()` can hit the network and must not
50 freeze rendering. A dead fetch degrades to "press r to retry".
51
52 ### Implementation notes
53
54 Pure logic (the tab cycle, age and row formatting, `session_store::list`) lives
55 outside the Unix-only `mod tui` behind the same cfg-gate pattern as
56 `permissions::TUI_SESSION`, so all four CI targets compile and unit-test it.
57
58 ---
59
60 ## 2. Spec: thinking display with `/thinking` (sigit #26)
61
62 Reasoning models (Qwen 3, DeepSeek-R1 distills) emit their thought process in
63 `<think>` tags. Before this feature the TUI hid reasoning behind the spinner
64 while streaming and then rendered it as an unconditional box on every finished
65 message. Both extremes were wrong: watching the model reason is useful, reading
66 every past thought is noise.
67
68 ### Behavior
69
70 - **While streaming**, if the turn is still inside its think block, the TUI
71 shows the last three wrapped lines of the reasoning live, dim italic, under
72 the thinking spinner. Once visible (non-think) text arrives, the reply
73 streams as before.
74 - **Finished replies** collapse the reasoning to a one-line dim indicator with
75 the line count, e.g. `· thought for a bit (12 lines), /thinking to show`.
76 - **`/thinking [on|off]`** (bare flips) expands the full reasoning block, dim
77 and visually separated, above each reply across the whole transcript, and
78 collapses it again when turned off.
79
80 ### Boundaries
81
82 - Display only. Nothing changes in what is sent to the model, what is saved to
83 the session store, or what goes over ACP, where reasoning stays stripped and
84 editors render their own thought UI. `/thinking` is TUI-only and not
85 advertised over ACP, the same precedent as `/resume`.
86 - Restored sessions re-split think blocks on entry, so `/resume` and the
87 History tab keep the indicator behavior.
88 - The TUI streams only when no tools are offered (on-device tool turns buffer
89 to detect tool calls), so the live tail appears exactly on the turns that can
90 stream, which are also the turns where think deltas exist.
91
92 ### Implementation notes
93
94 The live-tail extraction is a pure, width-aware function with its own greedy
95 word wrap (hard-splitting over-wide words), unit-tested without ratatui.
96
97 ---
98
99 ## 3. Follow-ups worth considering
100
101 - Copilot CLI's Issues and Pull requests tabs have a natural sigit equivalent
102 once the MCP repo workflow tools (sigit-si #3) are consumed by the client: a
103 fourth tab listing issues and PRs for the current repo when its origin points
104 at sigit.si.
105 - A persistent setting for the thinking toggle (settings.toml) if the
106 per-session default proves annoying.
107 - Coarse ages in the History tab could show absolute timestamps on a keypress
108 if precision is ever needed.