@sagmans/dsh-tui 0.6.0 → 0.8.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 (271) hide show
  1. package/.agents/skills/dsh-tui-dogfood/SKILL.md +83 -0
  2. package/.agents/skills/dsh-tui-dogfood/references/home-state.md +78 -0
  3. package/.agents/skills/dsh-tui-dogfood/scripts/clone-links.mjs +133 -0
  4. package/.agents/skills/dsh-tui-dogfood/scripts/run-plugin-from-worktree.sh +417 -0
  5. package/.agents/skills/dsh-tui-update-models/SKILL.md +199 -0
  6. package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +292 -0
  7. package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +314 -0
  8. package/README.md +154 -27
  9. package/lib/agent/present.d.ts.map +1 -1
  10. package/lib/agent/present.js +2 -1
  11. package/lib/agent/present.js.map +1 -1
  12. package/lib/cards/composition.d.ts +68 -0
  13. package/lib/cards/composition.d.ts.map +1 -0
  14. package/lib/cards/composition.js +117 -0
  15. package/lib/cards/composition.js.map +1 -0
  16. package/lib/cards/presenter.d.ts +23 -0
  17. package/lib/cards/presenter.d.ts.map +1 -0
  18. package/lib/cards/presenter.js +394 -0
  19. package/lib/cards/presenter.js.map +1 -0
  20. package/lib/cards/preview.d.ts +42 -0
  21. package/lib/cards/preview.d.ts.map +1 -0
  22. package/lib/cards/preview.js +51 -0
  23. package/lib/cards/preview.js.map +1 -0
  24. package/lib/cards.d.ts +12 -120
  25. package/lib/cards.d.ts.map +1 -1
  26. package/lib/cards.js +4 -556
  27. package/lib/cards.js.map +1 -1
  28. package/lib/compat/section.d.ts +29 -0
  29. package/lib/compat/section.d.ts.map +1 -0
  30. package/lib/compat/section.js +82 -0
  31. package/lib/compat/section.js.map +1 -0
  32. package/lib/config.d.ts +27 -2
  33. package/lib/config.d.ts.map +1 -1
  34. package/lib/config.js +61 -1
  35. package/lib/config.js.map +1 -1
  36. package/lib/contracts.d.ts +28 -0
  37. package/lib/contracts.d.ts.map +1 -1
  38. package/lib/fold-cursor.d.ts +8 -0
  39. package/lib/fold-cursor.d.ts.map +1 -1
  40. package/lib/fold-cursor.js +18 -0
  41. package/lib/fold-cursor.js.map +1 -1
  42. package/lib/gates/question-card.d.ts +77 -0
  43. package/lib/gates/question-card.d.ts.map +1 -0
  44. package/lib/gates/question-card.js +113 -0
  45. package/lib/gates/question-card.js.map +1 -0
  46. package/lib/gates/questions.d.ts +127 -0
  47. package/lib/gates/questions.d.ts.map +1 -0
  48. package/lib/gates/questions.js +418 -0
  49. package/lib/gates/questions.js.map +1 -0
  50. package/lib/gates.d.ts +1 -113
  51. package/lib/gates.d.ts.map +1 -1
  52. package/lib/gates.js +1 -484
  53. package/lib/gates.js.map +1 -1
  54. package/lib/herdr/client.d.ts +8 -0
  55. package/lib/herdr/client.d.ts.map +1 -1
  56. package/lib/herdr/client.js +13 -1
  57. package/lib/herdr/client.js.map +1 -1
  58. package/lib/herdr/constants.d.ts +18 -0
  59. package/lib/herdr/constants.d.ts.map +1 -1
  60. package/lib/herdr/constants.js +18 -0
  61. package/lib/herdr/constants.js.map +1 -1
  62. package/lib/herdr/reporter.d.ts +20 -4
  63. package/lib/herdr/reporter.d.ts.map +1 -1
  64. package/lib/herdr/reporter.js +70 -20
  65. package/lib/herdr/reporter.js.map +1 -1
  66. package/lib/herdr/state.d.ts +10 -0
  67. package/lib/herdr/state.d.ts.map +1 -1
  68. package/lib/herdr/state.js +21 -4
  69. package/lib/herdr/state.js.map +1 -1
  70. package/lib/index.d.ts +1 -0
  71. package/lib/index.d.ts.map +1 -1
  72. package/lib/index.js +348 -2602
  73. package/lib/index.js.map +1 -1
  74. package/lib/input/action-catalog.d.ts +74 -0
  75. package/lib/input/action-catalog.d.ts.map +1 -0
  76. package/lib/input/action-catalog.js +137 -0
  77. package/lib/input/action-catalog.js.map +1 -0
  78. package/lib/input/actions.d.ts +5 -81
  79. package/lib/input/actions.d.ts.map +1 -1
  80. package/lib/input/actions.js +4 -625
  81. package/lib/input/actions.js.map +1 -1
  82. package/lib/input/completion.d.ts +1 -1
  83. package/lib/input/completion.d.ts.map +1 -1
  84. package/lib/input/completion.js +2 -1
  85. package/lib/input/completion.js.map +1 -1
  86. package/lib/input/file-index.d.ts +40 -0
  87. package/lib/input/file-index.d.ts.map +1 -0
  88. package/lib/input/file-index.js +141 -0
  89. package/lib/input/file-index.js.map +1 -0
  90. package/lib/input/file-search.d.ts +1 -38
  91. package/lib/input/file-search.d.ts.map +1 -1
  92. package/lib/input/file-search.js +1 -487
  93. package/lib/input/file-search.js.map +1 -1
  94. package/lib/input/key-press.d.ts +57 -0
  95. package/lib/input/key-press.d.ts.map +1 -0
  96. package/lib/input/key-press.js +218 -0
  97. package/lib/input/key-press.js.map +1 -0
  98. package/lib/input/keymap-conflicts.d.ts +59 -0
  99. package/lib/input/keymap-conflicts.d.ts.map +1 -0
  100. package/lib/input/keymap-conflicts.js +292 -0
  101. package/lib/input/keymap-conflicts.js.map +1 -0
  102. package/lib/input/keymap-settings.js +1 -1
  103. package/lib/input/keymap-settings.js.map +1 -1
  104. package/lib/input/keymap.d.ts.map +1 -1
  105. package/lib/input/keymap.js +3 -1
  106. package/lib/input/keymap.js.map +1 -1
  107. package/lib/input/workspace-files.d.ts +10 -0
  108. package/lib/input/workspace-files.d.ts.map +1 -0
  109. package/lib/input/workspace-files.js +359 -0
  110. package/lib/input/workspace-files.js.map +1 -0
  111. package/lib/install-skills.d.ts +39 -0
  112. package/lib/install-skills.d.ts.map +1 -0
  113. package/lib/install-skills.js +273 -0
  114. package/lib/install-skills.js.map +1 -0
  115. package/lib/keys-command.d.ts +2 -1
  116. package/lib/keys-command.d.ts.map +1 -1
  117. package/lib/keys-command.js +2 -1
  118. package/lib/keys-command.js.map +1 -1
  119. package/lib/model-list.d.ts +37 -0
  120. package/lib/model-list.d.ts.map +1 -0
  121. package/lib/model-list.js +60 -0
  122. package/lib/model-list.js.map +1 -0
  123. package/lib/startup.d.ts +8 -0
  124. package/lib/startup.d.ts.map +1 -1
  125. package/lib/startup.js +120 -24
  126. package/lib/startup.js.map +1 -1
  127. package/lib/subagents.d.ts +7 -3
  128. package/lib/subagents.d.ts.map +1 -1
  129. package/lib/subagents.js +28 -4
  130. package/lib/subagents.js.map +1 -1
  131. package/lib/surface/appearance-preferences.d.ts +26 -0
  132. package/lib/surface/appearance-preferences.d.ts.map +1 -0
  133. package/lib/surface/appearance-preferences.js +139 -0
  134. package/lib/surface/appearance-preferences.js.map +1 -0
  135. package/lib/surface/appearance.d.ts +87 -0
  136. package/lib/surface/appearance.d.ts.map +1 -0
  137. package/lib/surface/appearance.js +353 -0
  138. package/lib/surface/appearance.js.map +1 -0
  139. package/lib/surface/background-work.d.ts +51 -0
  140. package/lib/surface/background-work.d.ts.map +1 -0
  141. package/lib/surface/background-work.js +172 -0
  142. package/lib/surface/background-work.js.map +1 -0
  143. package/lib/surface/commands.d.ts +82 -0
  144. package/lib/surface/commands.d.ts.map +1 -0
  145. package/lib/surface/commands.js +370 -0
  146. package/lib/surface/commands.js.map +1 -0
  147. package/lib/surface/modal-input.d.ts +59 -0
  148. package/lib/surface/modal-input.d.ts.map +1 -0
  149. package/lib/surface/modal-input.js +243 -0
  150. package/lib/surface/modal-input.js.map +1 -0
  151. package/lib/surface/model-choice.d.ts +54 -0
  152. package/lib/surface/model-choice.d.ts.map +1 -0
  153. package/lib/surface/model-choice.js +325 -0
  154. package/lib/surface/model-choice.js.map +1 -0
  155. package/lib/surface/preset-choice.d.ts +78 -0
  156. package/lib/surface/preset-choice.d.ts.map +1 -0
  157. package/lib/surface/preset-choice.js +163 -0
  158. package/lib/surface/preset-choice.js.map +1 -0
  159. package/lib/surface/prompt-input.d.ts +97 -0
  160. package/lib/surface/prompt-input.d.ts.map +1 -0
  161. package/lib/surface/prompt-input.js +215 -0
  162. package/lib/surface/prompt-input.js.map +1 -0
  163. package/lib/surface/prompt-memory.d.ts +76 -0
  164. package/lib/surface/prompt-memory.d.ts.map +1 -0
  165. package/lib/surface/prompt-memory.js +167 -0
  166. package/lib/surface/prompt-memory.js.map +1 -0
  167. package/lib/surface/session-lifecycle.d.ts +120 -0
  168. package/lib/surface/session-lifecycle.d.ts.map +1 -0
  169. package/lib/surface/session-lifecycle.js +324 -0
  170. package/lib/surface/session-lifecycle.js.map +1 -0
  171. package/lib/surface/session-picker.d.ts +39 -0
  172. package/lib/surface/session-picker.d.ts.map +1 -0
  173. package/lib/surface/session-picker.js +107 -0
  174. package/lib/surface/session-picker.js.map +1 -0
  175. package/lib/surface/session-view.d.ts +86 -0
  176. package/lib/surface/session-view.d.ts.map +1 -0
  177. package/lib/surface/session-view.js +215 -0
  178. package/lib/surface/session-view.js.map +1 -0
  179. package/lib/surface/staged-turns.d.ts +81 -0
  180. package/lib/surface/staged-turns.d.ts.map +1 -0
  181. package/lib/surface/staged-turns.js +206 -0
  182. package/lib/surface/staged-turns.js.map +1 -0
  183. package/lib/surface/terminal-lifecycle.d.ts +76 -0
  184. package/lib/surface/terminal-lifecycle.d.ts.map +1 -0
  185. package/lib/surface/terminal-lifecycle.js +222 -0
  186. package/lib/surface/terminal-lifecycle.js.map +1 -0
  187. package/lib/terminal-text/scan.d.ts +44 -0
  188. package/lib/terminal-text/scan.d.ts.map +1 -0
  189. package/lib/terminal-text/scan.js +195 -0
  190. package/lib/terminal-text/scan.js.map +1 -0
  191. package/lib/terminal-text/sgr.d.ts +32 -0
  192. package/lib/terminal-text/sgr.d.ts.map +1 -0
  193. package/lib/terminal-text/sgr.js +203 -0
  194. package/lib/terminal-text/sgr.js.map +1 -0
  195. package/lib/terminal-text.d.ts +1 -1
  196. package/lib/terminal-text.d.ts.map +1 -1
  197. package/lib/terminal-text.js +2 -379
  198. package/lib/terminal-text.js.map +1 -1
  199. package/lib/theme-command.js +2 -1
  200. package/lib/theme-command.js.map +1 -1
  201. package/lib/theme-defaults.d.ts +64 -0
  202. package/lib/theme-defaults.d.ts.map +1 -0
  203. package/lib/theme-defaults.js +248 -0
  204. package/lib/theme-defaults.js.map +1 -0
  205. package/lib/theme-files.d.ts +1 -1
  206. package/lib/theme-files.d.ts.map +1 -1
  207. package/lib/theme-files.js +1 -1
  208. package/lib/theme-files.js.map +1 -1
  209. package/lib/theme-resolver.d.ts +36 -0
  210. package/lib/theme-resolver.d.ts.map +1 -0
  211. package/lib/theme-resolver.js +112 -0
  212. package/lib/theme-resolver.js.map +1 -0
  213. package/lib/theme-schema.d.ts.map +1 -1
  214. package/lib/theme-schema.js +3 -2
  215. package/lib/theme-schema.js.map +1 -1
  216. package/lib/theme-settings.d.ts +5 -7
  217. package/lib/theme-settings.d.ts.map +1 -1
  218. package/lib/theme-settings.js +37 -21
  219. package/lib/theme-settings.js.map +1 -1
  220. package/lib/theme-tokens.d.ts +0 -89
  221. package/lib/theme-tokens.d.ts.map +1 -1
  222. package/lib/theme-tokens.js +0 -356
  223. package/lib/theme-tokens.js.map +1 -1
  224. package/lib/theme.d.ts +1 -1
  225. package/lib/theme.d.ts.map +1 -1
  226. package/lib/theme.js +2 -1
  227. package/lib/theme.js.map +1 -1
  228. package/lib/tool-display.d.ts.map +1 -1
  229. package/lib/tool-display.js +2 -1
  230. package/lib/tool-display.js.map +1 -1
  231. package/lib/transcript/message-content.d.ts +21 -0
  232. package/lib/transcript/message-content.d.ts.map +1 -0
  233. package/lib/transcript/message-content.js +61 -0
  234. package/lib/transcript/message-content.js.map +1 -0
  235. package/lib/transcript/tool-calls.d.ts +106 -0
  236. package/lib/transcript/tool-calls.d.ts.map +1 -0
  237. package/lib/transcript/tool-calls.js +254 -0
  238. package/lib/transcript/tool-calls.js.map +1 -0
  239. package/lib/transcript.d.ts +14 -55
  240. package/lib/transcript.d.ts.map +1 -1
  241. package/lib/transcript.js +31 -253
  242. package/lib/transcript.js.map +1 -1
  243. package/lib/ui/dock.d.ts +14 -2
  244. package/lib/ui/dock.d.ts.map +1 -1
  245. package/lib/ui/dock.js +52 -10
  246. package/lib/ui/dock.js.map +1 -1
  247. package/lib/ui/editor.d.ts.map +1 -1
  248. package/lib/ui/editor.js +2 -1
  249. package/lib/ui/editor.js.map +1 -1
  250. package/lib/ui/keymap-picker.d.ts +2 -1
  251. package/lib/ui/keymap-picker.d.ts.map +1 -1
  252. package/lib/ui/keymap-picker.js +1 -0
  253. package/lib/ui/keymap-picker.js.map +1 -1
  254. package/lib/ui/view/gate-card.d.ts +21 -0
  255. package/lib/ui/view/gate-card.d.ts.map +1 -0
  256. package/lib/ui/view/gate-card.js +104 -0
  257. package/lib/ui/view/gate-card.js.map +1 -0
  258. package/lib/ui/view/tool-card.d.ts +149 -0
  259. package/lib/ui/view/tool-card.d.ts.map +1 -0
  260. package/lib/ui/view/tool-card.js +429 -0
  261. package/lib/ui/view/tool-card.js.map +1 -0
  262. package/lib/ui/view/transcript-message.d.ts +62 -0
  263. package/lib/ui/view/transcript-message.d.ts.map +1 -0
  264. package/lib/ui/view/transcript-message.js +158 -0
  265. package/lib/ui/view/transcript-message.js.map +1 -0
  266. package/lib/ui/view.d.ts +105 -223
  267. package/lib/ui/view.d.ts.map +1 -1
  268. package/lib/ui/view.js +132 -679
  269. package/lib/ui/view.js.map +1 -1
  270. package/package.json +3 -1
  271. package/themes/violet-orbit.yaml +7 -5
