@sagmans/dsh-tui 0.13.0 → 0.14.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 (485) hide show
  1. package/.agents/skills/dsh-tui-dogfood/SKILL.md +18 -2
  2. package/.agents/skills/dsh-tui-dogfood/references/home-state.md +4 -4
  3. package/.agents/skills/dsh-tui-dogfood/scripts/clone-links.mjs +19 -11
  4. package/.agents/skills/dsh-tui-dogfood/scripts/run-plugin-from-worktree.sh +31 -9
  5. package/.agents/skills/dsh-tui-update-models/SKILL.md +1 -1
  6. package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +6 -6
  7. package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +21 -13
  8. package/README.md +61 -23
  9. package/cordis.patch.yml +2 -0
  10. package/lib/agent/fork.d.ts +3 -1
  11. package/lib/agent/fork.d.ts.map +1 -1
  12. package/lib/agent/fork.js +2 -0
  13. package/lib/agent/fork.js.map +1 -1
  14. package/lib/agent/history.d.ts +14 -22
  15. package/lib/agent/history.d.ts.map +1 -1
  16. package/lib/agent/history.js +20 -14
  17. package/lib/agent/history.js.map +1 -1
  18. package/lib/agent/host.d.ts.map +1 -1
  19. package/lib/agent/host.js +6 -0
  20. package/lib/agent/host.js.map +1 -1
  21. package/lib/agent/model.d.ts +10 -8
  22. package/lib/agent/model.d.ts.map +1 -1
  23. package/lib/agent/model.js +9 -7
  24. package/lib/agent/model.js.map +1 -1
  25. package/lib/agent/present.d.ts +1 -1
  26. package/lib/agent/present.d.ts.map +1 -1
  27. package/lib/agent/present.js +1 -1
  28. package/lib/agent/present.js.map +1 -1
  29. package/lib/agent/presets.d.ts +4 -1
  30. package/lib/agent/presets.d.ts.map +1 -1
  31. package/lib/agent/presets.js +9 -2
  32. package/lib/agent/presets.js.map +1 -1
  33. package/lib/agent/projections.d.ts +8 -2
  34. package/lib/agent/projections.d.ts.map +1 -1
  35. package/lib/agent/projections.js +8 -2
  36. package/lib/agent/projections.js.map +1 -1
  37. package/lib/agent/prompt-history.d.ts +8 -48
  38. package/lib/agent/prompt-history.d.ts.map +1 -1
  39. package/lib/agent/prompt-history.js +34 -15
  40. package/lib/agent/prompt-history.js.map +1 -1
  41. package/lib/agent/status.d.ts +9 -24
  42. package/lib/agent/status.d.ts.map +1 -1
  43. package/lib/agent/status.js +7 -2
  44. package/lib/agent/status.js.map +1 -1
  45. package/lib/agent/undo.d.ts +2 -4
  46. package/lib/agent/undo.d.ts.map +1 -1
  47. package/lib/agent/undo.js +10 -5
  48. package/lib/agent/undo.js.map +1 -1
  49. package/lib/cards/composition.d.ts +7 -7
  50. package/lib/cards/composition.d.ts.map +1 -1
  51. package/lib/cards/composition.js +13 -12
  52. package/lib/cards/composition.js.map +1 -1
  53. package/lib/cards/presenter.d.ts +11 -14
  54. package/lib/cards/presenter.d.ts.map +1 -1
  55. package/lib/cards/presenter.js +40 -19
  56. package/lib/cards/presenter.js.map +1 -1
  57. package/lib/cards/preview.d.ts.map +1 -1
  58. package/lib/cards/preview.js +5 -1
  59. package/lib/cards/preview.js.map +1 -1
  60. package/lib/cards.d.ts +17 -23
  61. package/lib/cards.d.ts.map +1 -1
  62. package/lib/cards.js +27 -12
  63. package/lib/cards.js.map +1 -1
  64. package/lib/compat/probe.d.ts +2 -5
  65. package/lib/compat/probe.d.ts.map +1 -1
  66. package/lib/compat/probe.js +2 -2
  67. package/lib/compat/probe.js.map +1 -1
  68. package/lib/compat/section.d.ts +5 -4
  69. package/lib/compat/section.d.ts.map +1 -1
  70. package/lib/compat/section.js +4 -0
  71. package/lib/compat/section.js.map +1 -1
  72. package/lib/config.d.ts +0 -3
  73. package/lib/config.d.ts.map +1 -1
  74. package/lib/config.js +7 -1
  75. package/lib/config.js.map +1 -1
  76. package/lib/export.d.ts +5 -7
  77. package/lib/export.d.ts.map +1 -1
  78. package/lib/export.js +48 -10
  79. package/lib/export.js.map +1 -1
  80. package/lib/fold-cursor.d.ts +3 -3
  81. package/lib/fold-cursor.d.ts.map +1 -1
  82. package/lib/fold-cursor.js +5 -3
  83. package/lib/fold-cursor.js.map +1 -1
  84. package/lib/gates/question-card.d.ts +3 -38
  85. package/lib/gates/question-card.d.ts.map +1 -1
  86. package/lib/gates/question-card.js +13 -10
  87. package/lib/gates/question-card.js.map +1 -1
  88. package/lib/gates/questions.d.ts +14 -8
  89. package/lib/gates/questions.d.ts.map +1 -1
  90. package/lib/gates/questions.js +16 -12
  91. package/lib/gates/questions.js.map +1 -1
  92. package/lib/gates.d.ts +17 -25
  93. package/lib/gates.d.ts.map +1 -1
  94. package/lib/gates.js +2 -4
  95. package/lib/gates.js.map +1 -1
  96. package/lib/herdr/client.d.ts +10 -12
  97. package/lib/herdr/client.d.ts.map +1 -1
  98. package/lib/herdr/client.js +9 -8
  99. package/lib/herdr/client.js.map +1 -1
  100. package/lib/herdr/constants.d.ts +3 -2
  101. package/lib/herdr/constants.d.ts.map +1 -1
  102. package/lib/herdr/constants.js +3 -2
  103. package/lib/herdr/constants.js.map +1 -1
  104. package/lib/herdr/reporter.d.ts +4 -39
  105. package/lib/herdr/reporter.d.ts.map +1 -1
  106. package/lib/herdr/reporter.js +13 -19
  107. package/lib/herdr/reporter.js.map +1 -1
  108. package/lib/herdr/state.d.ts +4 -3
  109. package/lib/herdr/state.d.ts.map +1 -1
  110. package/lib/herdr/state.js +6 -5
  111. package/lib/herdr/state.js.map +1 -1
  112. package/lib/host/preset-files.d.ts +0 -17
  113. package/lib/host/preset-files.d.ts.map +1 -1
  114. package/lib/host/preset-files.js +7 -2
  115. package/lib/host/preset-files.js.map +1 -1
  116. package/lib/host/roster.d.ts +1 -1
  117. package/lib/host/roster.d.ts.map +1 -1
  118. package/lib/host/roster.js +3 -3
  119. package/lib/host/roster.js.map +1 -1
  120. package/lib/host/runner.d.ts +2 -5
  121. package/lib/host/runner.d.ts.map +1 -1
  122. package/lib/host/runner.js +2 -5
  123. package/lib/host/runner.js.map +1 -1
  124. package/lib/identity.d.ts +6 -3
  125. package/lib/identity.d.ts.map +1 -1
  126. package/lib/identity.js +18 -3
  127. package/lib/identity.js.map +1 -1
  128. package/lib/index.d.ts +2 -0
  129. package/lib/index.d.ts.map +1 -1
  130. package/lib/index.js +42 -14
  131. package/lib/index.js.map +1 -1
  132. package/lib/injection.d.ts.map +1 -1
  133. package/lib/injection.js +1 -0
  134. package/lib/injection.js.map +1 -1
  135. package/lib/input/action-catalog.d.ts.map +1 -1
  136. package/lib/input/action-catalog.js +4 -0
  137. package/lib/input/action-catalog.js.map +1 -1
  138. package/lib/input/actions.d.ts +4 -3
  139. package/lib/input/actions.d.ts.map +1 -1
  140. package/lib/input/actions.js +8 -3
  141. package/lib/input/actions.js.map +1 -1
  142. package/lib/input/completion.d.ts +3 -11
  143. package/lib/input/completion.d.ts.map +1 -1
  144. package/lib/input/completion.js +4 -4
  145. package/lib/input/completion.js.map +1 -1
  146. package/lib/input/file-index.d.ts +1 -12
  147. package/lib/input/file-index.d.ts.map +1 -1
  148. package/lib/input/file-index.js +21 -17
  149. package/lib/input/file-index.js.map +1 -1
  150. package/lib/input/file-search.d.ts +4 -3
  151. package/lib/input/file-search.d.ts.map +1 -1
  152. package/lib/input/file-search.js +8 -5
  153. package/lib/input/file-search.js.map +1 -1
  154. package/lib/input/fuzzy.d.ts +6 -12
  155. package/lib/input/fuzzy.d.ts.map +1 -1
  156. package/lib/input/fuzzy.js +18 -27
  157. package/lib/input/fuzzy.js.map +1 -1
  158. package/lib/input/ghost.d.ts +5 -5
  159. package/lib/input/ghost.d.ts.map +1 -1
  160. package/lib/input/ghost.js +4 -3
  161. package/lib/input/ghost.js.map +1 -1
  162. package/lib/input/key-press.d.ts +8 -7
  163. package/lib/input/key-press.d.ts.map +1 -1
  164. package/lib/input/key-press.js +8 -6
  165. package/lib/input/key-press.js.map +1 -1
  166. package/lib/input/keymap-conflicts.d.ts +6 -6
  167. package/lib/input/keymap-conflicts.d.ts.map +1 -1
  168. package/lib/input/keymap-conflicts.js +6 -6
  169. package/lib/input/keymap-conflicts.js.map +1 -1
  170. package/lib/input/keymap.d.ts +6 -18
  171. package/lib/input/keymap.d.ts.map +1 -1
  172. package/lib/input/keymap.js +7 -10
  173. package/lib/input/keymap.js.map +1 -1
  174. package/lib/input/match.js +4 -4
  175. package/lib/input/match.js.map +1 -1
  176. package/lib/input/submission.d.ts +7 -3
  177. package/lib/input/submission.d.ts.map +1 -1
  178. package/lib/input/submission.js +2 -2
  179. package/lib/input/submission.js.map +1 -1
  180. package/lib/input/workspace-files.d.ts +1 -2
  181. package/lib/input/workspace-files.d.ts.map +1 -1
  182. package/lib/input/workspace-files.js +20 -11
  183. package/lib/input/workspace-files.js.map +1 -1
  184. package/lib/input.d.ts.map +1 -1
  185. package/lib/input.js +3 -1
  186. package/lib/input.js.map +1 -1
  187. package/lib/install-skills.d.ts +5 -22
  188. package/lib/install-skills.d.ts.map +1 -1
  189. package/lib/install-skills.js +18 -18
  190. package/lib/install-skills.js.map +1 -1
  191. package/lib/jobs.d.ts +10 -5
  192. package/lib/jobs.d.ts.map +1 -1
  193. package/lib/jobs.js +39 -13
  194. package/lib/jobs.js.map +1 -1
  195. package/lib/keymaps.d.ts.map +1 -1
  196. package/lib/keymaps.js +2 -0
  197. package/lib/keymaps.js.map +1 -1
  198. package/lib/keys-command.d.ts +1 -1
  199. package/lib/keys-command.d.ts.map +1 -1
  200. package/lib/model-list.d.ts +0 -27
  201. package/lib/model-list.d.ts.map +1 -1
  202. package/lib/model-list.js +1 -1
  203. package/lib/model-list.js.map +1 -1
  204. package/lib/moshi.d.ts +13 -0
  205. package/lib/moshi.d.ts.map +1 -0
  206. package/lib/moshi.js +130 -0
  207. package/lib/moshi.js.map +1 -0
  208. package/lib/spacing.d.ts +0 -7
  209. package/lib/spacing.d.ts.map +1 -1
  210. package/lib/spacing.js +1 -1
  211. package/lib/spacing.js.map +1 -1
  212. package/lib/startup.d.ts +1 -1
  213. package/lib/startup.d.ts.map +1 -1
  214. package/lib/startup.js +9 -1
  215. package/lib/startup.js.map +1 -1
  216. package/lib/stash/lock.d.ts +1 -37
  217. package/lib/stash/lock.d.ts.map +1 -1
  218. package/lib/stash/lock.js +41 -35
  219. package/lib/stash/lock.js.map +1 -1
  220. package/lib/stash/paths.d.ts +8 -7
  221. package/lib/stash/paths.d.ts.map +1 -1
  222. package/lib/stash/paths.js +21 -17
  223. package/lib/stash/paths.js.map +1 -1
  224. package/lib/stash/private-fs.d.ts +14 -5
  225. package/lib/stash/private-fs.d.ts.map +1 -1
  226. package/lib/stash/private-fs.js +30 -8
  227. package/lib/stash/private-fs.js.map +1 -1
  228. package/lib/stash/schema.d.ts +3 -6
  229. package/lib/stash/schema.d.ts.map +1 -1
  230. package/lib/stash/schema.js +11 -9
  231. package/lib/stash/schema.js.map +1 -1
  232. package/lib/stash/store.d.ts +9 -40
  233. package/lib/stash/store.d.ts.map +1 -1
  234. package/lib/stash/store.js +26 -24
  235. package/lib/stash/store.js.map +1 -1
  236. package/lib/stash.d.ts +7 -11
  237. package/lib/stash.d.ts.map +1 -1
  238. package/lib/stash.js +18 -11
  239. package/lib/stash.js.map +1 -1
  240. package/lib/subagents.d.ts +9 -9
  241. package/lib/subagents.d.ts.map +1 -1
  242. package/lib/subagents.js +19 -18
  243. package/lib/subagents.js.map +1 -1
  244. package/lib/surface/appearance-preferences.d.ts.map +1 -1
  245. package/lib/surface/appearance-preferences.js +7 -0
  246. package/lib/surface/appearance-preferences.js.map +1 -1
  247. package/lib/surface/appearance.d.ts.map +1 -1
  248. package/lib/surface/appearance.js +7 -2
  249. package/lib/surface/appearance.js.map +1 -1
  250. package/lib/surface/background-work.d.ts +2 -0
  251. package/lib/surface/background-work.d.ts.map +1 -1
  252. package/lib/surface/background-work.js +45 -36
  253. package/lib/surface/background-work.js.map +1 -1
  254. package/lib/surface/commands.d.ts.map +1 -1
  255. package/lib/surface/commands.js +17 -9
  256. package/lib/surface/commands.js.map +1 -1
  257. package/lib/surface/modal-input.d.ts +3 -0
  258. package/lib/surface/modal-input.d.ts.map +1 -1
  259. package/lib/surface/modal-input.js +4 -1
  260. package/lib/surface/modal-input.js.map +1 -1
  261. package/lib/surface/model-choice.d.ts.map +1 -1
  262. package/lib/surface/model-choice.js +10 -8
  263. package/lib/surface/model-choice.js.map +1 -1
  264. package/lib/surface/plugin-actions.d.ts.map +1 -1
  265. package/lib/surface/plugin-actions.js +4 -0
  266. package/lib/surface/plugin-actions.js.map +1 -1
  267. package/lib/surface/preset-choice.d.ts.map +1 -1
  268. package/lib/surface/preset-choice.js +15 -17
  269. package/lib/surface/preset-choice.js.map +1 -1
  270. package/lib/surface/prompt-input.js +1 -1
  271. package/lib/surface/prompt-input.js.map +1 -1
  272. package/lib/surface/prompt-memory.d.ts +7 -6
  273. package/lib/surface/prompt-memory.d.ts.map +1 -1
  274. package/lib/surface/prompt-memory.js +3 -3
  275. package/lib/surface/session-lifecycle.d.ts +7 -1
  276. package/lib/surface/session-lifecycle.d.ts.map +1 -1
  277. package/lib/surface/session-lifecycle.js +17 -12
  278. package/lib/surface/session-lifecycle.js.map +1 -1
  279. package/lib/surface/session-picker.js +1 -1
  280. package/lib/surface/session-picker.js.map +1 -1
  281. package/lib/surface/session-view.d.ts +1 -1
  282. package/lib/surface/session-view.d.ts.map +1 -1
  283. package/lib/surface/session-view.js +4 -5
  284. package/lib/surface/session-view.js.map +1 -1
  285. package/lib/surface/staged-turns.d.ts.map +1 -1
  286. package/lib/surface/staged-turns.js +8 -4
  287. package/lib/surface/staged-turns.js.map +1 -1
  288. package/lib/surface/terminal-lifecycle.d.ts +1 -1
  289. package/lib/surface/terminal-lifecycle.d.ts.map +1 -1
  290. package/lib/surface/terminal-lifecycle.js +8 -5
  291. package/lib/surface/terminal-lifecycle.js.map +1 -1
  292. package/lib/terminal/bell.d.ts +0 -2
  293. package/lib/terminal/bell.d.ts.map +1 -1
  294. package/lib/terminal/bell.js +2 -1
  295. package/lib/terminal/bell.js.map +1 -1
  296. package/lib/terminal/clipboard.d.ts +4 -4
  297. package/lib/terminal/clipboard.js +4 -4
  298. package/lib/terminal/external-editor.d.ts +4 -60
  299. package/lib/terminal/external-editor.d.ts.map +1 -1
  300. package/lib/terminal/external-editor.js +28 -40
  301. package/lib/terminal/external-editor.js.map +1 -1
  302. package/lib/terminal/host-writes.d.ts +7 -18
  303. package/lib/terminal/host-writes.d.ts.map +1 -1
  304. package/lib/terminal/host-writes.js +9 -14
  305. package/lib/terminal/host-writes.js.map +1 -1
  306. package/lib/terminal/input.d.ts +6 -0
  307. package/lib/terminal/input.d.ts.map +1 -0
  308. package/lib/terminal/input.js +15 -0
  309. package/lib/terminal/input.js.map +1 -0
  310. package/lib/terminal/restore.d.ts +2 -1
  311. package/lib/terminal/restore.d.ts.map +1 -1
  312. package/lib/terminal/signals.d.ts +2 -1
  313. package/lib/terminal/signals.d.ts.map +1 -1
  314. package/lib/terminal/signals.js +1 -1
  315. package/lib/terminal/signals.js.map +1 -1
  316. package/lib/terminal/title.d.ts +1 -11
  317. package/lib/terminal/title.d.ts.map +1 -1
  318. package/lib/terminal/title.js +5 -4
  319. package/lib/terminal/title.js.map +1 -1
  320. package/lib/terminal/warning-screen.d.ts +2 -0
  321. package/lib/terminal/warning-screen.d.ts.map +1 -1
  322. package/lib/terminal/warning-screen.js +21 -3
  323. package/lib/terminal/warning-screen.js.map +1 -1
  324. package/lib/terminal-text/scan.d.ts +4 -5
  325. package/lib/terminal-text/scan.d.ts.map +1 -1
  326. package/lib/terminal-text/scan.js +16 -9
  327. package/lib/terminal-text/scan.js.map +1 -1
  328. package/lib/terminal-text/sgr.d.ts +4 -3
  329. package/lib/terminal-text/sgr.d.ts.map +1 -1
  330. package/lib/terminal-text/sgr.js +9 -14
  331. package/lib/terminal-text/sgr.js.map +1 -1
  332. package/lib/terminal-text.d.ts +7 -12
  333. package/lib/terminal-text.d.ts.map +1 -1
  334. package/lib/terminal-text.js +31 -28
  335. package/lib/terminal-text.js.map +1 -1
  336. package/lib/text.d.ts +8 -14
  337. package/lib/text.d.ts.map +1 -1
  338. package/lib/text.js +14 -15
  339. package/lib/text.js.map +1 -1
  340. package/lib/theme-capability.d.ts +3 -15
  341. package/lib/theme-capability.d.ts.map +1 -1
  342. package/lib/theme-capability.js +18 -15
  343. package/lib/theme-capability.js.map +1 -1
  344. package/lib/theme-defaults.d.ts +3 -57
  345. package/lib/theme-defaults.d.ts.map +1 -1
  346. package/lib/theme-defaults.js +25 -14
  347. package/lib/theme-defaults.js.map +1 -1
  348. package/lib/theme-files.d.ts +16 -32
  349. package/lib/theme-files.d.ts.map +1 -1
  350. package/lib/theme-files.js +43 -27
  351. package/lib/theme-files.js.map +1 -1
  352. package/lib/theme-resolver.d.ts +3 -3
  353. package/lib/theme-resolver.d.ts.map +1 -1
  354. package/lib/theme-resolver.js +9 -6
  355. package/lib/theme-resolver.js.map +1 -1
  356. package/lib/theme-schema.d.ts +7 -42
  357. package/lib/theme-schema.d.ts.map +1 -1
  358. package/lib/theme-schema.js +9 -11
  359. package/lib/theme-schema.js.map +1 -1
  360. package/lib/theme-settings.d.ts +19 -10
  361. package/lib/theme-settings.d.ts.map +1 -1
  362. package/lib/theme-settings.js +23 -17
  363. package/lib/theme-settings.js.map +1 -1
  364. package/lib/theme-tokens.d.ts +6 -12
  365. package/lib/theme-tokens.d.ts.map +1 -1
  366. package/lib/theme-tokens.js +2 -2
  367. package/lib/theme-tokens.js.map +1 -1
  368. package/lib/theme.d.ts +5 -10
  369. package/lib/theme.d.ts.map +1 -1
  370. package/lib/theme.js +11 -18
  371. package/lib/theme.js.map +1 -1
  372. package/lib/todo-guard.d.ts +8 -4
  373. package/lib/todo-guard.d.ts.map +1 -1
  374. package/lib/todo-guard.js +17 -6
  375. package/lib/todo-guard.js.map +1 -1
  376. package/lib/tokens.d.ts +0 -2
  377. package/lib/tokens.d.ts.map +1 -1
  378. package/lib/tokens.js +1 -1
  379. package/lib/tokens.js.map +1 -1
  380. package/lib/tool-display.d.ts +1 -13
  381. package/lib/tool-display.d.ts.map +1 -1
  382. package/lib/tool-display.js +4 -4
  383. package/lib/tool-display.js.map +1 -1
  384. package/lib/transcript/message-content.d.ts.map +1 -1
  385. package/lib/transcript/message-content.js +31 -9
  386. package/lib/transcript/message-content.js.map +1 -1
  387. package/lib/transcript/tool-calls.d.ts +9 -7
  388. package/lib/transcript/tool-calls.d.ts.map +1 -1
  389. package/lib/transcript/tool-calls.js +27 -20
  390. package/lib/transcript/tool-calls.js.map +1 -1
  391. package/lib/transcript.d.ts +10 -18
  392. package/lib/transcript.d.ts.map +1 -1
  393. package/lib/transcript.js +40 -28
  394. package/lib/transcript.js.map +1 -1
  395. package/lib/ui/copy.d.ts +5 -4
  396. package/lib/ui/copy.d.ts.map +1 -1
  397. package/lib/ui/copy.js +9 -6
  398. package/lib/ui/copy.js.map +1 -1
  399. package/lib/ui/diff.d.ts +0 -30
  400. package/lib/ui/diff.d.ts.map +1 -1
  401. package/lib/ui/diff.js +16 -9
  402. package/lib/ui/diff.js.map +1 -1
  403. package/lib/ui/dock.d.ts +4 -10
  404. package/lib/ui/dock.d.ts.map +1 -1
  405. package/lib/ui/dock.js +10 -14
  406. package/lib/ui/dock.js.map +1 -1
  407. package/lib/ui/editor.d.ts +4 -3
  408. package/lib/ui/editor.d.ts.map +1 -1
  409. package/lib/ui/editor.js +2 -2
  410. package/lib/ui/editor.js.map +1 -1
  411. package/lib/ui/frame.d.ts +4 -12
  412. package/lib/ui/frame.d.ts.map +1 -1
  413. package/lib/ui/frame.js +6 -6
  414. package/lib/ui/frame.js.map +1 -1
  415. package/lib/ui/gap.d.ts +0 -4
  416. package/lib/ui/gap.d.ts.map +1 -1
  417. package/lib/ui/gap.js +4 -3
  418. package/lib/ui/gap.js.map +1 -1
  419. package/lib/ui/gate-input.d.ts +3 -3
  420. package/lib/ui/gate-input.d.ts.map +1 -1
  421. package/lib/ui/gate-input.js +9 -9
  422. package/lib/ui/gate-input.js.map +1 -1
  423. package/lib/ui/layout.d.ts +1 -8
  424. package/lib/ui/layout.d.ts.map +1 -1
  425. package/lib/ui/layout.js +5 -3
  426. package/lib/ui/layout.js.map +1 -1
  427. package/lib/ui/markdown.d.ts +3 -5
  428. package/lib/ui/markdown.d.ts.map +1 -1
  429. package/lib/ui/markdown.js +18 -7
  430. package/lib/ui/markdown.js.map +1 -1
  431. package/lib/ui/mermaid.d.ts +0 -11
  432. package/lib/ui/mermaid.d.ts.map +1 -1
  433. package/lib/ui/mermaid.js +32 -17
  434. package/lib/ui/mermaid.js.map +1 -1
  435. package/lib/ui/picker-card.d.ts +4 -8
  436. package/lib/ui/picker-card.d.ts.map +1 -1
  437. package/lib/ui/picker-card.js +17 -15
  438. package/lib/ui/picker-card.js.map +1 -1
  439. package/lib/ui/picker.d.ts +10 -17
  440. package/lib/ui/picker.d.ts.map +1 -1
  441. package/lib/ui/picker.js +14 -8
  442. package/lib/ui/picker.js.map +1 -1
  443. package/lib/ui/stash-picker.d.ts +1 -10
  444. package/lib/ui/stash-picker.d.ts.map +1 -1
  445. package/lib/ui/stash-picker.js +4 -4
  446. package/lib/ui/stash-picker.js.map +1 -1
  447. package/lib/ui/status.d.ts +2 -19
  448. package/lib/ui/status.d.ts.map +1 -1
  449. package/lib/ui/status.js +15 -17
  450. package/lib/ui/status.js.map +1 -1
  451. package/lib/ui/view/document.d.ts +4 -1
  452. package/lib/ui/view/document.d.ts.map +1 -1
  453. package/lib/ui/view/document.js +15 -6
  454. package/lib/ui/view/document.js.map +1 -1
  455. package/lib/ui/view/gate-card.d.ts +2 -0
  456. package/lib/ui/view/gate-card.d.ts.map +1 -1
  457. package/lib/ui/view/gate-card.js +12 -10
  458. package/lib/ui/view/gate-card.js.map +1 -1
  459. package/lib/ui/view/tool-card.d.ts +7 -4
  460. package/lib/ui/view/tool-card.d.ts.map +1 -1
  461. package/lib/ui/view/tool-card.js +12 -17
  462. package/lib/ui/view/tool-card.js.map +1 -1
  463. package/lib/ui/view/transcript-message.d.ts +7 -7
  464. package/lib/ui/view/transcript-message.d.ts.map +1 -1
  465. package/lib/ui/view/transcript-message.js +19 -10
  466. package/lib/ui/view/transcript-message.js.map +1 -1
  467. package/lib/ui/view.d.ts +8 -8
  468. package/lib/ui/view.d.ts.map +1 -1
  469. package/lib/ui/view.js +11 -13
  470. package/lib/ui/view.js.map +1 -1
  471. package/lib/work.d.ts +13 -10
  472. package/lib/work.d.ts.map +1 -1
  473. package/lib/work.js +30 -8
  474. package/lib/work.js.map +1 -1
  475. package/package.json +11 -7
  476. package/presets/cordis.patch.yml +1 -0
  477. package/presets/minimal.patch.yml +1 -0
  478. package/presets/ptc.patch.yml +1 -0
  479. package/presets/standard.patch.yml +1 -0
  480. package/themes/deepseek-blue.yaml +38 -51
  481. package/themes/marine-static.yaml +27 -35
  482. package/themes/pine-slope.yaml +13 -11
  483. package/themes/polar-drift.yaml +6 -0
  484. package/themes/violet-orbit.yaml +14 -18
  485. package/themes/wine-thicket.yaml +13 -13
