@agi-fans/dsh-tui 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/lib/CHANGELOG.md +158 -1
  2. package/lib/chrome/box.d.ts +47 -16
  3. package/lib/chrome/box.js +172 -130
  4. package/lib/chrome/box.js.map +1 -1
  5. package/lib/chrome/code-highlight.d.ts +15 -0
  6. package/lib/chrome/code-highlight.js +60 -4
  7. package/lib/chrome/code-highlight.js.map +1 -1
  8. package/lib/chrome/command-output.d.ts +29 -2
  9. package/lib/chrome/command-output.js +100 -4
  10. package/lib/chrome/command-output.js.map +1 -1
  11. package/lib/chrome/main-screen-renderer.d.ts +16 -0
  12. package/lib/chrome/main-screen-renderer.js +53 -5
  13. package/lib/chrome/main-screen-renderer.js.map +1 -1
  14. package/lib/chrome/markdown.js +30 -10
  15. package/lib/chrome/markdown.js.map +1 -1
  16. package/lib/chrome/relative-time.d.ts +17 -0
  17. package/lib/chrome/relative-time.js +36 -0
  18. package/lib/chrome/relative-time.js.map +1 -1
  19. package/lib/chrome/secret-mask.d.ts +35 -0
  20. package/lib/chrome/secret-mask.js +180 -0
  21. package/lib/chrome/secret-mask.js.map +1 -0
  22. package/lib/chrome/status-config.d.ts +161 -51
  23. package/lib/chrome/status-config.js +237 -126
  24. package/lib/chrome/status-config.js.map +1 -1
  25. package/lib/chrome/status-line.d.ts +3 -2
  26. package/lib/chrome/status-line.js +105 -63
  27. package/lib/chrome/status-line.js.map +1 -1
  28. package/lib/chrome/terminal-colors.d.ts +85 -0
  29. package/lib/chrome/terminal-colors.js +230 -0
  30. package/lib/chrome/terminal-colors.js.map +1 -0
  31. package/lib/chrome/terminal-images.d.ts +9 -1
  32. package/lib/chrome/terminal-images.js +27 -4
  33. package/lib/chrome/terminal-images.js.map +1 -1
  34. package/lib/chrome/theme.d.ts +32 -9
  35. package/lib/chrome/theme.js +595 -498
  36. package/lib/chrome/theme.js.map +1 -1
  37. package/lib/chrome/tool-renderers.js +69 -13
  38. package/lib/chrome/tool-renderers.js.map +1 -1
  39. package/lib/chrome/tools-list.d.ts +1 -4
  40. package/lib/chrome/tools-list.js +1 -41
  41. package/lib/chrome/tools-list.js.map +1 -1
  42. package/lib/chrome/welcome-tips.d.ts +20 -8
  43. package/lib/chrome/welcome-tips.js +22 -42
  44. package/lib/chrome/welcome-tips.js.map +1 -1
  45. package/lib/commands/auth-ids.d.ts +25 -0
  46. package/lib/commands/auth-ids.js +27 -0
  47. package/lib/commands/auth-ids.js.map +1 -0
  48. package/lib/commands/auth-input.d.ts +34 -0
  49. package/lib/commands/auth-input.js +96 -0
  50. package/lib/commands/auth-input.js.map +1 -0
  51. package/lib/commands/auth-providers.d.ts +39 -0
  52. package/lib/commands/auth-providers.js +125 -0
  53. package/lib/commands/auth-providers.js.map +1 -0
  54. package/lib/commands/auth.d.ts +12 -20
  55. package/lib/commands/auth.js +42 -229
  56. package/lib/commands/auth.js.map +1 -1
  57. package/lib/commands/btw.d.ts +13 -1
  58. package/lib/commands/btw.js +37 -104
  59. package/lib/commands/btw.js.map +1 -1
  60. package/lib/commands/diff.js +1 -96
  61. package/lib/commands/diff.js.map +1 -1
  62. package/lib/commands/export.d.ts +1 -1
  63. package/lib/commands/export.js +3 -27
  64. package/lib/commands/export.js.map +1 -1
  65. package/lib/commands/files.d.ts +17 -1
  66. package/lib/commands/files.js +67 -107
  67. package/lib/commands/files.js.map +1 -1
  68. package/lib/commands/jobs.d.ts +19 -4
  69. package/lib/commands/jobs.js +50 -7
  70. package/lib/commands/jobs.js.map +1 -1
  71. package/lib/commands/model.js +108 -76
  72. package/lib/commands/model.js.map +1 -1
  73. package/lib/commands/permission.js +15 -16
  74. package/lib/commands/permission.js.map +1 -1
  75. package/lib/commands/plugins.js +133 -16
  76. package/lib/commands/plugins.js.map +1 -1
  77. package/lib/commands/schedule.d.ts +10 -0
  78. package/lib/commands/schedule.js +45 -14
  79. package/lib/commands/schedule.js.map +1 -1
  80. package/lib/commands/session-configuration.js +2 -10
  81. package/lib/commands/session-configuration.js.map +1 -1
  82. package/lib/commands/session.js +14 -38
  83. package/lib/commands/session.js.map +1 -1
  84. package/lib/commands/terminal.d.ts +14 -8
  85. package/lib/commands/terminal.js +19 -178
  86. package/lib/commands/terminal.js.map +1 -1
  87. package/lib/commands/trajectory.js +4 -1
  88. package/lib/commands/trajectory.js.map +1 -1
  89. package/lib/definition.d.ts +122 -22
  90. package/lib/definition.js.map +1 -1
  91. package/lib/index.d.ts +1 -0
  92. package/lib/index.js +1 -0
  93. package/lib/index.js.map +1 -1
  94. package/lib/input/actions.d.ts +51 -0
  95. package/lib/input/actions.js +120 -0
  96. package/lib/input/actions.js.map +1 -0
  97. package/lib/input/editor.d.ts +0 -10
  98. package/lib/input/editor.js +11 -9
  99. package/lib/input/editor.js.map +1 -1
  100. package/lib/input/image-paste.d.ts +19 -1
  101. package/lib/input/image-paste.js +82 -1
  102. package/lib/input/image-paste.js.map +1 -1
  103. package/lib/input/keybindings-config.d.ts +12 -5
  104. package/lib/input/keybindings-config.js +30 -57
  105. package/lib/input/keybindings-config.js.map +1 -1
  106. package/lib/input/keys.d.ts +16 -0
  107. package/lib/input/keys.js +38 -3
  108. package/lib/input/keys.js.map +1 -1
  109. package/lib/input/wheel-scroll.d.ts +46 -0
  110. package/lib/input/wheel-scroll.js +69 -0
  111. package/lib/input/wheel-scroll.js.map +1 -0
  112. package/lib/prompt-intents.d.ts +182 -0
  113. package/lib/prompt-intents.js +127 -0
  114. package/lib/prompt-intents.js.map +1 -0
  115. package/lib/runtime/cancellable.d.ts +75 -0
  116. package/lib/runtime/cancellable.js +76 -0
  117. package/lib/runtime/cancellable.js.map +1 -0
  118. package/lib/runtime/composer-images.js +5 -4
  119. package/lib/runtime/composer-images.js.map +1 -1
  120. package/lib/runtime/composer-shell.d.ts +17 -2
  121. package/lib/runtime/composer-shell.js +109 -43
  122. package/lib/runtime/composer-shell.js.map +1 -1
  123. package/lib/runtime/file-recovery-review.d.ts +0 -1
  124. package/lib/runtime/file-recovery-review.js +29 -30
  125. package/lib/runtime/file-recovery-review.js.map +1 -1
  126. package/lib/runtime/file-recovery-store.js +5 -1
  127. package/lib/runtime/file-recovery-store.js.map +1 -1
  128. package/lib/runtime/file-review.js +1 -1
  129. package/lib/runtime/file-review.js.map +1 -1
  130. package/lib/runtime/hook-settings.d.ts +2 -2
  131. package/lib/runtime/plain-tui.d.ts +2 -0
  132. package/lib/runtime/plain-tui.js +7 -1
  133. package/lib/runtime/plain-tui.js.map +1 -1
  134. package/lib/runtime/plugin-settings.d.ts +1 -1
  135. package/lib/runtime/plugin-settings.js +10 -8
  136. package/lib/runtime/plugin-settings.js.map +1 -1
  137. package/lib/runtime/provider-local.d.ts +57 -15
  138. package/lib/runtime/provider-local.js +1112 -471
  139. package/lib/runtime/provider-local.js.map +1 -1
  140. package/lib/runtime/runner.js +5 -11
  141. package/lib/runtime/runner.js.map +1 -1
  142. package/lib/runtime/settings-preferences.js +1 -1
  143. package/lib/runtime/settings-preferences.js.map +1 -1
  144. package/lib/runtime/startup-notices.js +2 -0
  145. package/lib/runtime/startup-notices.js.map +1 -1
  146. package/lib/runtime/terminal-modes.d.ts +47 -0
  147. package/lib/runtime/terminal-modes.js +86 -0
  148. package/lib/runtime/terminal-modes.js.map +1 -0
  149. package/lib/runtime/terminal-notifications.d.ts +3 -5
  150. package/lib/runtime/terminal-notifications.js +4 -8
  151. package/lib/runtime/terminal-notifications.js.map +1 -1
  152. package/lib/runtime/terminal-probe.d.ts +36 -0
  153. package/lib/runtime/terminal-probe.js +37 -0
  154. package/lib/runtime/terminal-probe.js.map +1 -0
  155. package/lib/runtime/terminal-session.d.ts +57 -0
  156. package/lib/runtime/terminal-session.js +164 -0
  157. package/lib/runtime/terminal-session.js.map +1 -0
  158. package/lib/session/interaction-adapter.js +7 -8
  159. package/lib/session/interaction-adapter.js.map +1 -1
  160. package/lib/session/message-queue.js +1 -1
  161. package/lib/session/message-queue.js.map +1 -1
  162. package/lib/session/package-metadata.d.ts +8 -0
  163. package/lib/session/package-metadata.js +8 -0
  164. package/lib/session/package-metadata.js.map +1 -1
  165. package/lib/session/session-controller.d.ts +10 -11
  166. package/lib/session/session-controller.js +95 -13
  167. package/lib/session/session-controller.js.map +1 -1
  168. package/lib/session/session-tree.d.ts +2 -0
  169. package/lib/session/session-tree.js +2 -0
  170. package/lib/session/session-tree.js.map +1 -1
  171. package/lib/session/tui-settings.d.ts +40 -11
  172. package/lib/session/tui-settings.js +73 -34
  173. package/lib/session/tui-settings.js.map +1 -1
  174. package/lib/views/autocomplete.d.ts +18 -2
  175. package/lib/views/autocomplete.js +51 -38
  176. package/lib/views/autocomplete.js.map +1 -1
  177. package/lib/views/copy-targets.d.ts +12 -13
  178. package/lib/views/copy-targets.js +16 -46
  179. package/lib/views/copy-targets.js.map +1 -1
  180. package/lib/views/document-reader.js +18 -5
  181. package/lib/views/document-reader.js.map +1 -1
  182. package/lib/views/event-views.js +42 -6
  183. package/lib/views/event-views.js.map +1 -1
  184. package/lib/views/history-search.js +15 -21
  185. package/lib/views/history-search.js.map +1 -1
  186. package/lib/views/hotkeys.d.ts +7 -1
  187. package/lib/views/hotkeys.js +49 -25
  188. package/lib/views/hotkeys.js.map +1 -1
  189. package/lib/views/list-navigation.d.ts +62 -0
  190. package/lib/views/list-navigation.js +73 -0
  191. package/lib/views/list-navigation.js.map +1 -0
  192. package/lib/views/list-view.d.ts +99 -0
  193. package/lib/views/list-view.js +165 -0
  194. package/lib/views/list-view.js.map +1 -0
  195. package/lib/views/prompt-selector.d.ts +31 -3
  196. package/lib/views/prompt-selector.js +249 -125
  197. package/lib/views/prompt-selector.js.map +1 -1
  198. package/lib/views/session-files.d.ts +1 -2
  199. package/lib/views/session-files.js +1 -11
  200. package/lib/views/session-files.js.map +1 -1
  201. package/lib/views/settings-list.d.ts +10 -8
  202. package/lib/views/settings-list.js +116 -283
  203. package/lib/views/settings-list.js.map +1 -1
  204. package/lib/views/trajectory-timeline.d.ts +72 -0
  205. package/lib/views/trajectory-timeline.js +133 -0
  206. package/lib/views/trajectory-timeline.js.map +1 -0
  207. package/lib/views/trajectory.d.ts +15 -4
  208. package/lib/views/trajectory.js +557 -123
  209. package/lib/views/trajectory.js.map +1 -1
  210. package/lib/views/transcript-render.d.ts +95 -25
  211. package/lib/views/transcript-render.js +501 -167
  212. package/lib/views/transcript-render.js.map +1 -1
  213. package/lib/views/transcript-search.d.ts +39 -6
  214. package/lib/views/transcript-search.js +46 -11
  215. package/lib/views/transcript-search.js.map +1 -1
  216. package/lib/views/transcript-types.d.ts +63 -5
  217. package/lib/views/transcript-types.js +23 -11
  218. package/lib/views/transcript-types.js.map +1 -1
  219. package/package.json +67 -86
  220. package/lib/commands/advisor.d.ts +0 -15
  221. package/lib/commands/advisor.js +0 -200
  222. package/lib/commands/advisor.js.map +0 -1
  223. package/lib/commands/loop.d.ts +0 -52
  224. package/lib/commands/loop.js +0 -307
  225. package/lib/commands/loop.js.map +0 -1
  226. package/lib/commands/rate.d.ts +0 -33
  227. package/lib/commands/rate.js +0 -212
  228. package/lib/commands/rate.js.map +0 -1
  229. package/lib/commands/steer.d.ts +0 -5
  230. package/lib/commands/steer.js +0 -24
  231. package/lib/commands/steer.js.map +0 -1
  232. package/lib/commands/worktree.d.ts +0 -5
  233. package/lib/commands/worktree.js +0 -103
  234. package/lib/commands/worktree.js.map +0 -1
  235. package/lib/runtime/terminal-reader.d.ts +0 -11
  236. package/lib/runtime/terminal-reader.js +0 -87
  237. package/lib/runtime/terminal-reader.js.map +0 -1
  238. package/lib/views/agent-hub.d.ts +0 -32
  239. package/lib/views/agent-hub.js +0 -209
  240. package/lib/views/agent-hub.js.map +0 -1
  241. package/lib/views/copy-selector.d.ts +0 -54
  242. package/lib/views/copy-selector.js +0 -170
  243. package/lib/views/copy-selector.js.map +0 -1