package/README.md CHANGED
@@ -6,7 +6,7 @@ Status: **v1 feature-complete; published on npm as `@sagmans/dsh-tui`.** The sur
6
6
 
7
7
  ## Install
8
8
 
9
- A profile keeps this plugin as one bundle layer. Install it from a checkout of this repository, or from the registry (`0.1.0` or later). Both paths need Node.js >= 22.19 and `pnpm` on `PATH`. Both need a real terminal: stdin and stdout must be TTYs.
9
+ A profile keeps this plugin as one bundle layer. Install it from a checkout of this repository, or from the registry (`0.1.0` or later). Both paths need Node.js >= 22.19 and `pnpm` on `PATH`. Interactive sessions need a real terminal: stdin and stdout must be TTYs.
10
10
 
11
11
  ### From a plugin checkout
12
12
 
@@ -30,6 +30,47 @@ dsh --profile tui
30
30
 
31
31
  Releases are published, so this path works today. A checkout stays the path for unreleased work.
32
32
 
33
+ ### Install the dogfood skill (optional)
34
+
35
+ Run this explicit command after you add the plugin:
36
+
37
+ ```sh
38
+ dsh --profile tui install-skills
39
+ ```
40
+
41
+ The command copies `dsh-tui-dogfood` to
42
+ `~/.agents/skills/dsh-tui-dogfood/`. Agents can then load it from any dsh
43
+ plugin repository. The skill uses a cloned dsh home, so tests do not change
44
+ your real profile. A first install needs no TTY. `npm install` does not copy
45
+ skills into your home.
46
+
47
+ If the skill exists, the command asks `Update existing skill? [y/N]` in a
48
+ terminal. Only `y` or `yes` replaces it. Enter or `n` keeps the existing
49
+ copy. To update without a prompt, including in non-interactive runs, use:
50
+
51
+ ```sh
52
+ dsh --profile tui install-skills --update
53
+ ```
54
+
55
+ Updating removes any local changes inside the previous skill directory.
56
+ The command stages the new copy before replacement and restores the old
57
+ copy if replacement fails. If cleanup fails after replacement, the new copy
58
+ stays installed and the command reports the old backup path.
59
+
60
+ A started session compares every installed copy with the skills this build
61
+ ships and prints one line when they differ, because an agent loading a stale
62
+ skill is told the old wiring:
63
+
64
+ ```text
65
+ bundled skills changed since they were installed: dsh-tui-update-models · run dsh --profile tui install-skills --update
66
+ ```
67
+
68
+ The comparison reads content only, over the files this package ships: a
69
+ helper's execute bit is the installer's own doing, and a note kept beside a
70
+ skill stays unremarked. A skill that was never installed is not drift — a first
71
+ install is the prompt above — and a run that never opens the screen, like
72
+ `list-models`, prints nothing.
73
+
33
74
  ### Confirm the plugin mounted