@@ -4,6 +4,21 @@ description: "Use when a dsh plugin checkout must be tested against a real profi
4
4
  ---
5
5
  # Dogfood a dsh plugin checkout
6
6
 
7
+ For a dsh-tui checkout, run `pnpm verify` after development. It runs golden
8
+ frames and all free dogfood scenarios automatically. `pnpm dogfood` starts the
9
+ installed Harness with the base bundle and worktree in credential-free scratch
10
+ homes. In a Herdr-managed caller, the same free gate also runs real native-pane workflows in an owned disposable named session.
11
+ Without that prerequisite, Herdr evidence remains `environment-not-run`; portable PTY checks still run.
12
+ When tmux is installed, the free gate also verifies its private server and actual restoration.
13
+ Native controllers do not launch the caller's configured shell or source its startup files.
14
+ Read `FEATURES.md` in the checkout for scope and evidence rules.
15
+
16
+ Paid live-model use requires an explicit human request. List scenarios with
17
+ `pnpm dogfood:paid --list`, then select one with `--scenario`, `--home`,
18
+ `--provider`, and `--model`. Use a cloned profile for its credentials and model
19
+ adapter. Never submit a model prompt automatically, even a short smoke prompt.
20
+
21
+
7
22
  A fresh `DSH_HOME` misses the installed bundles, profile patch, settings, and themes.