package/lib/CHANGELOG.md CHANGED
@@ -6,6 +6,162 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.22.0] - 2026-10-31
10
+
11
+ ### Added
12
+
13
+ - `previewFormat` on a prompt option, and `disabled` on a row. The first ends a real ambiguity: the same `preview` field was rendered as markdown by the tree page and as plain text by the composer card, so an option read differently depending on which surface opened it — markdown is now opt-in and plain is the only default. The second is for a row that groups others: focusable, dimmed, and carrying no answer, so Enter on it stays put instead of closing the surface with a value nobody chose.
14
+
15
+ - Reaching a `/trajectory` detail pane no longer costs the scroll: `↑`/`↓` and the mouse wheel scroll the open pane instead of moving the record selection under the reader.
16
+
17
+ - `/trajectory` opens with a timing overview: one bar per lane — model, tools, other — showing where the wall clock went, with each lane's share and duration. The numbers were already in the ledger, but a reader asking why a turn took sixteen minutes had to open each record and add them up. It is a fixed-width bar rather than the desktop client's draggable timeline, because the useful reading is a proportion and a proportion needs no interaction; the span is the recorded activity, not the session wall clock, so idle time between turns cannot shrink every lane.
18
+
19
+ - Four named prompt intents — `ask`, `choose`, `confirm`, and `read` — alongside the existing `prompt` service. `TuiPrompt` had grown to forty-six optional fields, so every new surface added one: a caller wanting free text had to know that omitting `options` means input and that `allowCustom: false` is what makes a list non-editable. The intents are measured from the 196 existing call sites (109 free text, 45 lists, 14 document readers) and compile to the same request, so the escape hatch stays for the surfaces that genuinely combine several. Call sites migrate as they are touched: 28 so far (worktree, attach, session search and labels, reminders, credentials, access selection, code review, plugin management).
20
+
21
+ - `Alt+Enter` queues the composer draft behind the running turn, and `Alt+Up` recalls the latest queued message for editing. `Enter` keeps meaning "next turn".
22
+
23
+ - `Ctrl+L` opens model and reasoning selection, `Shift+Tab` cycles the reasoning effort, and `Ctrl+T` shows or hides thinking across the transcript. Thinking is visible by default and collapses to a one-line `Thinking: …` summary that keeps its first line.
24
+
25
+ - `Ctrl+Shift+F` searches the current transcript. `Ctrl+F` still does when the composer is empty and keeps moving the caret when it is not.
26
+
27
+ - `Ctrl+G` edits the prompt in the configured editor, alongside the existing `Ctrl+X`.
28
+
29
+ - A `system` theme derives its surfaces and text color from the colors the terminal reports about itself, so the TUI sits on the terminal's own background and follows a light terminal. It is selectable in Settings; `dark` stays the default. On terminals that support color-scheme notifications, `system` also follows a light/dark switch mid-session.
30
+
31
+ - On terminals that support the Kitty keyboard protocol, omdsh enables unambiguous key reporting so `Alt` and `Ctrl` shortcuts are recognized reliably, including inside full-screen overlays.
32
+
33
+ - The composer's activity reports a pending provider retry (`Retrying in 4s`) and how long a compaction has been running.
34
+
35
+ - `Alt+M` opens the newest image in the conversation — a pasted attachment or a `read_image` result — in the full-screen preview when the composer has no draft image.
36
+
37
+ - Inline image detection recognizes Herdr, Rex, Ghostty, WezTerm, Warp and iTerm2, `OMDSH_IMAGE_PROTOCOL=kitty|iterm2|none` overrides detection, and `omdsh doctor` reports the detected protocol.
38
+
39
+ ### Changed
40
+
41
+ - `/trajectory` now reads as three levels — turn, step, record — the shape the desktop client settled on, instead of one flat list. A turn rule states how many steps it folded and how long it took, a step header marks one model request and lists the tools a folded `c` hid, and each record ends with what it cost: `12.4K→812` and `4.3s` for a model request, duration for everything else. The `T1·1` location column is gone, since the headers now say where a row is.
42
+
43
+ - The ledger header states turns, steps and wall time instead of `12 records · 6 requests · 9 calls`, and counts errors and warnings only when there are some.
44
+
45
+ - The timing overview appears once a run has more than one step, and hides while searching. Two rows restating the single request below them was the chrome this view exists to replace.
46
+
47
+ - A record's detail section list is derived from the record: only sections with content are offered, so `Tab` no longer steps through `No tool schema recorded.`. The reader's last section is remembered and restored when returning to that record, and the active one is marked with `›` so it stays identifiable on a terminal without colour.
48
+
49
+ - Detail sections are drawn for what they hold instead of everything being printed as code. Facts are label/value rows, a model's answer and a user's message are rendered as Markdown — its reasoning under a `Thinking` label, its answer under `Answer` — and payloads and tool results stay code with syntax highlighting. Timing and token usage moved from their own section into the summary, where a reader looks first.
50
+
51
+ - Code in the detail pane is numbered only once a line is too long for the pane, and the numbers count source lines: a wrapped continuation leaves the column blank instead of claiming to be another line.
52
+
53
+ - Record durations use the status line's precision, so the overview can no longer read `0s` beside a row that says `0.4s`.
54
+
55
+ - `c` folds the tool calls inside every step, not only subtool calls.
56
+
57
+ - The Codex and Claude Code subagent bundles stay disabled until explicitly enabled, and the documentation now says why: the Codex bundle pins its own `@openai/codex` at 0.153.4, independent of the CLI on `PATH` and unchanged by any DSH release, and it has no human approval channel. Enabling an external agent is a deliberate act, not a default.
58
+
59
+ - The pinned DeepSeek Harness cohort moves from `0.2.1-rc.3` to `0.2.1-rc.5` across all 145 runtime packages, and the `examples/hello` fixture follows it. No API changes reached this codebase: typecheck, the full suite, and all three PTY smokes pass unchanged. The one real adjustment was the fixture itself — the compatibility check refused it while it still declared `rc.3`, which is the check doing its job.
60
+
61
+ - The `/copy` picker is the same composer card as every other list. It had been the last bespoke overlay with its own key model: nine hotkey rows of its own, and a filter that stayed inactive until `/` — so a typed letter did nothing and `Space` copied instead of typing a space. Typing filters now, `Enter` copies, and the selected row's payload is the preview.
62
+
63
+ - A finished `/btw` answer folds into the transcript when its pane closes, as one `/btw <question>` line with the answer behind `Ctrl+O`. Closing the pane used to be the only way to reclaim the screen height, and it cost the text; now the reader never has to choose. A consultation left before it answers records nothing, and the block is local presentation — the session log is untouched, so a resumed session does not carry it, exactly like any other command output.
64
+
65
+ - The Session Tree opens as a block above the composer instead of taking the whole screen. Double-Esc is a rewind gesture, and the conversation being rewound — the thing the reader needs to see while choosing a point in it — used to disappear behind the tree. It is bounded to a little over half the terminal, matching how pi mounts its tree selector. `Ctrl+↑`/`Ctrl+↓` now scroll the preview they always claimed to.
66
+
67
+ - `/btw <question>` asks at once and answers in its own pane docked above the composer, streaming as it arrives, scrolled with the arrow keys, and closed with Esc — which also stops the consultation instead of leaving it running unseen. The exchange belongs to a conversation that is not this one, so it occupies the pane rather than a row of the conversation being read, and closing it returns the session exactly as it was. A bare `/btw` prints `Usage: /btw <your question>` instead of opening a prompt: a second way to ask the same command would need learning as well. Gone with the pane are the topic library, the progress card, and the five-item menu.
68
+
69
+ - The finished `/btw` answer appears in the `/copy` picker as `Side answer`, with the question as its label. The pane is not a transcript row, so without this the answer could be read but not taken anywhere.
70
+
71
+ - `/help`, `/tools` and `/changelog` are transcript results again, and any command result longer than twelve rows folds behind one line with the rest on `Ctrl+O`. They had been moved into a reader to stop sixty rows landing in immutable scrollback; that traded one interruption for another, since the conversation disappeared while you looked something up. Folding keeps both: one line in the conversation, the whole page behind the key.
72
+
73
+ - Six more reports stopped opening a surface: saved recovery reports, the file-recovery result, integration status, session content search, approval-rule details, and agent composition. They print into the transcript and fold when long, so reading a status no longer covers the menu it was opened from.
74
+
75
+ - Approvals and plan review stay on the card that asks for the decision: the requested action, its reason, the exact matching rule and the plan itself are the card's detail, so the decision no longer sits behind a full-screen page. Scope confirmation for a remembered rule keeps its preview on the same card.
76
+
77
+ ### Removed
78
+
79
+ - The `@agi-fans/oh-my-dsh/advisor` export, which pointed at a module the advisor removal had already deleted, and an unreferenced launcher file left beside it. A published export that resolves to nothing is a crash for anyone who imports it.
80
+
81
+ ### Removed
82
+
83
+ - `TuiPrompt.presentation`'s `fullscreen-list` became `fullscreen-tree`'s sibling `card`. A list stopped taking the screen when the composer card learned to window its rows, filter by typing and preview the selected row, so the value described a behaviour it no longer had — in an API whose whole point is being readable at the call site.
84
+
85
+ - `TuiPrompt.optionLayout` and the `choose` intent's `fullscreen` and `spacious` options are gone. `optionLayout` was written in eight places and read in none; `fullscreen` and `spacious` only ever existed to set it, so their two branches could not do anything either.
86
+
87
+ - The Agent Hub is gone, and its one irreplaceable action moved into the subagent roster: `↓` on an empty composer selects a row, `↑`/`↓` moves, and `Enter` opens that child's transcript. The hub existed because it was the only trigger for `#openInspect` — a missing key binding, not a layout requirement — and paid for it with a full screen, its own nine-row key table, `Alt+A`, a `T` tree toggle and a wide/narrow two-pane layout. Everything it was the only view of now has a home: the roster is the list, an external child (which keeps no local transcript) prints its status and recent activity as a fold-able result, and recorded workflow runs appear as a line at the top of the roster.
88
+
89
+ - The advisor is gone: `consult_advisor`, `/advisor`, its Integrations setting, and the 810 lines that composed them. It reached the same ACP transport as a Codex or Claude Code subagent, but handed the second model only a question the primary agent wrote plus a context slice it chose — so the advisor answered from a summary of the problem rather than the problem. Claude Code's advisor reads the full conversation because it runs server-side; a local version would have to serialize that itself, at the cost of choosing what to drop. What it did uniquely — ask for an opinion without giving away the ability to act — stays reachable by delegating a read-only subagent instead.
90
+
91
+ - `/steer` and `/todo` are gone. Steering is `Alt+S` on the draft, which is the same handler without typing a six-character prefix; the todo list is already drawn live above the composer, and printing a copy into immutable scrollback produced a list that was stale the moment it appeared.
92
+
93
+ - `/copy text|code|cmd|output` lost its kinds. `text` meant "the default", so it was a no-op parameter, and the other three named a row the picker already shows with its content, language and size: the reader had to recall a word to skip a keystroke. `/copy` opens the picker; `Alt+C` still copies a selection when there is one.
94
+
95
+ - `/tree` is gone: double `Esc` already opened the same Session Tree controller, so the command was a second name for a gesture the shortcut list already documents. Reach it with `Esc` twice on an empty composer.
96
+
97
+ - `/review`. It resolved a Git target and injected a fixed prompt — the resolution was its only real work, and the prompt itself is something every reader who reviews code already has their own version of, either as a Skill or as habit. A fixed template cannot be better than the reader's own, and by the scope principle in `docs/design/philosophy.md` a capability whose need is not demonstrated is maintenance cost. `/diff` remains: it shows the changes, which is the part a terminal uniquely owns.
98
+
99
+ - `/rate` and the `dsh-message-feedback` service behind it. The feedback it recorded was log-only: nothing read it, exported it, or sent it anywhere, so a reader who filed a judgment took a four-step flow to write a record with no consumer. This is the scope principle in `docs/design/philosophy.md` applied — a capability with no path to being used is maintenance cost, not a feature.
100
+
101
+ - `Notifications → Terminal activity`, the opt-in OSC 9 busy/idle indicator. It reported the same lifecycle as Terminal status through a weaker protocol that carried no state, and it cost a keepalive write on every second of a running turn. A terminal tab that answers OSC 7501 already shows what omdsh is doing.
102
+
103
+ - `/attachments`. `/attach` without a path now opens the same list with an **Add a file** entry at the top, so reviewing what this session attached and attaching something new are one surface rather than two commands to keep apart. A `/attach <path>` invocation and a bare `/attach` in a pipe both behave as before.
104
+
105
+ ### Fixed
106
+
107
+ - `verbose` gives the session's totals a third footer line — Time on the left, Activity on the right — so the line above it no longer has to shed them on a narrow terminal. The line appears only once the line above is whole: priority is still global, so nothing below a dropped latency appears above it.
108
+
109
+ - Turning Telemetry off now reclaims its rows instead of leaving them blank; a session without projected stats yet keeps the reserved line, so the composer does not step up when the first numbers arrive.
110
+
111
+ - The status footer puts occupancy back on the left and cost on the right. `Ctx` and `Cache` hold the left edge; Tokens, Latency, Time and Activity answer from the right, so the same number sits in the same place from session to session instead of the whole row running from the left margin.
112
+
113
+ - The densities are cumulative again. `minimal` is occupancy (Context and Cache), `standard` adds latency (`TTFT · tok/s`), and `verbose` adds Tokens, Time and Activity with long labels and the detailed context form. On a narrow terminal the visible set is now a prefix of that order: Activity goes before Time, and Time before Latency, rather than a wider group being skipped so a narrower one behind it could fit.
114
+
115
+ - `Space` on a footer part no longer changes a different part's behaviour. Toggling one took the rendered footer and stored everything it did not show as an explicit hiding, so afterwards `verbose` showed exactly what `standard` had — one switch silently freezing another. Hiding is now a delta from the density, and adding a part the density omits is its own delta, so `Space` on a part the density leaves out finally does something.
116
+
117
+ - A footer switch no longer flips back on its own. The preferences handed to the settings rows carried the density alone, so any session refresh that reseeded the overlay — which happens on every projection update — redrew the parts the reader had just hidden as `shown`. The document now travels whole, deltas included.
118
+
119
+ - The `Path` row in Settings is labelled `Path` again instead of printing its own description at full width across the row.
120
+
121
+ - Diff line numbers no longer step sideways down a hunk. The gutter carried the old and the new number in two sub-columns, so a removal printed its number in the left one and the addition under it in the right one; with one digit each that read as a rendering fault. Each row now states one number on one column — the side it belongs to.
122
+
123
+ - A step's duration stays on its own line. The padding was counted in string length, so a CJK step label — one character, two cells — pushed the duration onto the next row.
124
+
125
+ - The Session Tree page draws each option's description and its badge in the option's own tone. Both were dropped when tree rows moved onto this renderer, so a full-screen tree lost an agent's phase colour and its elapsed time — the two things that tell two similar-looking nodes apart.
126
+
127
+ - A filterable card now draws the query it is filtering on, with what it kept (`⌕ build · 1/1`); a query that matches nothing says so and stops advertising `Enter`; a truncated preview ends with `… N more lines`; and `Esc` clears an active filter before it closes the list, which only the session tree used to do. All four were lost when lists stopped being full-screen pages — the page printed the query, the empty state and the paged preview, and the card did not.
128
+
129
+ - A run the reader stops stays open instead of folding under them. Interrupting is an action taken while watching that work, so collapsing it at that moment took the rows out from under the reader — and, because a fold shortens the document, left the live viewport starting inside rows already committed to native history. Those rows cannot be repainted, so the screen began with a band of empty rows and, when the boundary landed inside the startup header, a `Tips:` line with no logo above it. The run now keeps its rows until the next submission, which is the point at which the reader has moved on; a turn that ended on its own conclusion still folds immediately, because its summary describes something that finished.
130
+
131
+ - A short conversation sits next to the composer instead of the top of the screen, and the header stays where it is. The slack now lives between the header and the conversation: a fold shortens the conversation into that slack, so neither the header nor the newest rows move. The first attempt put the slack above the whole frame, which kept the newest rows still but dragged the header to the bottom the moment a message arrived. The transcript used to hug the top and leave its spare rows between the last line and the composer, so folding a run — which shortens the transcript — opened a wide gap in the middle of the screen and shifted nothing the reader was actually looking at. The spare rows are now above the document, which keeps the newest rows where they were when something above them folds. A session with no conversation yet still opens with the header at the top, because with nothing to anchor to the composer the header is the first thing to read.
132
+
133
+ - A successful tool card on the `system` theme no longer turns pale green. Its fill was a fixed-weight mix of the terminal's own green into the background, so the card's lightness was the terminal's choice: a terminal reporting a bright green produced a fill at 11.7% relative luminance instead of the shipped 4.4%, and dimmed text on it fell to 3.33:1. The three state fills are now held at a target luminance and take only their hue from the terminal, capped so a card stays a surface rather than a swatch. On the same terminal the successful fill lands at 4.48% with every card ink at or above 4.6:1.
134
+
135
+ - The pending card on the `system` theme was the lightest of the three, inverting the state order. It is now the quietest fill, and it keeps the background's own tint instead of flattening to the foreground's grey.
136
+
137
+ - A `system` theme on a light terminal no longer washes out its secondary text. `dim` and `muted` were mixed from the foreground toward the background at a fixed weight, which brightens the ink on a dark host but fades it toward the page on paper: `dim` on a light terminal's cards measured 1.75:1, and on a white one 1.64:1. `dim` is now solved against the card fills it is actually drawn on, reproducing the hierarchy the shipped palettes reached (3.64:1 on light where they reach 3.59:1, 3.30:1 on dark where they reach 3.30:1). `muted` simply inherits the palette's swatch, which both shipped themes already set equal to `toolOutput`.
138
+
139
+ - A `system` theme keeps its card fills light on a light terminal, and the alternating successful surface is a slight step above the primary one instead of jumping to a brightness no card should reach.
140
+
141
+ - A running turn keeps the access level on the composer's right corner. The activity row was assembled from `fillWidth + 4`, a constant left over from the four-cell corner pair this composer no longer draws, so every running frame was one cell too wide; the renderer truncated the overflow, which is the right-hand rule, and the badge printed as `workspace write…`. The frame is now measured from the pieces it actually prints.
142
+
143
+ - A `!` command's card shows only what that line produced and carries a state fill. It used to render the whole persistent-shell scrollback, so the command's own echo appeared a second time under the `$ command` header, output from earlier `!` lines was replayed, and the trailing prompt the shell paints after every line stayed in the card. The card now projects from a line-count baseline taken before the command is sent, drops the trailing prompt, and uses the composer's Shell ink with the pending/success/failure fills a tool card uses.
144
+
145
+ - The `@` mention menu no longer flashes while typing or deleting. Every keystroke cleared it because its search is debounced, so the list vanished for the whole debounce-plus-search interval and reappeared afterwards. The rows already on screen describe the token being extended, so they now stay until a real result replaces them.
146
+
147
+ - A wrapped line keeps its style on every row. `wrapText` attached escape sequences to the following glyph but never reopened them after a line break, so a long bold command showed its ink on the first row and plain text on the rest. Every painted wrap now uses the restabilizing variant, which tracks the active foreground, weight, slant, underline, inverse, and hyperlink across the break.
148
+
149
+ - A tool card now shows its state on every terminal, not only on a truecolor one. Pending, successful, and failed cards had three near-black fills that 256-color and 16-color terminals quantized onto the same entry, so a failed call looked exactly like a successful one. The three fills are resolved as a group now, and the failing card keeps a fill of its own.
150
+
151
+ - A tool card's output is syntax highlighted, and its command line is not. The command stays one bold ink so the reader recognizes their own intent at a glance; the colour belongs to the output they actually have to read. Output used to be coloured one line at a time, so a multi-line payload kept only its first row highlighted, and tokens the highlighter had no colour for fell back to the terminal's default ink, which made a highlighted block read as mostly plain text. Both are fixed: the payload is highlighted as one block, and every token is painted.
152
+
153
+ - A Markdown heading's level is visible again: `#` and `##` carry weight and an underline, deeper levels keep their marker. Block quotes and horizontal rules use their own `mdQuoteBorder` and `mdHr` inks instead of borrowing the component border colour, and quoted prose is set in italic.
154
+
155
+ - Image preview and the Harness attachment store load the same `sharp`, so a duplicate libvips warning no longer appears in the middle of the screen.
156
+
157
+ - Terminal replies that arrive together no longer leak fragments such as `[?62;22c` into the composer, and an unrecognized control sequence is discarded whole.
158
+
159
+ - A background job's settlement line is separated from the command output by a blank row.
160
+
161
+ - Every terminal mode omdsh enables — bracketed paste, focus and mouse reporting, and the keyboard protocol — is given back while `Ctrl+Z` or an external editor owns the terminal, and when the process exits without shutting down cleanly, so the shell and the editor receive their usual input.
162
+
163
+ - Closing the terminal window shuts omdsh down cleanly — the session is saved and terminal handlers run — instead of the process being killed by SIGHUP.
164
+
9
165
  ## [0.21.0] - 2026-10-19