34
75
 
35
76
  The profile records its layers in `$DSH_HOME/profiles/tui/package.json` (`~/.dsh` by default). `@sagmans/dsh-tui` must appear in `dsh.profile.bundles`:
@@ -117,8 +158,18 @@ dsh --profile tui --preset minimal # start in a shipped mode other than
117
158
  dsh --profile tui --model deepseek-chat
118
159
  dsh --profile tui --no-color
119
160
  dsh --profile tui --no-bell # do not ring when a long turn finishes
161
+ dsh --profile tui list-models # print every provider/model the picker can reach
120
162
  ```
121
163
 
164
+ `list-models` prints one line per route the `/model` picker can reach —
165
+ `provider/model`, a tab, then the model's display name — in picker order:
166
+ providers as the llm service registered them, then each provider's own model
167
+ order. It writes plain stdout, so it works piped or redirected, never opens the
168
+ alternate screen, and exits 0 after printing at least one route. When the
169
+ profile has no llm service, when the provider listing cannot be read, or when
170
+ nothing is configured to advertise a model, it names the reason on stderr and
171
+ exits 1.
172
+
122
173
  Every key below is a shipped default. `/keys` opens every action the surface
123
174
  and its library can perform as a list you filter as you type, with the keys in
124
175
  force, and the `keys:` section moves any of them — see [Keys](#keys).
@@ -130,7 +181,7 @@ force, and the `keys:` section moves any of them — see [Keys](#keys).
130
181
  | Ctrl+C | take back one thing at a time: the draft in the bar, the prompts waiting in the agent's inbox, the running turn, or a child's conversation; with a picker, an approval, a question, or the transcript search open it closes that instead. With nothing left to cancel it does nothing — it never leaves |
131
182
  | Ctrl+D | leave and print the resume command, when the bar holds no text and nothing is open; a running turn is cancelled first |
132
183
  | Ctrl+O | open every tool card: its header plus every retained row. Folded, a card is one line, and a shell card keeps its command plus the last 20 rows of output with a hint naming what it dropped |
133
- | Ctrl+Y | show or hide the calls a PTC program dispatched: one two-space-indented row per call under its `run_code` card, named and argued from the tool's own header and cut at the screen edge; clicking one row opens that call in full — the change it declared, then what it produced — for every tool, a failed call included; shown by default |
184
+ | Ctrl+Y | show or hide the calls a PTC program dispatched: one two-space-indented row per call under its `run_code` card, named and argued from the tool's own header and cut at the screen edge; clicking the card's own header does the same for that card alone, and one level only — the program's own rows stay under `Ctrl+O`; clicking one call's row opens that call in full — the change it declared, then what it produced — for every tool, a failed call included; hidden by default |
134
185
  | Shift+Tab | expand or fold every thought behind the answers: folded, the row names itself, its token count, and the key; opened, it adds the thought, laid out as markdown; a click decides for one thought instead |
135
186
  | Ctrl+T | pick the reasoning effort for the next step |
136
187
  | Ctrl+R | reverse-search recorded prompts: the list opens filtered by whatever is in the bar, `enter` puts one back, `esc` keeps the draft |
@@ -223,7 +274,7 @@ While a turn runs, a prompt submitted into the editor waits in the agent's own i
223
274
 
224
275
  Copying is read back through what the surface drew rather than through the screen, so a selection is the words alone: dragging across a message takes its box with it on screen, and the surface takes its own frame back out before the text reaches the clipboard — the sides, the padding beside them, and the rules above and below. A selection that covers a whole message, two of them, or a part of one is read the same way, and a row the transcript did not draw — the editor's own bar, a picker's card — is copied exactly as it read, and a selection that was nothing but frame is handed back as the reader made it, because a copy is never emptied. The frame still comes back in a copy taken with the terminal's own selection — Shift held while dragging, or a terminal that keeps selection to itself — which is the one path no program can filter.
225
276
 
226
- Every submitted line is also kept in a global prompt history at
277
+ When prompt history is enabled, each submitted line is kept in a global history at
227
278
  `$DSH_HOME/prompt-history.json`. Typing the start of a prompt that was sent
228
279
  before draws the rest of the newest match after the cursor in a faint shade.
229
280
  `Ctrl+E` takes the whole suggestion and the word-movement key takes the next
@@ -328,13 +379,13 @@ must not also be a way to lose the work.
328
379
 
329
380
  Every styled element is a named token with a shipped default, and every key is
330
381
  an action with one, so the surface can be restyled and rebound without touching
331
- code. Preferences live in the same user-settings document as every other
332
- (`$DSH_HOME/settings.yaml`), under a `dsh-tui:` section:
382
+ code. Released hosts with section APIs store preferences in
383
+ `$DSH_HOME/settings.yaml`, under a `dsh-tui:` section:
333
384
 
334
385
  ```yaml