8
23
  A run against the real home writes real sessions and state. Clone the source
9
24
  home and relink only the plugin under test inside the clone.
@@ -23,8 +38,9 @@ runs `pnpm run build` only when the checkout declares a build script. It adds
23
38
  the bundle once if absent from the cloned profile, updates only its dependency,
24
39
  restores local links from `link:` specifications, and launches
25
40
  `dsh --profile tui` by default. For this TUI, the packaged helper checks
26
- the launcher against compatible releases in the checkout’s `package.json` before
27
- cloning. This checkout uses the installed `dsh 0.2.0-rc.2` line for PTY tests. Never
41
+ the launcher against `dsh.compatibility.dshReleases` in the checkout’s
42
+ `package.json` before cloning, not against the declared version range. This
43
+ checkout lists only installed `dsh 0.2.0-rc.2` as verified for PTY tests. Never
28
44
  substitute `pnpm dsh` or a `--dsh` path from a Harness source checkout: that
29
45
  host may migrate the cloned `settings.yaml`. The legacy
30
46
  `scripts/dogfood/run-tui-from-worktree.sh` remains available in dsh-tui and
@@ -8,7 +8,7 @@ profile. It gives the operational detail behind [../SKILL.md](../SKILL.md).
8
8
  | Entry | Kind | What reads or writes it |