10
166
 
11
167
  ### Added
@@ -629,7 +785,8 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic
629
785
  - Preserved terminal-cell alignment and right padding for long commands, CJK text, emoji, ANSI styling, and narrow viewports.
630
786
  - Stabilized incremental rendering, transcript scrolling, cursor placement, tool-output folding, and queued input during active turns.
631
787
 
632
- [Unreleased]: https://github.com/agi-fans/oh-my-dsh/compare/v0.21.0...HEAD
788
+ [Unreleased]: https://github.com/agi-fans/oh-my-dsh/compare/v0.22.0...HEAD
789
+ [0.22.0]: https://github.com/agi-fans/oh-my-dsh/compare/v0.21.0...v0.22.0
633
790
  [0.21.0]: https://github.com/agi-fans/oh-my-dsh/compare/v0.20.0...v0.21.0
634
791
  [0.20.0]: https://github.com/agi-fans/oh-my-dsh/compare/v0.19.0...v0.20.0
635
792
  [0.19.0]: https://github.com/agi-fans/oh-my-dsh/compare/v0.18.0...v0.19.0
@@ -4,8 +4,7 @@
4
4
  * @module @agi-fans/dsh-tui
5
5
  */
6
6
  import { type Theme, type ThemeColor } from './theme.ts';