335
386
  dsh-tui:
336
- theme: violet-orbit # restyle the whole surface by name (default: deepseek-blue)
337
- subcalls: collapsed # fold the calls a PTC program dispatched (default inline)
387
+ theme: deepseek-blue # restyle the whole surface by name (default: violet-orbit)
388
+ subcalls: inline # draw the calls a PTC program dispatched (default collapsed)
338
389
  mermaid: streaming # draw a reply's mermaid fences: off, final, or streaming (default streaming)
339
390
  tools:
340
391
  default: { collapsed: true, output: hidden } # how every tool's card starts
@@ -364,17 +415,73 @@ dsh-tui:
364
415
  hidden: true # the element renders nothing at all
365
416
  ```
366
417
 
418
+ Config-backed source hosts store the same preference fields in the TUI entry's
419
+ `config` in the active profile patch. Use the actual entry ID, normally `tui`,
420
+ not the legacy `dsh-tui` namespace. For example:
421
+
422
+ ```yaml
423
+ - id: tui
424
+ config:
425
+ theme: violet-orbit
426
+ history:
427
+ enabled: false
428
+ ghost: false
429
+ ```
430
+
431
+ The plugin exports a Config schema for all preferences shown above, including
432
+ `prefix`, `prefixWindow`, and `keys`. Launch fields such as `sessionId`,
433
+ `model`, and `provider` remain separate from live preference edits.
434
+ The settings service owns persistence. TUI does not create another preference store.
435
+ It uses released `installSection` or `register` APIs, or Config-backed
436
+ `describe` and revision-checked `update` APIs. Unsupported or read-only writes
437
+ show a notice instead of reporting success. A rejected theme selection restores
438
+ the applied theme, and `/theme tokens` reports that same appearance.
439
+
440
+ On Config-backed hosts, absent `history.enabled` and `history.ghost` stay off.
441
+ Set each switch to `true` explicitly to enable it. This prevents recording while
442
+ the host's asynchronous legacy import is pending or has failed. Released section
443
+ hosts retain their existing defaults. If the host reports unreadable preferences,
444
+ history stays off. Readable `false` switches survive errors in other fields.
445
+ Malformed updates retain the last valid appearance and do not overwrite their source.
446
+
447
+ When public descriptors expose raw user layers, history checks those layers at use
448
+ time. A readable opt-out survives rejected siblings even without a change event.
449
+ Another rejected opt-in cannot clear this protection; a valid committed update can.
450
+ A released-provider limit remains: after an absent user section, rejected scalar
451
+ sections can produce identical public descriptors. TUI cannot detect that transition
452
+ without host validity metadata, so normal released defaults remain active.
453
+
454
+ The inspected source host has no legacy import alias from `dsh-tui` to `tui`.
455
+ Exporting Config does not resolve that namespace mismatch. The host can rename
456
+ `settings.yaml` to `settings.yaml.imported` before import completes.
457
+ TUI does not retry or restore that file automatically. Preserve current privacy
458
+ opt-outs and copy only the intended legacy fields into the actual TUI entry's
459
+ `config`. Keep the original file for rollback.
460
+
461
+ Live Config edits require the loaded schema runtime to create native volatile
462
+ references. The released schemastery 3.18.2 implementation used by this checkout's
463
+ unit tests lacks that API. A source host can resolve a different implementation
464
+ with the same version label. TUI checks the loaded implementation and actual
465
+ references, not the package version or CLI identity.
466
+
467
+ If the loaded schema runtime lacks native support, TUI exports ordinary fields
468
+ rather than unsupported live metadata. TUI then rejects Config-backed writes,
469
+ and the host cannot import preferences through its volatile-field settings API.
470
+ Reading row preferences still works, and ordinary profile changes use the host's
471
+ reload lifecycle. Native schema-backed hosts can apply live preference updates.
472
+
367
473
  Every field is optional, so a section that changes one shade is enough. The
368
474
  document is hot-reloaded: an edit restyles a running session and re-arms the
369
475
  keymap on the next press, and `/theme` shows each element's effective value and
370
476
  whether it came from an override, the palette, or the default.
371
477
 
372
478
 
373
- The section is not only shades. By default every session draws one row per call
374
- a PTC program dispatched under its card, and `subcalls: collapsed` starts with
375
- the card alone instead. `Ctrl+Y` toggles the same choice for the current
376
- session, and an edit to the document re-seeds it. An unknown key or value is
377
- refused with a notice naming it, so a typo cannot quietly do nothing.
479
+ The section is not only shades. By default a PTC program's card arrives alone,
480
+ and `subcalls: inline` draws one row per call it dispatched under that card
481
+ instead — or one click on the card's own header, for that card alone.
482
+ `Ctrl+Y` toggles the same choice for the current session, and an edit to the
483
+ document re-seeds it. An unknown key or value is refused with a notice naming
484
+ it, so a typo cannot quietly do nothing.
378
485
 
379
486
  The `tools` block decides how each tool's cards draw. `collapsed` starts a
380
487
  tool folded to one header row (default `true`), and `output` is `hidden`
@@ -388,8 +495,11 @@ profile mounts. Clicking a card opens or folds that one message, and a dispatche
388
495
  call's row opens on the same click to what the tool itself drew for it — an
389
496
  edit's diff in the diff colours, a read's numbered lines, a command and its
390
497
  output — followed by the outcome it produced; a call that failed opens to the
391
- reason it reported instead of rows for work that never happened. `Ctrl+O` still
392
- decides for every message nobody clicked.
498
+ reason it reported instead of rows for work that never happened. A program's
499
+ card opens one level at a time: its own row draws the calls, and the rows below
500
+ them — what the program returned — are the card's, so a click on each answers
501
+ for what it drew. `Ctrl+O` still decides for every message nobody clicked, and
502
+ `Ctrl+Y` for every program whose own header nobody clicked.
393
503
 
394
504
  The `history` block tunes the prompt history. `enabled: false` stops recording
395
505
  and offering it; `ghost: false` keeps reverse search but stops the dimmed
@@ -428,9 +538,9 @@ leaving a gap, and `NO_COLOR` draws the fence as plain text. `/export` and the
428
538
  session file still keep the fence exactly as the model wrote it.
429
539
 
430
540
  A theme restyles the whole surface by name, and a theme is a file. The package
431
- ships two: `deepseek-blue`, the table written out in full in the colours the
432
- project answers to, and `violet-orbit`, a port of pi's theme of that name — its
433
- palette, plus the elements it draws its own way. `deepseek-blue` is also what a
541
+ ships two: `violet-orbit`, a port of pi's theme of that name — its palette, plus
542
+ the elements it draws its own way — and `deepseek-blue`, the table written out
543
+ in full in the colours the project answers to. `violet-orbit` is also what a
434
544
  document naming no theme draws, so the default look is a file you can read, list,
435
545
  and copy rather than a table compiled in. Your own themes live in
436
546
  `$DSH_HOME/themes/`, which the surface creates at start-up and watches, so saving
@@ -620,7 +730,7 @@ The fold is durable-only: the live stream decorates the row that is still being
620
730
 
621
731
  Tool cards are folded by default: a card draws one header row — the tool, its argument clipped to the configured budget, and the facts the result measured — so a long read, diff, or search cannot bury the conversation. A call that has not answered yet names itself in the running colour, `tool.running.title`, and ends that row with the whole seconds it has been waiting, in `tool.running.elapsed`, once it has waited one, so a reader can tell the call they are watching from the one below it that already finished; both give way to the measured facts the moment the result lands. A call that failed names itself in the failed colour, `tool.failed.title` — including a shell whose command exited non-zero or died on a signal, which is a failure whether or not the tool that ran it said so. A shell card's row also carries the exit status and the count of output rows waiting behind the fold, because its output is the answer the reader asked for and a fold that left no trace of it would read as a call that produced nothing. Clicking a card opens or folds that one message; `Ctrl+O` opens or folds every card at once, and `tools:` in the [settings](#settings) decides how each tool starts and whether a fold hides its rows or keeps a `tail` of them.
622
732
 
623
- A PTC card is the one card with children: every call the `run_code` program dispatched hangs off the card that made it, and each draws under the header as the tool's own name and argument, on one row cut at the screen edge whether the card itself is open or folded — a program's work must stay legible without opening its card. Each of those rows names its own call in the colour of what that call is doing — `tool.subcall.running` while the program is waiting on it, `tool.failed.title` when it failed, and `tool.subcall.title` once it is back — and a settled row keeps the one line the tool itself drew about its outcome, in `tool.terminal.status` where that tool declares one. A shell call therefore reads `bash pnpm test · exit 0` when it worked and the same row in red, with `exit 1`, when it did not, so a program's work reads row by row without opening the card. The program's own row is the one card that shows no mark: its timer is what says it is still running, and it is also what the card keeps when the program answers — the total it ran for, drawn in `tool.elapsed.done`, dimmed and italic, because the work it measured is over. Clicking one of those rows opens that call's argument in full and leaves its neighbours and the card as they were; a shell call also brings back the rows it printed, because the program's return value is all the card itself keeps. `Ctrl+Y` hides or shows them all, and `subcalls: collapsed` starts every session with them hidden; see [Settings](#settings).
733
+ A PTC card is the one card with children: every call the `run_code` program dispatched hangs off the card that made it, and once shown, each draws under the header as the tool's own name and argument, on one row cut at the screen edge whether the card itself is open or folded — a program's work must stay legible without opening its card. Those rows start folded, because a program can dispatch hundreds of calls and what a reader came for is the answer they produced: one click on the card's own header draws them for that card and for that card alone, `Ctrl+Y` draws them for every card at once, and `subcalls:` decides what a session starts with. Nothing else arrives with that click: the program's own rows are the level below, and `Ctrl+O` is what opens them. Each of those rows names its own call in the colour of what that call is doing — `tool.subcall.running` while the program is waiting on it, `tool.failed.title` when it failed, and `tool.subcall.title` once it is back — and a settled row keeps the one line the tool itself drew about its outcome, in `tool.terminal.status` where that tool declares one. A shell call therefore reads `bash pnpm test · exit 0` when it worked and the same row in red, with `exit 1`, when it did not, so a program's work reads row by row without opening the card. The program's own row is the one card that shows no mark: its timer is what says it is still running, and it is also what the card keeps when the program answers — the total it ran for, drawn in `tool.elapsed.done`, dimmed and italic, because the work it measured is over. Clicking one of those rows opens that call's argument in full and leaves its neighbours and the card as they were; a shell call also brings back the rows it printed, because the program's return value is all the card itself keeps. `Ctrl+Y` hides or shows them all, and `subcalls: collapsed`, the shipped default, starts every session with them hidden; see [Settings](#settings).
624
734
 
625
735
  A card's header names the tool, then the argument the call was made with — a path or a command — in the `tool.args` colour, then the facts the result measured: a read reports its line range, line count, and token size; a file change that carried no prior content to compare against reports its lines and tokens; one that did reports added, changed, and removed lines as `+n ~n -n` in green, yellow, and red. Each stat is its own token, so any of them can be recoloured or hidden independently, and so are the elements a call in flight is drawn with — hiding `tool.running.elapsed` leaves the name in its running colour, hiding `tool.running.title` leaves the seconds counting, hiding `tool.elapsed.done` takes the total off a program's settled row, and a dispatched row is toned the same way per state with `tool.subcall.running` and `tool.subcall.title`. A state is only how a name is painted, so hiding one of those colours leaves the name in the colour a call with no state is read in rather than taking the name away.
626
736
 
@@ -659,15 +769,29 @@ The list the dock and `/todo` draw follows the same lifetime every other surface
659
769
  |---|---|
660
770
  | the screen is taken, before any session opens | `idle`, claiming the pane's agent row |
661
771
  | the agent's driver starts, including a run of turns chained through pending work | `working` |
662
- | an approval, a question, or a picker takes the keyboard | `blocked`, with that card's title sent along |
663
- | the decision settles | `working` if the driver is running, otherwise `idle` |
664
- | the agent's driver stops with nothing pending | `idle` |
772
+ | a subagent or background job remains live after the driver stops | `working` until the last one settles |
773
+ | an approval or a question takes the keyboard | `blocked`, with that card's title sent along, and set as the `blocked` display label |
774
+ | the decision settles | `working` if the driver or background work is running, otherwise `idle` |
775
+ | the agent's driver stops with no live subagent or job | `idle` |
665
776
  | a session opens, resumes, forks, or is switched to | its id and reason, plus the `dsh_session` / `dsh_cwd` pane tokens |
666
777
  | exit, signal, or boot failure | `herdr pane release-agent`, so no row is left waiting on a process that is gone |
667
778
 
668
- A wait outranks a running driver: an agent waiting on a human is not making progress, and the wait is the only thing worth acting on from a wall of panes. The pane reports the agent's driver rather than each turn: the harness chains turns through a pending inbox inside one driver run, and reporting each turn's end would read as done between two turns of an agent that is still working. Reports are sequenced per source, so a delivery that arrives late cannot undo the state the surface already moved past, and a state Herdr is already showing is not sent again. A report is only counted as made when Herdr acknowledges it: one that failed is tried again — soon after, then with a growing wait — and a session identity Herdr never confirmed travels with the next report of any kind. The retry cannot wait for another state change, because the pane may have nothing left to say: a driver that stopped while the socket was down produces no further event. States still waiting to be sent are collapsed into the newest one, so a socket that was down for a minute is told where the pane is rather than where it has been. The release carries the next number in that same sequence for the same reason: Herdr reads one that cannot beat the pane's last report as stale, and a stale release leaves the row waiting on a process that is gone. It also stops reporting first — a claim landing after the release would take the row back for a process that is leaving — and the report already on the wire is waited for before the row goes back, because Herdr ignores the release of a pane nothing has claimed yet and that late report would then claim it. What is still waiting behind it is dropped rather than sent.
779
+ A picker is deliberately absent from that table. Herdr answers a transition into `blocked` with a needs-attention notification and its sound, and 0.9.1 plays it for the focused pane of the active tab as well as for a background one, so a menu the reader opened themselves would ring for their own navigation — once per menu, on the model picker and the reasoning picker behind it — and the row would read as an agent stuck on a decision it never asked for. A gate is the opposite case: the agent asked, and may have asked somebody who walked away.
780
+
781
+ A wait outranks running work: an agent waiting on a human is not making progress, and the wait is the only thing worth acting on from a wall of panes. The pane follows the agent's driver and the live subagents and jobs it owns. The harness chains turns through a pending inbox inside one driver run, and reporting each turn's end would read as done between two turns of an agent that is still working. A parent driver can also stop while a delegated child or job continues, so its idle transition alone does not make the pane done. The job registry announces settlement before its completion notice wakes the parent, so the pane checks for idle after that handoff instead of briefly announcing done in the middle. Reports are sequenced per source, so a delivery that arrives late cannot undo the state the surface already moved past, and a state Herdr is already showing is not sent again. A report is only counted as made when Herdr acknowledges it: one that failed is tried again — soon after, then with a growing wait — and a session identity Herdr never confirmed travels with the next report of any kind. The retry cannot wait for another state change, because the pane may have nothing left to say: a driver that stopped while the socket was down produces no further event. States still waiting to be sent are collapsed into the newest one, so a socket that was down for a minute is told where the pane is rather than where it has been. The release carries the next number in that same sequence for the same reason: Herdr reads one that cannot beat the pane's last report as stale, and a stale release leaves the row waiting on a process that is gone. It also stops reporting first — a claim landing after the release would take the row back for a process that is leaving — and the report already on the wire is waited for before the row goes back, because Herdr ignores the release of a pane nothing has claimed yet and that late report would then claim it. What is still waiting behind it is dropped rather than sent.
782
+
783
+ Herdr persists a session reference only for its own built-in integrations, so this pane's session identity travels as metadata tokens instead: a script or a companion plugin reads them back with `herdr pane get <id>` and resumes that exact conversation with `dsh --profile tui --resume=<id>`. Herdr holds a token value up to 80 characters and shortens anything longer, so a session id or directory that cannot be sent whole has its token cleared instead: a shortened path would read as a different directory, and a pane must not claim one. What Herdr cannot do is identify the process itself — its detection table and its screen rules both name built-in agents only — so a pane that has not reported yet reads as an ordinary pane, and is not yet a target: `herdr agent wait` on it fails with `agent_not_found` until the first report lands. Herdr 0.9.1 keeps the title that accompanies a `blocked` state without drawing it anywhere, so the same title is sent again as that state's display label — the one Herdr's sidebar renders through its `state_text` token. The complete default agent rows do not include it:
784
+
785
+ ```toml
786
+ [ui.sidebar.agents]
787
+ rows = [
788
+ ["state_icon", "machine", "workspace", "tab"],
789
+ ["state_text"],
790
+ ["agent"],
791
+ ]
792
+ ```
669
793
 
670
- Herdr persists a session reference only for its own built-in integrations, so this pane's session identity travels as metadata tokens instead: a script or a companion plugin reads them back with `herdr pane get <id>` and resumes that exact conversation with `dsh --profile tui --resume=<id>`. Herdr holds a token value up to 80 characters and shortens anything longer, so a session id or directory that cannot be sent whole has its token cleared instead: a shortened path would read as a different directory, and a pane must not claim one. What Herdr cannot do is identify the process itself — its detection table and its screen rules both name built-in agents only — so a pane that has not reported yet reads as an ordinary pane, and is not yet a target: `herdr agent wait` on it fails with `agent_not_found` until the first report lands. Herdr 0.9.1 also keeps the title that accompanies a `blocked` state without showing it anywhere, so a reader sees the state and reads the card on screen.
794
+ With that row present, a pane waiting on a decision names the tool that asked instead of showing a colour alone. A label longer than the 80 characters Herdr holds whole is cut here rather than server-side, so the ellipsis lands where this surface put it; the message that rides the state report keeps its own, longer bound.
671
795
 
672
796
  ## Development
673
797
 
@@ -684,6 +808,7 @@ pnpm run build
684
808
  node tools/pty-drive.mjs --prompt 'Reply with exactly: pong'
685
809
  node tools/pty-drive.mjs --prompt 'Run: echo hi' --approve 20 # answer the approval gate
686
810
  node tools/pty-drive.mjs --home /tmp/scratch-home --seconds 20 # no credentials: proves failures are visible
811
+ node tools/pty-drive.mjs --prompt 'Run: echo hi' --click 20:12 # press the left button at row 12
687
812
  ```