9
9
  | --- | --- | --- |
10
10
  | `.credentials.yaml` | secret | the provider layer, at start-up; read-only |
11
- | `settings.yaml`, `settings.yaml.imported` | config | the `dsh-tui:` section: theme, tokens, dock, stash, prompt history |
11
+ | `settings.yaml`, `settings.yaml.imported` | legacy config | On verified `0.2.0-rc.2`, settings migration renames the file before attempting a one-time import into profile entries. Rejected sections remain in `.imported`; neither file is the live TUI configuration. |
12
12
  | `themes/` | data | created and watched at start-up; saving a file changes the live surface |
13
13
  | `prompt-history.json` | data | the editor's history recall; appended as prompts are sent |
14
14
  | `tui-stash/` | data | the parked-draft bank, one file per session, behind a lock |
@@ -20,9 +20,9 @@ profile. It gives the operational detail behind [../SKILL.md](../SKILL.md).
20
20
 
21
21
  ## Home state versus profile state
22
22
 
23
- Credentials, settings, themes, history, the stash, storages, and sessions belong
24
- to the **home**: every profile in it shares them. The bundle list and the patch
25
- overlay belong to the **profile**: a new profile name starts from the base plus
23
+ Credentials, themes, history, the stash, storages, and sessions belong to the
24
+ **home**: every profile in it shares them. On verified `0.2.0-rc.2`, live settings,
25
+ the bundle list, and the patch overlay belong to the **profile**: a new profile name starts from the base plus
26
26
  whatever is added to it, and inherits none of another profile's bundles or
27
27
  patches. That is the trap behind "test it in a profile named after the feature" —
28
28
  the run is compositionally thinner than the developer's own while still writing
@@ -2,14 +2,12 @@
2
2
  /**
3
3
  * Link policy for the dogfood clone.
4
4
  *
5
- * A cloned home is a sandbox: a dogfood run may write only inside it. Two kinds
6
- * of link are legitimate there — a package entry that resolves to an installed
7
- * package or another checkout, and a link that stays inside the clone. A link
8
- * that escapes is either copied in or refused, and which one depends on who
9
- * writes the entry: the instruction files below are only read, so the bytes come
10
- * along; everything else (credentials, settings, storages, sessions, profiles)
11
- * is state the run may write, and a link out of the clone would let that write
12
- * reach the developer's own home. Refusing is the safe answer there.
5
+ * Protect mutable home state from writes reaching the source home. Package
6
+ * links remain external for dependency loading; writes through them are not
7
+ * isolated. Other links must stay inside the clone. The instruction files below
8
+ * are only read, so their external targets can be copied into the clone instead
9
+ * of blocking a run. Refuse escaping links for other home entries so writes
10
+ * cannot follow them into the developer's own home.
13
11
  *
14
12
  * Usage: clone-links.mjs check|materialize <home> <source>
15
13
  */
@@ -25,8 +23,9 @@ import { pathToFileURL } from 'node:url'
25
23
  export const INSTRUCTION_ENTRIES = new Set(['AGENTS.md', 'CLAUDE.md'])
26
24
 
27
25
  /**
28
- * Paths whose whole purpose is to point at an installed package, which may live
29
- * outside the clone. A link here is expected; a link anywhere else is not.
26
+ * Package entries may resolve externally so cloned profiles can load installed
27
+ * packages or checkouts, except source-home targets. Other retained links must stay
28
+ * inside the clone to keep home-state writes local.
30
29
  */