7
- import type { MotionMode } from '../session/tui-settings.ts';
8
- import { type WelcomeTip } from './welcome-tips.ts';
7
+ import { type WelcomeHint } from './welcome-tips.ts';
9
8
  /** Visual state that drives border + fill color. */
10
9
  export type BoxState = 'idle' | 'info' | 'running' | 'ok' | 'error' | 'warning';
11
10
  /** Options for a rounded output block (tool / notice). */
@@ -28,25 +27,32 @@ export interface FramedBlockOptions {
28
27
  * OMP `renderOutputBlock`: `╭─── header ────╮` / padded body / `╰────╯`.
29
28
  */
30
29
  export declare function renderFramedBlock(options: FramedBlockOptions, theme: Theme): string[];
31
- /** Welcome card inputs. */
30
+ /** Header inputs. */
32
31
  export interface WelcomeOptions {
33
32
  width: number;
34
- model: string;
35
- /** Effective reasoning effort for the selected model, painted under the model name. */
33
+ /** Kept for callers that already resolve it; the compact header does not print it. */
34
+ model?: string;
35
+ /** Kept for callers that already resolve it; the compact header does not print it. */
36
36
  reasoningEffort?: string;
37
37
  version: string;
38
38
  appName: string;
39
- recentSessions?: readonly {
40
- id: string;
41
- title: string;
42
- createdAt: number;
43
- updatedAt?: number;
44
- }[];
45
- /** Per-process hint sample; defaults to a deterministic catalog prefix for pure callers. */
46
- tips?: readonly WelcomeTip[];
39
+ /** Startup hints; defaults to every entry in the shipped catalog. */
40
+ hints?: readonly WelcomeHint[];
47
41
  }
48
42
  /**
49
- * Two-column welcome card: gradient DeepSeek logo + tips, titled `app vversion`.
43
+ * Startup header: the DeepSeek mark beside the name, its version, and the
44
+ * slogan, then one sampled hint.
45
+ *
46
+ * It is a lockup rather than a card. The previous header was a thirteen-row
47
+ * bordered panel with a tips table, a recent-session list, and a second copy of
48
+ * the model and effort the status footer already shows — most of a screen spent
49
+ * before the reader has typed anything, and its rows were committed to native
50
+ * scrollback where they stay. Nothing here repeats what the composer and footer
51
+ * already say.
52
+ *
53
+ * The mark is the brand, so it stays at its source aspect ratio; below the width
54
+ * that holds the lockup, the wordmark folds underneath rather than the mark
55
+ * shrinking or the slogan being dropped.
50
56
  */
51
57
  export declare function renderWelcome(options: WelcomeOptions, theme: Theme): string[];
52
58
  /** Editor chrome inputs. */
@@ -58,11 +64,38 @@ export interface EditorOptions {
58
64
  /** Optional right-aligned cap on the top border (permission mode). */
59
65
  statusRight?: string;
60
66
  border: ThemeColor;
67
+ /**
68
+ * Activity drawn in the top border instead of as a row above the editor.
69
+ *
70
+ * The composer is where the reader is looking while they wait, so a spinner
71
+ * that sits on its own row above the box costs a line and reads as a separate
72
+ * component. `label` is empty only when the caller wants the spinner alone,
73
+ * which is what a narrow terminal degrades to.
74
+ */
75
+ activity?: EditorActivity;
76
+ /** Animation frame, forwarded to the activity's shimmer when it has one. */
77
+ spinnerFrame?: number;
78
+ /**
79
+ * One line of confirmation drawn in the bottom border.
80
+ *
81
+ * Replaced rather than appended: what a key just did is a reading of the last
82
+ * action, not a record of the conversation, so it belongs to the frame that
83
+ * is already on screen.
84
+ */
85
+ note?: string;
61
86
  /** Dim ghost text painted after the caret (slash-arg hint). */
62
87
  inlineHint?: string;
63
88
  /** Paint one wrapped input slice without changing its visible width. */
64
89
  paintInput?: (text: string, sourceStart: number) => string;
65
90
  }
91
+ /** One in-flight activity shown in the composer's top border. */
92
+ export interface EditorActivity {
93
+ /** Spinner frame, already resolved by the caller; `-1` stops the animation. */
94
+ readonly frame: string;
95
+ readonly label: string;
96
+ /** Whether the label is painted with the driving shimmer. */
97
+ readonly shimmer?: boolean;
98
+ }
66
99
  /** Editor frame plus a cursor offset relative to the editor's first row. */
67
100
  export interface EditorFrame {
68
101
  lines: string[];
@@ -78,5 +111,3 @@ export interface EditorFrame {
78
111
  export declare function renderEditor(options: EditorOptions, theme: Theme): EditorFrame;
79
112
  /** DeepSeek Harness-aligned label shown while the model is driving a turn. */
80
113
  export declare const DEEP_DRIVING_LABEL = "Deep Driving";
81
- /** Activity row that sits above the editor while a turn is in flight. */
82
- export declare function renderWorking(theme: Theme, spinnerFrame: number, action?: string, width?: number, motion?: MotionMode): string[];