688
813
 
689
814
  Keep verification off your real home: install the profile into a throwaway one and copy only the credentials it needs.
@@ -713,11 +838,11 @@ The automated checks drive a real PTY, but they run on this machine's terminal.
713
838
  | `NO_COLOR=1 dsh --profile tui` | no styling anywhere, layout unchanged |
714
839
  | `dsh --profile tui --no-bell` | a turn that runs for minutes still ends silently |
715
840
  | `dsh --profile tui --preset ptc`, then a turn | the status line names `ptc`, and the agent reaches its tools through one TypeScript program rather than one shell call at a time |
716
- | a PTC turn | one row per dispatched call draws two spaces indented under the `run_code` header without opening it |
841
+ | a PTC turn | the `run_code` card arrives alone, whatever the program dispatched; `ctrl+y` draws one row per call two spaces indented under it without opening it, and a click on the card's own header does the same for that card — and for that card alone, one level, with the program's own rows still behind `ctrl+o` |
717
842
  | that turn, then a click on one of those rows | that call unfolds in full at the same indent: its argument, then what the tool itself drew — an edit's diff in the diff colours, a read's lines, a shell's output — and its neighbours and the card stay as they were |
718
843
  | a PTC turn in which a dispatched call failed, then a click on that red row | the row opens to the reason the call reported, and a click on those rows folds it back |