31
30
  export const packageEntry = (parts) => parts[0] === 'profiles' && (
32
31
  parts[1] === 'node_modules' && parts.length > 2 ||
@@ -34,8 +33,14 @@ export const packageEntry = (parts) => parts[0] === 'profiles' && (
34
33
  parts[2] === '.dsh-module-fallback' && parts[3] === 'node_modules' && parts.length > 4
35
34
  )
36
35
 
36
+ /**
37
+ * Boundary checks require physical absolute paths; this lexical check cannot resolve aliases.
38
+ * The separator prevents sibling names sharing a prefix from passing the home boundary.
39
+ */
37
40
  export const inside = (root, file) => file === root || file.startsWith(root + path.sep)
38
41
 
42
+ // Keep the read-only exception scoped to home instruction entries; matching names
43
+ // inside mutable state do not establish read-only use.
39
44
  const instruction = (home, file) => {
40
45
  const parts = path.relative(home, file).split(path.sep)
41
46
  return parts.length === 1 && INSTRUCTION_ENTRIES.has(parts[0])
@@ -59,7 +64,6 @@ export function destination(file) {
59
64
  const entries = (root) => fs.readdirSync(root, { withFileTypes: true })
60
65
  const partsOf = (home, file) => path.relative(home, file).split(path.sep)
61
66
 
62
- /** Every reason the clone cannot be run as a sandbox, in the order they are met. */
63
67
  export function problems(home, source) {
64
68
  const found = []
65
69
  const visit = (dir) => {
@@ -73,6 +77,8 @@ export function problems(home, source) {
73
77
  } else if (entry.isDirectory()) {
74
78
  visit(file)
75
79
  } else if (entry.isFile() && !packageEntry(parts) && fs.lstatSync(file).nlink > 1) {
80
+ // Hardlink names share writable contents; the link count cannot prove every name stays inside the clone.
81
+ // Reject non-package hardlinks conservatively rather than risk writes reaching another home.
76
82
  found.push('unsafe cloned hardlink outside package modules: ' + file)
77
83
  }
78
84
  }
@@ -93,6 +99,8 @@ export function materialize(home) {
93
99
  const target = destination(path.resolve(dir, fs.readlinkSync(file)))
94
100
  if (inside(home, target)) continue
95
101
  if (!fs.existsSync(target)) {
102
+ // No instruction content exists to copy; dropping the external link lets
103
+ // boundary validation proceed without retaining an escape path.
96
104
  fs.rmSync(file)
97
105
  console.log('materialize: dropped dangling link ' + path.relative(home, file))
98
106
  report.dropped += 1
@@ -4,8 +4,12 @@ set -euo pipefail
4
4
 
5
5
  name="$(basename "${BASH_SOURCE[0]}")"
6
6
  TUI_PACKAGE_NAME='@sagmans/dsh-tui'
7
+ ISOLATED_ENV_PREFIXES=('HERDR_' 'DSH_TUI_MOSHI_')
8
+ CLEAN_PREVIEW_PREFIX='would remove'
7
9
  # The link policy is shared with the validator, so both read one rule set.
8
10
  helper_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
11
+ # Default to the caller checkout so this packaged helper is not tied to its install location;
12
+ # the legacy wrapper overrides it to remain anchored when invoked from another directory.
9
13
  default_repo="${DSH_DOGFOOD_DEFAULT_REPO:-$PWD}"
10
14
  default_repo="$(cd "$default_repo" && pwd -P)"
11
15
 
@@ -54,6 +58,7 @@ EOF
54
58
 
55
59
  target=""
56
60
  home=""
61
+ # Agent sessions may set DSH_HOME to scratch state, not the developer home to clone.
57
62
  source_home="$HOME/.dsh"
58
63
  profile="tui"
59
64
  dsh_bin="${DSH_BIN:-}"
@@ -93,6 +98,8 @@ if [[ -n "$source_home" ]]; then source_home="${source_home/#\~/$HOME}"; fi
93
98
 
94
99
  # --- the repository's worktrees ---------------------------------------------
95
100
 
101
+ # Git discovery is best-effort so an unavailable registry does not block the
102
+ # sibling-directory fallback; the chosen directory still needs a plugin manifest.
96
103
  worktree_lines() {
97
104
  git -C "$default_repo" worktree list --porcelain 2>/dev/null || true
98
105
  }
@@ -143,6 +150,8 @@ resolve_target() {
143
150
  local hit sibling
144
151
  hit="$(resolve_by_name "$target")"
145
152
  if [[ -z "$hit" ]]; then
153
+ # Anchor sibling lookup to the selected repository, not the caller's cwd,
154
+ # so neighboring plugin checkouts need not appear in its Git worktree registry.
146
155
  sibling="$(cd "$default_repo/.." 2>/dev/null && pwd -P)/$target"
147
156
  if [[ -d "$sibling" ]]; then hit="$sibling"; fi
148
157
  fi
@@ -195,6 +204,7 @@ else
195
204
  [[ -d "$source_home" ]] || die "no home to clone at $source_home; pass --source-home"
196
205
  source_home="$(cd "$source_home" && pwd -P)"
197
206
  fi
207
+ # Physical paths keep parent symlink aliases from bypassing overlap checks.
198
208
  [[ ! -L "$home" ]] || die "scratch home cannot be a symlink: $home"
199
209
  home="$(node -e "const fs=require('node:fs'),p=require('node:path');let x=p.resolve(process.argv[1]),b=x;while(!fs.existsSync(b))b=p.dirname(b);console.log(p.join(fs.realpathSync(b),p.relative(b,x)))" "$home")"
200
210
  [[ ! -L "$home" ]] || die "scratch home cannot be a symlink: $home"
@@ -203,10 +213,12 @@ user_home="$(cd "$HOME" && pwd -P)"
203
213
  [[ "$home/" != "$user_home/"* && "$user_home/" != "$home/"* ]] || die "scratch home cannot overlap the user home"
204
214
  [[ "$home/" != "$target_path/"* && "$target_path/" != "$home/"* ]] || die "scratch home cannot overlap the target checkout"
205
215
  [[ "$home" != / ]] || die "scratch home cannot be filesystem root"
216
+ # Marker identities occupy one line each; embedded newlines would break identity checks.
206
217
  for path in "$home" "$source_home" "$target_path"; do [[ "$path" != *$'\n'* ]] || die "paths cannot contain newlines"; done
207
218
  marker="$home/.dsh-dogfood"
208
219
  profile_json="$home/profiles/$profile/package.json"
209
220
 
221
+ # Credential permission changes must not affect a shared inode or an external symlink target.
210
222
  check_credentials() {
211
223
  [[ ! -L "$home/.credentials.yaml" ]] || die "cloned credentials cannot be a symlink"
212
224
  [[ -e "$home/.credentials.yaml" ]] || return 0
@@ -253,6 +265,11 @@ fi
253
265
  if [[ "$action" == "clean" ]]; then
254
266
  [[ -d "$home" ]] || { note "nothing at $home"; exit 0; }
255
267
  validate_marker
268
+ # Preview must honor cleanup guards without deleting the state being inspected.
269
+ if [[ "$dry_run" == 1 ]]; then
270
+ note "$CLEAN_PREVIEW_PREFIX $home"
271
+ exit 0
272
+ fi
256
273
  rm -rf "$home"
257
274
  note "removed $home"
258
275
  exit 0
@@ -285,9 +302,8 @@ fi
285
302
 
286
303
  if [[ -d "$home" && "$action" != "clean" && "$dry_run" != 1 ]]; then
287
304
  validate_marker
288
- # A marker that still reads 0 belongs to a run the kernel killed before it could
289
- # clean up: the identity matches, so --reseed takes it, but nothing may reuse a
290
- # home whose copy stopped halfway. A marker without the line predates this.
305
+ # Copy or later setup failures can leave ready=0; require --reseed rather than
306
+ # reuse an incomplete clone.
291
307
  [[ "$reseed" == 1 ]] || [[ "$(marker_value ready)" != 0 ]] || die "$home is a half-seeded clone; pass --reseed to clone it again"
292
308
  check_credentials
293
309
  chmod 700 "$home"
@@ -311,7 +327,7 @@ if [[ ! -d "$home" ]]; then
311
327
  chmod 700 "$home"
312
328
  # Written before the copy, so whatever the copy does this directory is one that
313
329
  # --clean and --reseed already own: an interrupted clone is recoverable rather
314
- # than a husk neither action will touch. The copy marks it ready when it lands.
330
+ # than a husk neither action will touch. It becomes reusable only after setup.
315
331
  printf 'home=%s\nsource=%s\ntarget=%s\nprofile=%s\nready=0\n' "$home" "$source_home" "$target_path" "$profile" > "$marker"
316
332
  chmod 600 "$marker"
317
333
  if [[ "$fresh" == 1 ]]; then
@@ -342,6 +358,7 @@ check_clone_links
342
358
 
343
359
  # --- build, link, run --------------------------------------------------------
344
360
 
361
+ # Linked TUI profiles load lib/, not src/, so rebuilding makes source edits visible to the run.
345
362
  if [[ "$build" == 1 && ! -d "$target_path/node_modules" ]]; then
346
363
  die "$target_path has no node_modules; run pnpm install there first (or pass --no-build)"
347
364
  fi
@@ -392,6 +409,8 @@ const state = (file) => fs.lstatSync(file, { throwIfNoEntry: false })
392
409
  for (const part of [directory, path.dirname(directory), moduleDir]) {
393
410
  if (state(part)?.isSymbolicLink()) throw Error("unsafe symlink in profile path: " + part)
394
411
  }
412
+ // Reject invalid names and unsafe existing destinations before replacing links;
413
+ // target-boundary checks run afterward and do not roll back earlier relinking.
395
414
  for (const [name, spec] of entries) {
396
415
  if (!packagePattern.test(name)) throw Error("invalid link dependency name: " + name)
397
416
  if (name.includes("\n") || spec.includes("\n") || spec.includes("\0")) throw Error("unsafe link dependency: " + name)
@@ -417,8 +436,8 @@ if ! node -e "process.exit(require(process.argv[1]).dsh.profile.bundles.includes
417
436
  die "profile '$profile' does not list $package_name after relink (bundles: $bundles)"
418
437
  fi
419
438
 
420
- # The home is finished: it points at the target and its bundles answer, so it is
421
- # ready to be reused rather than re-seeded.
439
+ # Completed setup permits clone reuse; link safety and bundle membership checks
440
+ # do not prove that the bundles load or answer at runtime.
422
441
  printf 'home=%s\nsource=%s\ntarget=%s\nprofile=%s\nready=1\n' "$home" "$source_home" "$target_path" "$profile" > "$marker"
423
442
  chmod 600 "$marker"
424
443
 
@@ -431,9 +450,12 @@ printf 'profile: %s (%s)\n' "$profile" "$bundles" >&2
431
450
  # started with them claims that pane's agent row for this run: the row comes back
432
451
  # released, and the pane's real agent disappears from Herdr's pickers until it is
433
452
  # restarted. The clone is launched as a surface in a bare terminal instead.
434
- while IFS= read -r herdr_var; do
435
- unset "$herdr_var"
436
- done < <(env | sed -n 's/^\(HERDR_[A-Za-z0-9_]*\)=.*/\1/p')
453
+ # Incidental model notifications must not borrow the caller's production token.
454
+ for isolated_prefix in "${ISOLATED_ENV_PREFIXES[@]}"; do
455
+ while IFS= read -r isolated_var; do
456
+ if [[ "$isolated_var" == "$isolated_prefix"* ]]; then unset "$isolated_var"; fi
457
+ done < <(compgen -e)
458
+ done
437
459
 
438
460
  run_command=(env "DSH_HOME=$home" "$dsh_bin" --profile "$profile")
439
461
  if [[ "${#passthrough[@]}" -gt 0 ]]; then
@@ -13,7 +13,7 @@ the ctx gauge. Find the owner first; then edit exactly one place.
13
13
  | Where the wiring is | What it owns |
14
14
  | --- | --- |
15
15
  | `~/.dsh/profiles/<profile>/cordis.patch.yml` | The patch layer: applied after every bundle layer, last entry wins. Holds the catalog or `llm-pi-ai` config a developer actually edits. |
16
- | `~/.dsh/settings.yaml` | Host settings, hot-reloaded. A `llm-pi-ai:` or `llm-deepseek:` section overrides that adapter's patch entry without a restart - it is what the web Models page writes, and what an additive sign-in declares a route in. The legacy `dsh-provider-extra:` section carries `extraModels` and `codexExtraModels` only. **A catalog is never settings-owned**: managed mode installs no section, reads no overlay, and turns off settings projection for its own Config, so the profile patch is the only place a catalog exists. |
16
+ | `~/.dsh/settings.yaml`, `settings.yaml.imported` | Legacy input, not a live overlay on verified `0.2.0-rc.2`. Settings migration renames the file before attempting a one-time import into matching profile entries. Configure adapter rows in the active profile patch. Keep catalog edits in that patch and consult the installed catalog documentation. |
17
17
  | `~/.dsh/profiles/<profile>/package.json` | Bundles and their dependency specs (`link:` for a checkout, a range for a release). |
18
18
  | `node_modules/<bundle>/cordis.patch.yml` | The bundle's own defaults: disabled base rows, inserted rows, default config. |
19
19
  | `node_modules/@earendil-works/pi-ai/dist/providers/data/<source>.json` | Installed per-provider catalog: ids, and the cost/context/effort data a template clone or a `filter` match inherits. |
@@ -12,12 +12,12 @@ Companion to [SKILL.md](../SKILL.md): exact fields, files, and checks.
12
12
  4. The model directory a profile sees is owned by whichever row is enabled:
13
13
  `llm-pi-ai` (additive provider config), `dsh-provider-extra` (owned catalog),
14
14
  or both, if the profile is not using exclusive ownership.
15
- 5. `$DSH_HOME/settings.yaml` sits over the adapter rows, not over a catalog. A
16
- `llm-pi-ai:` or `llm-deepseek:` section reshapes that adapter per request; a
17
- `dsh-provider-extra:` section reshapes only the legacy routes'
18
- `extraModels`/`codexExtraModels`, and only where no `models`/`codexModels`
19
- selection is declared. A managed catalog reads no settings overlay at all, so
20
- a catalog edit lands in the profile patch or nowhere.
15
+ 5. On verified `0.2.0-rc.2`, settings forms read and update Config-backed
16
+ profile entries. `$DSH_HOME/settings.yaml` is legacy input, not a live adapter
17
+ overlay. Migration renames it to `.imported` before a one-time import; rejected
18
+ sections remain only in that renamed file. Edit adapter and catalog config in
19
+ the active profile patch. Do not assume legacy per-request settings behavior
20
+ on a host that exposes only Config-backed forms.
21
21
 
22
22
  Exclusive ownership is a set of disable rows plus the catalog itself:
23
23
 
@@ -1,30 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Print the model directory a dsh profile resolves, with the provenance of
4
- * every field.
3
+ * Inspect the profile's owned catalog and inherited model facts without
4
+ * composing the profile.
5
5
  *
6
6
  * The surface reads prices, context windows, and reasoning levels from the
7
7
  * composition, not from the vendor's page, so an inherited or stale value is
8
8
  * invisible in the UI. This reads the same two inputs the resolver does - the
9
9
  * owned catalog in the profile patch, and the installed pi-ai provider data -
10
- * and names where each number came from: "installed" for the source's own
11
- * entry, "template:<id>" for a clone, "route" for the protocol a sourceless
12
- * route declares once for every model it serves, "metadata" for what the
13
- * catalog declares.
10
+ * to expose inheritance and overrides that the UI does not distinguish.
11
+ * Installed facts are the unlabeled baseline; "template:<id>", "route", and
12
+ * "metadata" identify departures from it.
14
13
  *
15
14
  * An entry the catalog spells out completely needs no installed entry at all,
16
15
  * so a missing harness install must not hide it. A `filter` route is the
17
16
  * exception: its membership is the installed catalog's, so it cannot be read
18
- * without that install. A declaration the plugin's resolver would refuse is
19
- * reported as a refusal here too, because a catalog that cannot compose serves
20
- * nothing.
17
+ * without provider data. Selected resolution checks expose unusable declarations,
18
+ * but this inspection does not validate every template, schema, or ownership rule.
19
+ * Compose the candidate before trusting it as a usable profile.
21
20
  *
22
21
  * Usage: dump-model-catalog.mjs [--home <dsh home>] [--profile <name>]
23
22
  * [--data <pi-ai data dir>] [--json]
24
23
  *
25
- * `--data` names the installed provider-data directory to inherit from, which
26
- * is how a reading is checked where no harness is installed - a `filter` route
27
- * and every template clone need one.
24
+ * `--data` supplies inherited facts when no harness is installed, so filter
25
+ * membership and template-derived values can still be inspected offline.
28
26
  */
29
27
  import { execFileSync } from 'node:child_process'
30
28
  import { readFileSync, realpathSync } from 'node:fs'
@@ -55,6 +53,7 @@ export function supportedLevels(levelMap) {
55
53
  })
56
54
  }
57
55
 
56
+ /** Defaults target the documented TUI patch; DSH_HOME keeps inspection on the caller-selected home. */
58
57
  function parseArgs(argv) {
59
58
  const options = { home: process.env.DSH_HOME ?? join(homedir(), '.dsh'), profile: 'tui', data: undefined, json: false }
60
59
  for (let index = 0; index < argv.length; index += 1) {
@@ -80,7 +79,10 @@ function dataDirectory() {
80
79
  }
81
80
  }
82
81
 
83
- /** Every JSON patch entry that configures the owned catalog, last one winning. */
82
+ /**
83
+ * The catalog:setup flow map is the machine-readable inspection boundary;
84
+ * block YAML needs list-models composition. Later patch entries take precedence.
85
+ */
84
86
  export function catalogConfig(patch) {
85
87
  const lines = readFileSync(patch, 'utf8').split('\n')
86
88
  let catalog
@@ -92,6 +94,10 @@ export function catalogConfig(patch) {
92
94
  return catalog
93
95
  }
94
96
 
97
+ /**
98
+ * Unusable inherited data must not prevent inspection of fully declared models.
99
+ * Read and parse failures lose their diagnostics here; dependent entries get resolution errors instead.
100
+ */
95
101
  export function providerData(directory, source) {
96
102
  if (directory === undefined || source === undefined) return undefined
97
103
  try {
@@ -229,6 +235,8 @@ function rowsOf(catalog, directory) {
229
235
  ...(result.requestMax === undefined ? {} : { requestMax: result.requestMax }),
230
236
  ...(result.aliases === undefined ? {} : { aliases: result.aliases }),
231
237
  ...(result.tiers === undefined ? {} : { tiers: result.tiers }),
238
+ // Installed facts are the baseline; name only other origins to expose
239
+ // template inheritance and catalog overrides without repeating that baseline.
232
240
  origins: INHERITED_FIELDS
233
241
  .map(field => [field, result.origins[field]])
234
242
  .filter(([, origin]) => origin !== INSTALLED)
package/README.md CHANGED
@@ -108,7 +108,9 @@ The profile then keeps `@deepseek-ai/dsh-base` and no application, so `dsh --pro
108
108
 
109
109
  ### Use the installed Harness launcher
110
110
 
111
- Run `dsh --version` and confirm the release is inside the supported window (`>=0.2.0-rc.2 <0.3.0`) before launching this plugin. `pnpm dsh` from a Harness source checkout runs its development host, not the installed release. That host can migrate `settings.yaml` and is outside this plugin's supported range; do not use it for TUI dogfooding.
111
+ The manifest declares `>=0.2.0-rc.2 <0.3.0`, but lists only `0.2.0-rc.2` as a verified release. Range membership alone does not prove compatibility. Run `dsh --version` and use that installed release for dogfooding. `pnpm dsh` from a Harness source checkout runs a development host, not the verified installed release. It can migrate `settings.yaml`; do not use it for TUI dogfooding.
112
+
113
+ The surface probes required and optional services at startup, and selects settings APIs by capability. These checks do not validate the host version or prove full-profile behavior. The dogfood helper and PTY driver separately check the launcher against the manifest's verified releases.
112
114
 
113
115
  ## Troubleshooting
114
116
 
@@ -118,7 +120,7 @@ Two facts explain most failures.
118
120
 
119
121
  **`dsh plugin install` removes a bundle it cannot resolve, and says nothing.** The command reconciles `dsh.profile.bundles` against the installed dependencies. A bundle whose path does not resolve leaves the list, and the command still exits 0. The next launch composes `@deepseek-ai/dsh-base` alone. No application plugin mounts, so nothing reads the command line: `dsh --profile tui` then prints nothing and never exits, and `--help` waits with it.
120
122
 
121
- **npm reports `overriding peer dependency` while a harness tree resolves, and the lines are not failures.** The harness floats its own prereleases, so its dependencies hold overlapping ranges over the same packages and npm names each range it overrides; the install still exits 0. A plugin profile does not have that shape — `dsh plugin add` resolves one copy of every package this bundle mounts. The plugin's own peers are optional so that npm keeps the host's copy instead of nesting a private one.
123
+ **npm can report `overriding peer dependency` while a harness tree resolves.** A warning alone does not mean the install failed; check its exit status. This plugin pins its mounted harness dependencies to `0.2.0-rc.2` and declares optional harness peers as `*`. Optional peers avoid automatic installation when absent; neither open peers nor exact dependencies guarantee consumer deduplication. The consumer install smoke checks package-copy counts for its selected release and install paths, not every host in the declared range.
122
124
 
123
125
  | Symptom | Cause | Fix |
124
126
  |---|---|---|
@@ -127,7 +129,7 @@ Two facts explain most failures.
127
129
  | `dsh-tui: both stdin and stdout must be TTYs` | stdin or stdout is a pipe, a file, or a CI runner | run the command from a terminal |
128
130
  | Node warnings, such as `ExperimentalWarning: stripTypeScriptTypes …`, appear after exit | the TUI holds runtime warnings until it returns the terminal to your shell; startup warnings remain visible before the TUI starts | read the warnings in your shell after exit; no warning-suppression flag is needed |
129
131
  | Changes under `src/` have no effect | a linked profile loads `lib/`, not `src/` | `pnpm run build` in the plugin checkout |
130
- | TUI preferences disappear after launching a Harness source checkout | that host treats `settings.yaml` as migration input, not live preferences | use an installed release inside the supported window with a cloned home; preserve the original settings file |
132
+ | TUI preferences disappear after launching a Harness source checkout | that host treats `settings.yaml` as migration input, not live preferences | use the verified installed release with a cloned home; preserve the original settings file |
131
133
  | `--preset <id>` is refused, because the session's agent preset is fixed | a session keeps the mode that composed it, and this session already took a turn | `/preset <id>` before the first turn, or resume without `--preset` |
132
134
  | `--resume <id>` starts a new session | the id is a bare UUID | pass the stored id, `tui-session-…` included; a bare `--resume` opens the picker |
133
135
  | `dsh: profile "tui" does not exist` | the profile is not created yet | the `add` command creates it |
@@ -446,6 +448,8 @@ an action with one, so the surface can be restyled and rebound without touching
446
448
  code. On the supported line a preference lives in the active profile's own patch,
447
449
  under the TUI entry's `config`; `/theme <name>` writes a chosen theme there for
448
450
  you. Use the actual entry ID, normally `tui`, not the legacy `dsh-tui` namespace.
451
+ Merge preferences into the existing `config`; preserve its startup `!!js` fields.
452
+ The verified host replaces `config` wholesale, so a partial replacement loses the launch identity.
449
453
 
450
454
  ```yaml
451
455
  - id: tui
@@ -500,27 +504,27 @@ The plugin exports a Config schema for all preferences shown above, including
500
504
  `prefix`, `prefixWindow`, and `keys`. Launch fields such as `sessionId`,
501
505
  `model`, and `provider` remain separate from live preference edits.
502
506
  The settings service owns persistence. TUI does not create another preference store.
503
- It uses released `installSection` or `register` APIs, or Config-backed
507
+ It uses legacy section-style `installSection` or `register` APIs, or Config-backed
504
508
  `describe` and revision-checked `update` APIs. Unsupported or read-only writes
505
509
  show a notice instead of reporting success. A rejected theme selection restores
506
510
  the applied theme, and `/theme tokens` reports that same appearance.
507
511
 
508
512
  On Config-backed hosts, absent `history.enabled` and `history.ghost` stay off.
509
513
  Set each switch to `true` explicitly to enable it. This prevents recording while
510
- the host's asynchronous legacy import is pending or has failed. Released section
511
- hosts retain their existing defaults. If the host reports unreadable preferences,
514
+ the host's asynchronous legacy import is pending or has failed. Legacy section-style
515
+ settings providers retain their existing defaults. If the host reports unreadable preferences,
512
516
  history stays off. Readable `false` switches survive errors in other fields.
513
517
  Malformed updates retain the last valid appearance and do not overwrite their source.
514
518
 
515
519
  When public descriptors expose raw user layers, history checks those layers at use
516
520
  time. A readable opt-out survives rejected siblings even without a change event.
517
521
  Another rejected opt-in cannot clear this protection; a valid committed update can.
518
- A released-provider limit remains: after an absent user section, rejected scalar
522
+ A section-provider limit remains: after an absent user section, rejected scalar
519
523
  sections can produce identical public descriptors. TUI cannot detect that transition
520
- without host validity metadata, so normal released defaults remain active.
524
+ without host validity metadata, so section-provider defaults remain active.
521
525
 
522
- The inspected source host has no legacy import alias from `dsh-tui` to `tui`.
523
- Exporting Config does not resolve that namespace mismatch. The host can rename
526
+ The verified `0.2.0-rc.2` settings service has no legacy import alias from `dsh-tui` to `tui`.
527
+ Exporting Config does not resolve that namespace mismatch. The service renames
524
528
  `settings.yaml` to `settings.yaml.imported` before import completes.
525
529
  TUI does not retry or restore that file automatically. Preserve current privacy
526
530
  opt-outs and copy only the intended legacy fields into the actual TUI entry's
@@ -804,8 +808,8 @@ The mode is re-read rather than remembered: resuming mounts what that session's
804
808
  The package is a Cordis plugin bundle that stacks over `@deepseek-ai/dsh-base`:
805
809
 
806
810
  - `@sagmans/dsh-tui/startup` parses this app's own flags and publishes the launch identity.
807
- - The roster of modes holds the id a session starts in when nobody names one: `@deepseek-ai/dsh-agent-preset-registry` owns that service on the supported line, and each mode arrives as a row of `@deepseek-ai/dsh-agent-preset`, so this bundle declares the four modes itself. Both are mounted through this bundle's own `host/roster` entry point, because a patch row is applied before any service exists and the registry and the modes arrive with the harness's own agent services — after the surface that needs the roster. A mode names a selection rather than a composition: the plugins an agent runs on belong to the bundle shipping each of them, and the profile's own layers compose them, so a mode here declares no plugin row and the patch disables none. The one row a mode does own is its presentation: `ptc` mounts `@deepseek-ai/dsh-agent-tool-presentation` with `mode: ptc`, because the form an agent's tools take is declared per agent — a session's own row cannot say it, and a mode without the row presents natively whatever its id says.
808
- - `@deepseek-ai/dsh-cordis-host-runner` is the host machinery creator mode needs, and the base mounts no such row, so a terminal profile mounts it through this bundle's own `host/runner` entry point. The code runtime PTC mode runs programs against is a base row of its own (`ptc-runtime`) on the supported line, so this bundle mounts none of its own. Both packages are plain dependencies: a profile resolves exactly one copy of each, and the harness reads its runtime version off the runner it mounts.
811
+ - The roster of modes holds the id a session starts in when nobody names one: `@deepseek-ai/dsh-agent-preset-registry` owns that service on the supported line, and each mode arrives as a row of `@deepseek-ai/dsh-agent-preset`, so this bundle declares the four modes itself. Both are mounted through this bundle's own `host/roster` entry point, because a patch row is applied before any service exists and the registry and the modes arrive with the harness's own agent services — after the surface that needs the roster. A mode names a selection rather than a composition: the plugins an agent runs on belong to the bundle shipping each of them, and the profile's own layers compose them, so the other shipped modes declare no plugin row and the patch disables none. The one row a mode does own is its presentation: `ptc` mounts `@deepseek-ai/dsh-agent-tool-presentation` with `mode: ptc`, because the form an agent's tools take is declared per agent — a session's own row cannot say it, and a mode without the row presents natively whatever its id says.
812
+ - `@deepseek-ai/dsh-cordis-host-runner` is the host machinery creator mode needs, and the base mounts no such row, so a terminal profile mounts it through this bundle's own `host/runner` entry point. The code runtime PTC mode runs programs against is a base row of its own (`ptc-runtime`) on the supported line, so this bundle mounts none of its own. The registry, preset, and runner packages are plain dependencies pinned to `0.2.0-rc.2`; these pins do not guarantee one copy in every consumer tree.
809
813
  - `@sagmans/dsh-tui` owns the terminal: it creates or resumes one agent through `ctx.agents`, folds `session/event` into transcript rows and work state, renders them with `@earendil-works/pi-tui`, and releases the terminal on exit, on a boot failure, and on a signal.
810
814
  - `@sagmans/dsh-tui/todo-guard` is the one advisory row this bundle adds to the agent plane: it watches the harness's own `todos` and `plan` projections and rides the next tool result with a reminder when a plan ages. See [Todo discipline](#todo-discipline).
811
815
 
@@ -823,7 +827,7 @@ A PTC card is the one card with children: every call the `run_code` program disp
823
827
 
824
828
  A card's header names the tool, then, on a skill card, the skill it loaded in the `tool.skill` colour, 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. Hiding `tool.skill` is the same promise for a subject: the skill keeps its name in the label's colour. `/export` and a dispatched row spell the name too, so the words survive where no colour is.
825
829
 
826
- The bundle also takes the base's global agent rows out of the composition, twenty-three of them. Every one is a row the shipped modes supply per session instead, so leaving it mounted registers the same tool names in two layers and doubles each prompt section it owns. What stays mounted is the host: sessions, storage, models, permissions, jobs, and the command registry.
830
+ The bundle disables no base row. The profile's layers supply the agent tools, prompt sections, skills, and planning. The shipped modes do not duplicate those rows; PTC adds only its tool-presentation row.
827
831
 
828
832
  ### Todo discipline
829
833
 
@@ -882,18 +886,51 @@ rows = [
882
886
 
883
887
  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.
884
888
 
889
+ ## Moshi notifications
890
+
891
+ [Moshi](https://getmoshi.app/docs/notifications) can send optional notifications for the session this terminal drives.
892
+ Set `DSH_TUI_MOSHI_TOKEN` in the process environment before you start `dsh --profile tui`.
893
+ Use a Moshi API token, not the host secret used by `moshi-hook`.
894
+ The reporter is disabled when this variable is absent or empty.
895
+ It works without Herdr or the Moshi daemon.
896
+
897
+ Load the token through your secret manager. Do not put it in profile YAML, shell history, or a conversation.
898
+ Unset `DSH_TUI_MOSHI_TOKEN` and restart the surface to disable notifications.
899
+
900
+ The reporter sends these fixed messages:
901
+
902
+ - **DSH needs attention:** “Return to the terminal to continue.” An agent approval or question triggers this notification.
903
+ - **DSH finished:** “The current session is ready for input.” The driven agent and its background work must both stop.
904
+
905
+ Reader navigation does not trigger attention notifications. Duplicate status events do not produce duplicate notifications.
906
+ A finished run can include cancellation or failure; the message does not report task success.
907
+ Switching sessions discards queued notifications and aborts outstanding delivery.
908
+ Notifications already delivered cannot be recalled.
909
+
910
+ The only JSON fields sent to `https://api.getmoshi.app/api/webhook` are `token`, `title`, and `message`.
911
+ The message contains no transcript, prompt, tool arguments, approval text, working directory, or session/pane identifiers.
912
+ The token selects its owning Moshi device; the reporter does not request multi-device delivery.
913
+ Requests abort after three seconds. Network and HTTP failures remain silent, with no retries.
914
+ Notification delivery never blocks agent work or terminal teardown.
915
+
916
+ This integration does not provide native Chat View, Live Activity, remote approval controls, or automatic pane navigation.
917
+ Use the existing Moshi SSH connection to return to the terminal.
918
+
885
919
  ## Development
886
920
 
887
921
  ```sh
888
- pnpm install
889
- pnpm run typecheck
890
- pnpm test
891
- pnpm run build
922
+ pnpm install --frozen-lockfile
923
+ pnpm verify
892
924
  ```
893
925
 
894
926
  **A linked profile loads the built entry point**, so edits under `src/` are invisible to `dsh --profile tui` until `pnpm run build` runs. The PTY driver rebuilds, checks nested links in the isolated `--home`, and rejects a launcher whose version `dsh.compatibility.dshReleases` does not list.
895
927
 
896
- Clone your configured home with the dogfood helper for realistic runs. A minimal throwaway home can also expose startup failures without touching your real state:
928
+ `pnpm verify` preserves golden snapshots and automatically drives free real-profile
929
+ scenarios without credentials. [FEATURES.md](FEATURES.md) owns feature inventory
930
+ and evidence rules. Unit suites are not maintained.
931
+
932
+ Paid model use runs only on explicit demand. For those checks, clone your
933
+ configured home with the dogfood helper. These commands include paid model calls:
897
934
 
898
935
  ```sh
899
936
  S=$(mktemp -d)
@@ -905,10 +942,11 @@ node tools/pty-drive.mjs --home "$S" --seconds 20 --prompt ''
905
942
  node tools/pty-drive.mjs --home "$S" --prompt 'Run: echo hi' --click 20:12
906
943
  ```
907
944
 
908
- A minimal home starts on the shipped defaults: `settings.yaml` is legacy on the
909
- supported line, where the launcher renames it before import, so a preference
910
- copied there is read by nothing. Use the dogfood clone above when a run needs
911
- your own preferences.
945
+ A minimal home starts on the shipped defaults. On verified `0.2.0-rc.2`, the
946
+ settings service renames legacy `settings.yaml` before attempting a one-time
947
+ import into matching profile entries. Rejected sections remain only in
948
+ `settings.yaml.imported`. Use the active profile patch for current preferences,
949
+ or the dogfood clone above when a run needs your own composition.
912
950
 
913
951
  Test specs import plugin sources through the `@/` alias. Under this test runner the spec file is resolved with a root-relative id, so parent-relative imports (`../src/...`) do not resolve; the alias and its matching `tsconfig.test.json` path mapping avoid that.
914
952
 
@@ -1026,7 +1064,7 @@ discipline as this one.
1026
1064
 
1027
1065
  | Plugin | What it adds |
1028
1066
  |---|---|
1029
- | [`@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. |
1067
+ | [`@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 — a row this bundle does not disable — so the profile still keeps exactly one compaction service, and this surface needs no setting for it. |
1030
1068
  | [`@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. |
1031
1069
 
1032
1070
  ```sh
package/cordis.patch.yml CHANGED
@@ -29,6 +29,8 @@
29
29
  - id: tui-keymaps
30
30
  name: '@sagmans/dsh-tui/keymaps'
31
31
 
32
+ # Parse launcher intent once; injection keeps the surface behind committed startup state
33
+ # and prevents --help or usage errors from mounting the interactive screen.
32
34
  - id: tui-startup
33
35
  name: '@sagmans/dsh-tui/startup'
34
36
 
@@ -3,12 +3,14 @@ export interface ForkEvent {
3
3
  readonly type: string;
4
4
  readonly data?: unknown;
5
5
  readonly seq?: number;
6
+ /** Re-folding a log must preserve the clock of its recorded work. */
7
+ readonly time?: number;
6
8
  }
7
9
  /** Where a fork may branch, and how much of the log the child inherits. */
8
10
  export interface ForkPoint {
9
11
  /** Events the child inherits, counted from the start of the log. */
10
12
  readonly inheritedEvents: number;
11
- /** Seq of the turn/end the cut is anchored to. */
13
+ /** Boundary label for the fork notice, not the inherited-prefix offset. */
12
14
  readonly boundarySeq: number;
13
15
  }
14
16
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"fork.d.ts","sourceRoot":"","sources":["../../src/agent/fork.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,kDAAkD;IAClD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,SAAS,CAY7E"}
1
+ {"version":3,"file":"fork.d.ts","sourceRoot":"","sources":["../../src/agent/fork.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,SAAS,CAc7E"}
package/lib/agent/fork.js CHANGED
@@ -20,6 +20,8 @@ export function forkPoint(events) {
20
20
  let cut = boundary + 1;
21
21
  while (cut < events.length && events[cut]?.type !== 'turn/start')
22
22
  cut += 1;
23
+ // The notice still needs a boundary label when seq is absent; only the array
24
+ // cut determines inheritance, so this index does not stand in for a durable seq.
23
25
  return { inheritedEvents: cut, boundarySeq: events[boundary]?.seq ?? boundary };
24
26
  }
25
27
  //# sourceMappingURL=fork.js.map