719
- | that same turn, then `ctrl+y` | the rows fold away; `ctrl+y` again draws them back |
720
- | `dsh-tui: { subcalls: collapsed }` in `$DSH_HOME/settings.yaml`, then a PTC turn | the card arrives alone, and editing the document to `inline` draws the one-line calls in a running session |
844
+ | that same turn, then `ctrl+y` | the rows draw under the folded card; `ctrl+y` again folds them away, and one click on the card's own header does the same for that card alone |
845
+ | `dsh-tui: { subcalls: inline }` in `$DSH_HOME/settings.yaml`, then a PTC turn | the one-line calls draw under the card; deleting the key folds them away |
721
846
  | a thought, folded | a click on the row opens the thought under its summary; a click on the body folds it back, and the other thoughts keep their own state |
722
847
  | a bash card, then a click on it | the row opens to its command, its retained output, and its exit status; a click folds it back to one row |
723
848
  | a bash command that exits non-zero | the same row as any other failure: the tool's name in the failed colour, with the `exit 1` it ended on |
@@ -778,9 +903,11 @@ The workflow stores no npm token: the registry trusts `release.yml` on the `npm-
778
903
 
779
904
  - Two different things are called a preset. The agent mode (`--preset`, `/preset`) is fixed once a session has produced a turn; the permission preset (`/permission <preset>`, named in the status line) can change at any time.
780
905
  - `/model` changes the route and reasoning effort for the running session only. Catalog membership is advisory — an adapter may accept an id it does not advertise, while an explicit effort is checked against the route's own levels before it is applied. The picker offers the routes this deployment configured, not the ones it can prove credentialed: a provider whose key or sign-in is still missing appears like any other, and its first request names the missing credential.
906
+ - Model discovery failures show a safe notice. Healthy provider catalogs remain selectable. Check provider configuration and credentials before retrying `/model`.
781
907
  - Scrolling is the mouse wheel, or the terminal's own scrollback keys where it offers them.
782
908
  - A turn that ran longer than ten seconds rings the terminal bell when it ends, because the reader may have walked away; `--no-bell` turns that off.
783
909
  - The dock shows the goal, plan mode, the todo items still to do, and any background job or delegation still running; a settled item leaves rather than turns into a completed row, and the list clears when the next turn opens so a fresh task never inherits the previous one's checklist. The transcript marks where older history was compacted away. `/plan` toggles plan mode; `/plan <message>` also steers that message, which is the base command's own behaviour.
910
+ - The dock shows three running subagents by default. When more than three run, click the heading, overflow row, or blank cells in that section to show all. Click again to show three. Click a child’s text to view its transcript. Press `ctrl+b` to return.
784
911
  - Background jobs and subagent runs are live process state, not durable events: they disappear when the run ends, and a resumed session starts with an empty board and roster.
785
912
  - A card reads its tool's own render intent through the agent whose session is on screen, so a stored session with no live agent — one this process is not running, or a child that has already finished — folds to the generic card instead of the tool's own.
786
913
  - Reading a child's conversation does not move the terminal: commands, approvals, and the status line stay with the session you launched, and the transcript is the only thing that switches. The status line carries the way back, read from the map in force, so a remap shows up without reopening the view.
@@ -804,7 +931,7 @@ discipline as this one.
804
931
  | Plugin | What it adds |
805
932
  |---|---|
806
933
  | [`@sagmans/dsh-auto-compact`](https://github.com/sagmans/dsh-auto-compact) | An absolute token trigger for automatic compaction: the conversation condenses at `min(thresholdTokens, contextWindow × thresholdRatio)` instead of the window ratio alone, so a large-window model pays a fixed price, with per-route overrides. Its patch swaps the shipped `compaction-basic` backend — the same row this bundle already takes out of the global composition — so the profile still keeps exactly one compaction service, and this surface needs no setting for it. |
807
- | [`@sagmans/dsh-provider-extra`](https://github.com/sagmans/dsh-provider-extra) | Extra provider routes: OpenCode Go, which sends the live conversation id in `x-opencode-session` for routing and prompt caching, and OpenAI Codex over a ChatGPT subscription's OAuth flow with the harness credential store. Its routes join the `/model` picker like every configured provider. |
934
+ | [`@sagmans/dsh-provider-extra`](https://github.com/sagmans/dsh-provider-extra) | Extra provider routes: OpenCode Go, which sends the live conversation id in `x-opencode-session` for routing and prompt caching, and OpenAI Codex over a ChatGPT subscription's OAuth flow with the harness credential store. Its routes join the `/model` picker like every configured provider. TUI also works without this package, using the core `llm` and `agentDefaultModel` services. |
808
935
 
809
936
  ```sh
810
937
  dsh plugin --profile tui add @sagmans/dsh-auto-compact
@@ -1 +1 @@
1
- {"version":3,"file":"present.d.ts","sourceRoot":"","sources":["../../src/agent/present.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,aAAa,CAAA;AA4BpB;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,GAAG,SAAS,GAAG,aAAa,CAqChG"}
1
+ {"version":3,"file":"present.d.ts","sourceRoot":"","sources":["../../src/agent/present.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAEnD,OAAO,EAAgB,KAAK,aAAa,EAAwB,MAAM,aAAa,CAAA;AA4BpF;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,GAAG,SAAS,GAAG,aAAa,CAqChG"}
@@ -1,4 +1,5 @@
1
- import { cardOfCall, cardOfResult, contentLines, } from "../cards.js";
1
+ import { cardOfCall, cardOfResult } from "../cards/presenter.js";
2
+ import { contentLines } from "../cards.js";
2
3
  function parseArguments(argumentsJson) {
3
4
  try {
4
5
  return JSON.parse(argumentsJson);
@@ -1 +1 @@
1
- {"version":3,"file":"present.js","sourceRoot":"","sources":["../../src/agent/present.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,YAAY,GAGb,MAAM,aAAa,CAAA;AAEpB,SAAS,cAAc,CAAC,aAAqB;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAY,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,OAAgB;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAQ;QACzD,MAAM,MAAM,GAAG,KAAgC,CAAA;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,CAAC,OAAO,CAAA;IAC3F,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY,EAAE,KAA+B;IAC/E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,aAAa;YACtB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,cAAc,CAAC,aAAa,CAAU,CAAC,CAAA;gBACpF,wEAAwE;gBACxE,wEAAwE;gBACxE,sEAAsE;gBACtE,yCAAyC;gBACzC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,KAAsB;YACjC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,CAC5C,cAAc,CAAC,KAAK,CAAC,aAAa,CAAU,EAC5C,EAAE,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAW,CACjG,CAAA;gBACD,OAAO,YAAY,CAAC,IAAI,EAAE;oBACxB,IAAI;oBACJ,MAAM,EAAE,KAAK,CAAC,OAAO;oBACrB,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC;iBAC1C,CAAC,CAAA;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"present.js","sourceRoot":"","sources":["../../src/agent/present.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,EAAE,YAAY,EAA4C,MAAM,aAAa,CAAA;AAEpF,SAAS,cAAc,CAAC,aAAqB;IAC3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAY,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,OAAgB;IACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,SAAQ;QACzD,MAAM,MAAM,GAAG,KAAgC,CAAA;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,OAAO,MAAM,CAAC,OAAO,CAAA;IAC3F,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY,EAAE,KAA+B;IAC/E,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IACD,OAAO;QACL,IAAI,CAAC,IAAI,EAAE,aAAa;YACtB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,cAAc,CAAC,aAAa,CAAU,CAAC,CAAA;gBACpF,wEAAwE;gBACxE,wEAAwE;gBACxE,sEAAsE;gBACtE,yCAAyC;gBACzC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAChE,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,KAAsB;YACjC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,CAC5C,cAAc,CAAC,KAAK,CAAC,aAAa,CAAU,EAC5C,EAAE,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAW,CACjG,CAAA;gBACD,OAAO,YAAY,CAAC,IAAI,EAAE;oBACxB,IAAI;oBACJ,MAAM,EAAE,KAAK,CAAC,OAAO;oBACrB,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC;iBAC1C,CAAC,CAAA;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { type ToolSubCall, type ToolSubCallRows, type ToolCard } from '../cards.ts';
2
+ /**
3
+ * Nested calls retained on one PTC card.
4
+ *
5
+ * A program can dispatch in a loop, and one line each is small but not free;
6
+ * the cap keeps a card bounded while {@link ToolCard.subCallsTotal} still
7
+ * reports everything the program ran.
8
+ */
9
+ export declare const SUBCALL_MAX = 100;
10
+ /**
11
+ * What the fold learned about one dispatched call, in the order it learned it.
12
+ *
13
+ * A call is logged twice — once when the program asks for it, once with what it
14
+ * answered — and each moment supplies part of the row: the call view names it,
15
+ * the result view says how it ended and what it produced.
16
+ */
17
+ export interface SubCallFacts {
18
+ /** The card the call declared, or nothing when no presenter answered for it. */
19
+ readonly view: ToolCard | undefined;
20
+ /** The rows the row opens to, once the call reported them. */
21
+ readonly output: ToolSubCallRows | undefined;
22
+ /** How the call finished, as the tool that ran it reported. */
23
+ readonly status: string | undefined;
24
+ /** Whether the call is logged and still unanswered. */
25
+ readonly running: boolean;
26
+ /** Whether the call is one the log marked as an error. */
27
+ readonly failed: boolean;
28
+ }
29
+ /**
30
+ * The one-line row for one nested call, as its start or its settle leaves it.
31
+ *
32
+ * A tool that declares a call view is drawn exactly as its own header would be;
33
+ * only a tool with no view at all falls back to its registry name and raw call,
34
+ * because the surface cannot name a salient argument for a schema it never saw.
35
+ * A settle logs the same call again, and the presenter that answered the first
36
+ * time is asked again for the view it would draw — so the row's identity comes
37
+ * from the row already on screen wherever there is one, and only a call that was
38
+ * dropped earlier is named from the log. The row also keeps how the call ended,
39
+ * because a program's calls are told apart by their outcomes rather than by
40
+ * anything the program itself says about them.
41
+ */
42
+ export declare function subCallRow(id: string, name: string, argumentsJson: string, facts: SubCallFacts, existing?: ToolSubCall): ToolSubCall;
43
+ /**
44
+ * The rows one dispatched call keeps, from the card that drew them.
45
+ *
46
+ * The total is clamped to what was kept: a card built from a call or result
47
+ * view reports no total of its own, because it is not a stream retention had to
48
+ * cut, and a count below the rows on screen would hint at rows already shown.
49
+ */
50
+ export declare function subCallRows(card: ToolCard | undefined): ToolSubCallRows | undefined;
51
+ /**
52
+ * The header fields a rebuilt card must keep.
53
+ *
54
+ * Replacing a card's rows says nothing about what the call was made with, what
55
+ * it measured, how it ended, or which calls it dispatched, so those fields
56
+ * travel with the rebuild: dropping the argument is how a shell card loses its
57
+ * command the moment a presenter declines the result.
58
+ */
59
+ export declare function carriedFields(card: ToolCard): Pick<ToolCard, 'argument' | 'stats' | 'status' | 'subCalls' | 'subCallsTotal'>;
60
+ /**
61
+ * Collapse one call and its result into the single row the reader sees.
62
+ *
63
+ * The pending row already told the reader what the tool is doing, so the
64
+ * settled row keeps that header and swaps in the outcome; a result that
65
+ * presents nothing keeps the call's detail rather than blanking the row.
66
+ */
67
+ export declare function mergeCards(call: ToolCard | undefined, result: ToolCard | undefined): ToolCard;
68
+ //# sourceMappingURL=composition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../../src/cards/composition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAY,MAAM,aAAa,CAAA;AAG7F;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,MAAM,CAAA;AAE9B;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAA;IACnC,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAAA;IAC5C,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,WAAW,CAuBpI;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAGnF;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,eAAe,CAAC,CAQ5H;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CA8B7F"}
@@ -0,0 +1,117 @@
1
+ import { clipLine } from "../cards.js";
2
+ import { title } from "./presenter.js";
3
+ /**
4
+ * Nested calls retained on one PTC card.
5
+ *
6
+ * A program can dispatch in a loop, and one line each is small but not free;
7
+ * the cap keeps a card bounded while {@link ToolCard.subCallsTotal} still
8
+ * reports everything the program ran.
9
+ */
10
+ export const SUBCALL_MAX = 100;
11
+ /**
12
+ * The one-line row for one nested call, as its start or its settle leaves it.
13
+ *
14
+ * A tool that declares a call view is drawn exactly as its own header would be;
15
+ * only a tool with no view at all falls back to its registry name and raw call,
16
+ * because the surface cannot name a salient argument for a schema it never saw.
17
+ * A settle logs the same call again, and the presenter that answered the first
18
+ * time is asked again for the view it would draw — so the row's identity comes
19
+ * from the row already on screen wherever there is one, and only a call that was
20
+ * dropped earlier is named from the log. The row also keeps how the call ended,
21
+ * because a program's calls are told apart by their outcomes rather than by
22
+ * anything the program itself says about them.
23
+ */
24
+ export function subCallRow(id, name, argumentsJson, facts, existing) {
25
+ const { view, output, status, running, failed } = facts;
26
+ const title = view?.title ?? existing?.title ?? name;
27
+ const raw = view !== undefined || existing !== undefined ? undefined : clipLine(argumentsJson);
28
+ const argument = view?.argument ?? existing?.argument ?? raw;
29
+ // A failed call keeps only what still holds: the change it declared never
30
+ // happened, so the rows that drew as applied go with the outcome that never
31
+ // came. Its outcome stays, because the reason it failed is what a reader opens
32
+ // the row to read.
33
+ const presented = failed ? undefined : subCallRows(view) ?? existing?.presented;
34
+ // A settle that reports nothing keeps what the row already said about its own
35
+ // outcome, because a call does not stop having finished a certain way.
36
+ const ended = status ?? existing?.status;
37
+ return {
38
+ id,
39
+ title,
40
+ ...(argument === undefined || argument === '' ? {} : { argument }),
41
+ ...(ended === undefined || ended === '' ? {} : { status: ended }),
42
+ failed,
43
+ running,
44
+ ...(presented === undefined ? {} : { presented }),
45
+ ...(output === undefined ? {} : { output }),
46
+ };
47
+ }
48
+ /**
49
+ * The rows one dispatched call keeps, from the card that drew them.
50
+ *
51
+ * The total is clamped to what was kept: a card built from a call or result
52
+ * view reports no total of its own, because it is not a stream retention had to
53
+ * cut, and a count below the rows on screen would hint at rows already shown.
54
+ */
55
+ export function subCallRows(card) {
56
+ if (card === undefined || card.detail.length === 0)
57
+ return undefined;
58
+ return { kind: card.kind, rows: card.detail, totalLines: Math.max(card.totalLines, card.detail.length) };
59
+ }
60
+ /**
61
+ * The header fields a rebuilt card must keep.
62
+ *
63
+ * Replacing a card's rows says nothing about what the call was made with, what
64
+ * it measured, how it ended, or which calls it dispatched, so those fields
65
+ * travel with the rebuild: dropping the argument is how a shell card loses its
66
+ * command the moment a presenter declines the result.
67
+ */
68
+ export function carriedFields(card) {
69
+ return {
70
+ ...(card.argument === undefined ? {} : { argument: card.argument }),
71
+ ...(card.stats === undefined ? {} : { stats: card.stats }),
72
+ ...(card.status === undefined ? {} : { status: card.status }),
73
+ ...(card.subCalls === undefined ? {} : { subCalls: card.subCalls }),
74
+ ...(card.subCallsTotal === undefined ? {} : { subCallsTotal: card.subCallsTotal }),
75
+ };
76
+ }
77
+ /**
78
+ * Collapse one call and its result into the single row the reader sees.
79
+ *
80
+ * The pending row already told the reader what the tool is doing, so the
81
+ * settled row keeps that header and swaps in the outcome; a result that
82
+ * presents nothing keeps the call's detail rather than blanking the row.
83
+ */
84
+ export function mergeCards(call, result) {
85
+ const base = call ?? result;
86
+ if (base === undefined)
87
+ throw new Error('mergeCards requires at least one card');
88
+ if (call === undefined || result === undefined)
89
+ return base;
90
+ const kind = result.kind === 'generic' ? call.kind : result.kind;
91
+ // The result, when it names one, knows the argument that was actually acted
92
+ // on; a terminal result omits it, so the pending call's command is kept. The
93
+ // result also owns the measured facts, because only it knows the outcome.
94
+ const argument = result.argument ?? call.argument;
95
+ const stats = result.stats ?? call.stats;
96
+ const status = result.status ?? call.status;
97
+ // The nested calls belong to the call, not the outcome: a result never carries
98
+ // them, so the merge has to hand the call's own list through.
99
+ const subCalls = result.subCalls ?? call.subCalls;
100
+ const subCallsTotal = result.subCallsTotal ?? call.subCallsTotal;
101
+ return {
102
+ kind,
103
+ // The tool that ran is the call's identity: a result card describes the same
104
+ // call, so it cannot rename the message a reader's clicks are remembered by.
105
+ tool: call.tool,
106
+ title: call.title,
107
+ ...(argument === undefined ? {} : { argument }),
108
+ ...(stats === undefined ? {} : { stats }),
109
+ ...(status === undefined ? {} : { status }),
110
+ ...(subCalls === undefined ? {} : { subCalls }),
111
+ ...(subCallsTotal === undefined ? {} : { subCallsTotal }),
112
+ detail: result.detail.length > 0 ? result.detail : call.detail,
113
+ failed: result.failed,
114
+ totalLines: result.detail.length > 0 ? result.totalLines : call.totalLines,
115
+ };
116
+ }
117
+ //# sourceMappingURL=composition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composition.js","sourceRoot":"","sources":["../../src/cards/composition.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type CardRow, type ToolCard } from '../cards.ts';
2
+ import { type FileDiff, type ToolCallView, type ToolResultView } from '@deepseek-ai/dsh-tools';
3
+ /**
4
+ * Render one file change as a bounded unified hunk.
5
+ *
6
+ * Only the changed middle is shown: a presenter has the prior and next text but
7
+ * no hunk list, so trimming the shared prefix and suffix yields the same region
8
+ * a full diff would highlight without paying for a line-diff computation on
9
+ * every frame.
10
+ */
11
+ export declare function renderFileDiff(diff: FileDiff): CardRow[];
12
+ export declare function title(view: {
13
+ title?: string;
14
+ }, fallback: string): string;
15
+ /** Map a tool's pending-call intent to a card, falling back to the raw call name. */
16
+ export declare function cardOfCall(view: ToolCallView | undefined, name: string): ToolCard;
17
+ /** Map a tool's result intent to a card, falling back to the model-facing text. */
18
+ export declare function cardOfResult(view: ToolResultView | undefined, input: {
19
+ readonly name: string;
20
+ readonly failed: boolean;
21
+ readonly contentLines: readonly string[];
22
+ }): ToolCard;
23
+ //# sourceMappingURL=presenter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter.d.ts","sourceRoot":"","sources":["../../src/cards/presenter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAA0B,KAAK,QAAQ,EAAkC,MAAM,aAAa,CAAA;AACjH,OAAO,EAA0C,KAAK,QAAQ,EAA4I,KAAK,YAAY,EAAE,KAAK,cAAc,EAAsB,MAAM,wBAAwB,CAAA;AAoGpS;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,EAAE,CAsBxD;AAaD,wBAAgB,KAAK,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKxE;AAkBD,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAgEjF;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAC1B,IAAI,EAAE,cAAc,GAAG,SAAS,EAChC,KAAK,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACnG,QAAQ,CAoJV"}