@dsh-cc/tui 0.5.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 (363) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +144 -0
  3. package/lib/bash-history.d.ts +31 -0
  4. package/lib/bash-history.d.ts.map +1 -0
  5. package/lib/bash-history.js +94 -0
  6. package/lib/bash-history.js.map +1 -0
  7. package/lib/compact-fold.d.ts +35 -0
  8. package/lib/compact-fold.d.ts.map +1 -0
  9. package/lib/compact-fold.js +60 -0
  10. package/lib/compact-fold.js.map +1 -0
  11. package/lib/components/arg-completers.d.ts +22 -0
  12. package/lib/components/arg-completers.d.ts.map +1 -0
  13. package/lib/components/arg-completers.js +75 -0
  14. package/lib/components/arg-completers.js.map +1 -0
  15. package/lib/components/code-theme.d.ts +25 -0
  16. package/lib/components/code-theme.d.ts.map +1 -0
  17. package/lib/components/code-theme.js +137 -0
  18. package/lib/components/code-theme.js.map +1 -0
  19. package/lib/components/completion.d.ts +50 -0
  20. package/lib/components/completion.d.ts.map +1 -0
  21. package/lib/components/completion.js +279 -0
  22. package/lib/components/completion.js.map +1 -0
  23. package/lib/components/diff-card.d.ts +29 -0
  24. package/lib/components/diff-card.d.ts.map +1 -0
  25. package/lib/components/diff-card.js +175 -0
  26. package/lib/components/diff-card.js.map +1 -0
  27. package/lib/components/diff-hunks.d.ts +44 -0
  28. package/lib/components/diff-hunks.d.ts.map +1 -0
  29. package/lib/components/diff-hunks.js +188 -0
  30. package/lib/components/diff-hunks.js.map +1 -0
  31. package/lib/components/editor-history.d.ts +23 -0
  32. package/lib/components/editor-history.d.ts.map +1 -0
  33. package/lib/components/editor-history.js +29 -0
  34. package/lib/components/editor-history.js.map +1 -0
  35. package/lib/components/markdown-theme.d.ts +11 -0
  36. package/lib/components/markdown-theme.d.ts.map +1 -0
  37. package/lib/components/markdown-theme.js +29 -0
  38. package/lib/components/markdown-theme.js.map +1 -0
  39. package/lib/components/masked-input.d.ts +24 -0
  40. package/lib/components/masked-input.d.ts.map +1 -0
  41. package/lib/components/masked-input.js +168 -0
  42. package/lib/components/masked-input.js.map +1 -0
  43. package/lib/components/overlay-host.d.ts +31 -0
  44. package/lib/components/overlay-host.d.ts.map +1 -0
  45. package/lib/components/overlay-host.js +128 -0
  46. package/lib/components/overlay-host.js.map +1 -0
  47. package/lib/components/overlays.d.ts +94 -0
  48. package/lib/components/overlays.d.ts.map +1 -0
  49. package/lib/components/overlays.js +450 -0
  50. package/lib/components/overlays.js.map +1 -0
  51. package/lib/components/provider-box.d.ts +23 -0
  52. package/lib/components/provider-box.d.ts.map +1 -0
  53. package/lib/components/provider-box.js +164 -0
  54. package/lib/components/provider-box.js.map +1 -0
  55. package/lib/components/read-group.d.ts +51 -0
  56. package/lib/components/read-group.d.ts.map +1 -0
  57. package/lib/components/read-group.js +105 -0
  58. package/lib/components/read-group.js.map +1 -0
  59. package/lib/components/root-bash.d.ts +36 -0
  60. package/lib/components/root-bash.d.ts.map +1 -0
  61. package/lib/components/root-bash.js +112 -0
  62. package/lib/components/root-bash.js.map +1 -0
  63. package/lib/components/root-types.d.ts +42 -0
  64. package/lib/components/root-types.d.ts.map +1 -0
  65. package/lib/components/root-types.js +8 -0
  66. package/lib/components/root-types.js.map +1 -0
  67. package/lib/components/root-utils.d.ts +22 -0
  68. package/lib/components/root-utils.d.ts.map +1 -0
  69. package/lib/components/root-utils.js +45 -0
  70. package/lib/components/root-utils.js.map +1 -0
  71. package/lib/components/root.d.ts +25 -0
  72. package/lib/components/root.d.ts.map +1 -0
  73. package/lib/components/root.js +357 -0
  74. package/lib/components/root.js.map +1 -0
  75. package/lib/components/theme.d.ts +61 -0
  76. package/lib/components/theme.d.ts.map +1 -0
  77. package/lib/components/theme.js +99 -0
  78. package/lib/components/theme.js.map +1 -0
  79. package/lib/components/transcript.d.ts +43 -0
  80. package/lib/components/transcript.d.ts.map +1 -0
  81. package/lib/components/transcript.js +203 -0
  82. package/lib/components/transcript.js.map +1 -0
  83. package/lib/components/working-line.d.ts +35 -0
  84. package/lib/components/working-line.d.ts.map +1 -0
  85. package/lib/components/working-line.js +66 -0
  86. package/lib/components/working-line.js.map +1 -0
  87. package/lib/effort-catalog.d.ts +27 -0
  88. package/lib/effort-catalog.d.ts.map +1 -0
  89. package/lib/effort-catalog.js +36 -0
  90. package/lib/effort-catalog.js.map +1 -0
  91. package/lib/export-markdown.d.ts +18 -0
  92. package/lib/export-markdown.d.ts.map +1 -0
  93. package/lib/export-markdown.js +124 -0
  94. package/lib/export-markdown.js.map +1 -0
  95. package/lib/harness/approval-preview.d.ts +33 -0
  96. package/lib/harness/approval-preview.d.ts.map +1 -0
  97. package/lib/harness/approval-preview.js +179 -0
  98. package/lib/harness/approval-preview.js.map +1 -0
  99. package/lib/harness/boot-banner.d.ts +14 -0
  100. package/lib/harness/boot-banner.d.ts.map +1 -0
  101. package/lib/harness/boot-banner.js +89 -0
  102. package/lib/harness/boot-banner.js.map +1 -0
  103. package/lib/harness/driver-agent.d.ts +78 -0
  104. package/lib/harness/driver-agent.d.ts.map +1 -0
  105. package/lib/harness/driver-agent.js +314 -0
  106. package/lib/harness/driver-agent.js.map +1 -0
  107. package/lib/harness/driver-agents.d.ts +20 -0
  108. package/lib/harness/driver-agents.d.ts.map +1 -0
  109. package/lib/harness/driver-agents.js +123 -0
  110. package/lib/harness/driver-agents.js.map +1 -0
  111. package/lib/harness/driver-approvals.d.ts +38 -0
  112. package/lib/harness/driver-approvals.d.ts.map +1 -0
  113. package/lib/harness/driver-approvals.js +277 -0
  114. package/lib/harness/driver-approvals.js.map +1 -0
  115. package/lib/harness/driver-bash.d.ts +15 -0
  116. package/lib/harness/driver-bash.d.ts.map +1 -0
  117. package/lib/harness/driver-bash.js +73 -0
  118. package/lib/harness/driver-bash.js.map +1 -0
  119. package/lib/harness/driver-catalog.d.ts +84 -0
  120. package/lib/harness/driver-catalog.d.ts.map +1 -0
  121. package/lib/harness/driver-catalog.js +256 -0
  122. package/lib/harness/driver-catalog.js.map +1 -0
  123. package/lib/harness/driver-ctx.d.ts +462 -0
  124. package/lib/harness/driver-ctx.d.ts.map +1 -0
  125. package/lib/harness/driver-ctx.js +11 -0
  126. package/lib/harness/driver-ctx.js.map +1 -0
  127. package/lib/harness/driver-hud.d.ts +31 -0
  128. package/lib/harness/driver-hud.d.ts.map +1 -0
  129. package/lib/harness/driver-hud.js +204 -0
  130. package/lib/harness/driver-hud.js.map +1 -0
  131. package/lib/harness/driver-live.d.ts +36 -0
  132. package/lib/harness/driver-live.d.ts.map +1 -0
  133. package/lib/harness/driver-live.js +44 -0
  134. package/lib/harness/driver-live.js.map +1 -0
  135. package/lib/harness/driver-modal.d.ts +52 -0
  136. package/lib/harness/driver-modal.d.ts.map +1 -0
  137. package/lib/harness/driver-modal.js +78 -0
  138. package/lib/harness/driver-modal.js.map +1 -0
  139. package/lib/harness/driver-mode.d.ts +35 -0
  140. package/lib/harness/driver-mode.d.ts.map +1 -0
  141. package/lib/harness/driver-mode.js +84 -0
  142. package/lib/harness/driver-mode.js.map +1 -0
  143. package/lib/harness/driver-pickers.d.ts +48 -0
  144. package/lib/harness/driver-pickers.d.ts.map +1 -0
  145. package/lib/harness/driver-pickers.js +249 -0
  146. package/lib/harness/driver-pickers.js.map +1 -0
  147. package/lib/harness/driver-promote.d.ts +29 -0
  148. package/lib/harness/driver-promote.d.ts.map +1 -0
  149. package/lib/harness/driver-promote.js +36 -0
  150. package/lib/harness/driver-promote.js.map +1 -0
  151. package/lib/harness/driver-queue.d.ts +19 -0
  152. package/lib/harness/driver-queue.d.ts.map +1 -0
  153. package/lib/harness/driver-queue.js +281 -0
  154. package/lib/harness/driver-queue.js.map +1 -0
  155. package/lib/harness/driver-run-local.d.ts +32 -0
  156. package/lib/harness/driver-run-local.d.ts.map +1 -0
  157. package/lib/harness/driver-run-local.js +366 -0
  158. package/lib/harness/driver-run-local.js.map +1 -0
  159. package/lib/harness/driver-sessions.d.ts +28 -0
  160. package/lib/harness/driver-sessions.d.ts.map +1 -0
  161. package/lib/harness/driver-sessions.js +386 -0
  162. package/lib/harness/driver-sessions.js.map +1 -0
  163. package/lib/harness/driver.d.ts +22 -0
  164. package/lib/harness/driver.d.ts.map +1 -0
  165. package/lib/harness/driver.js +459 -0
  166. package/lib/harness/driver.js.map +1 -0
  167. package/lib/harness/preset.d.ts +32 -0
  168. package/lib/harness/preset.d.ts.map +1 -0
  169. package/lib/harness/preset.js +34 -0
  170. package/lib/harness/preset.js.map +1 -0
  171. package/lib/harness/session-list.d.ts +65 -0
  172. package/lib/harness/session-list.d.ts.map +1 -0
  173. package/lib/harness/session-list.js +91 -0
  174. package/lib/harness/session-list.js.map +1 -0
  175. package/lib/harness/shell-output.d.ts +44 -0
  176. package/lib/harness/shell-output.d.ts.map +1 -0
  177. package/lib/harness/shell-output.js +90 -0
  178. package/lib/harness/shell-output.js.map +1 -0
  179. package/lib/harness/statusline-cc-transcript.d.ts +51 -0
  180. package/lib/harness/statusline-cc-transcript.d.ts.map +1 -0
  181. package/lib/harness/statusline-cc-transcript.js +191 -0
  182. package/lib/harness/statusline-cc-transcript.js.map +1 -0
  183. package/lib/harness/statusline-command.d.ts +54 -0
  184. package/lib/harness/statusline-command.d.ts.map +1 -0
  185. package/lib/harness/statusline-command.js +161 -0
  186. package/lib/harness/statusline-command.js.map +1 -0
  187. package/lib/harness/statusline-payload.d.ts +79 -0
  188. package/lib/harness/statusline-payload.d.ts.map +1 -0
  189. package/lib/harness/statusline-payload.js +93 -0
  190. package/lib/harness/statusline-payload.js.map +1 -0
  191. package/lib/harness/statusline-settings.d.ts +47 -0
  192. package/lib/harness/statusline-settings.d.ts.map +1 -0
  193. package/lib/harness/statusline-settings.js +57 -0
  194. package/lib/harness/statusline-settings.js.map +1 -0
  195. package/lib/harness/statusline-wiring.d.ts +45 -0
  196. package/lib/harness/statusline-wiring.d.ts.map +1 -0
  197. package/lib/harness/statusline-wiring.js +247 -0
  198. package/lib/harness/statusline-wiring.js.map +1 -0
  199. package/lib/harness/usage-view.d.ts +84 -0
  200. package/lib/harness/usage-view.d.ts.map +1 -0
  201. package/lib/harness/usage-view.js +199 -0
  202. package/lib/harness/usage-view.js.map +1 -0
  203. package/lib/harness/worktree-exit.d.ts +105 -0
  204. package/lib/harness/worktree-exit.d.ts.map +1 -0
  205. package/lib/harness/worktree-exit.js +168 -0
  206. package/lib/harness/worktree-exit.js.map +1 -0
  207. package/lib/history.d.ts +50 -0
  208. package/lib/history.d.ts.map +1 -0
  209. package/lib/history.js +139 -0
  210. package/lib/history.js.map +1 -0
  211. package/lib/index.d.ts +63 -0
  212. package/lib/index.d.ts.map +1 -0
  213. package/lib/index.js +54 -0
  214. package/lib/index.js.map +1 -0
  215. package/lib/input.d.ts +158 -0
  216. package/lib/input.d.ts.map +1 -0
  217. package/lib/input.js +400 -0
  218. package/lib/input.js.map +1 -0
  219. package/lib/invariant.d.ts +14 -0
  220. package/lib/invariant.d.ts.map +1 -0
  221. package/lib/invariant.js +20 -0
  222. package/lib/invariant.js.map +1 -0
  223. package/lib/mode-cycle.d.ts +22 -0
  224. package/lib/mode-cycle.d.ts.map +1 -0
  225. package/lib/mode-cycle.js +32 -0
  226. package/lib/mode-cycle.js.map +1 -0
  227. package/lib/model-catalog.d.ts +22 -0
  228. package/lib/model-catalog.d.ts.map +1 -0
  229. package/lib/model-catalog.js +45 -0
  230. package/lib/model-catalog.js.map +1 -0
  231. package/lib/packaged-preset.d.ts +32 -0
  232. package/lib/packaged-preset.d.ts.map +1 -0
  233. package/lib/packaged-preset.js +94 -0
  234. package/lib/packaged-preset.js.map +1 -0
  235. package/lib/plugin.d.ts +11 -0
  236. package/lib/plugin.d.ts.map +1 -0
  237. package/lib/plugin.js +88 -0
  238. package/lib/plugin.js.map +1 -0
  239. package/lib/profile.d.ts +4 -0
  240. package/lib/profile.d.ts.map +1 -0
  241. package/lib/profile.js +7 -0
  242. package/lib/profile.js.map +1 -0
  243. package/lib/project-sessions.d.ts +29 -0
  244. package/lib/project-sessions.d.ts.map +1 -0
  245. package/lib/project-sessions.js +60 -0
  246. package/lib/project-sessions.js.map +1 -0
  247. package/lib/project.d.ts +75 -0
  248. package/lib/project.d.ts.map +1 -0
  249. package/lib/project.js +196 -0
  250. package/lib/project.js.map +1 -0
  251. package/lib/provider-actions.d.ts +37 -0
  252. package/lib/provider-actions.d.ts.map +1 -0
  253. package/lib/provider-actions.js +417 -0
  254. package/lib/provider-actions.js.map +1 -0
  255. package/lib/provider-command.d.ts +109 -0
  256. package/lib/provider-command.d.ts.map +1 -0
  257. package/lib/provider-command.js +220 -0
  258. package/lib/provider-command.js.map +1 -0
  259. package/lib/provider-detail.d.ts +15 -0
  260. package/lib/provider-detail.d.ts.map +1 -0
  261. package/lib/provider-detail.js +201 -0
  262. package/lib/provider-detail.js.map +1 -0
  263. package/lib/provider-flow.d.ts +191 -0
  264. package/lib/provider-flow.d.ts.map +1 -0
  265. package/lib/provider-flow.js +192 -0
  266. package/lib/provider-flow.js.map +1 -0
  267. package/lib/provider-presets.d.ts +32 -0
  268. package/lib/provider-presets.d.ts.map +1 -0
  269. package/lib/provider-presets.js +105 -0
  270. package/lib/provider-presets.js.map +1 -0
  271. package/lib/provider-read.d.ts +63 -0
  272. package/lib/provider-read.d.ts.map +1 -0
  273. package/lib/provider-read.js +115 -0
  274. package/lib/provider-read.js.map +1 -0
  275. package/lib/provider-settings.d.ts +30 -0
  276. package/lib/provider-settings.d.ts.map +1 -0
  277. package/lib/provider-settings.js +65 -0
  278. package/lib/provider-settings.js.map +1 -0
  279. package/lib/resume-target.d.ts +59 -0
  280. package/lib/resume-target.d.ts.map +1 -0
  281. package/lib/resume-target.js +143 -0
  282. package/lib/resume-target.js.map +1 -0
  283. package/lib/slash.d.ts +44 -0
  284. package/lib/slash.d.ts.map +1 -0
  285. package/lib/slash.js +81 -0
  286. package/lib/slash.js.map +1 -0
  287. package/lib/state/driver-types.d.ts +505 -0
  288. package/lib/state/driver-types.d.ts.map +1 -0
  289. package/lib/state/driver-types.js +8 -0
  290. package/lib/state/driver-types.js.map +1 -0
  291. package/lib/state/driver-usage-types.d.ts +59 -0
  292. package/lib/state/driver-usage-types.d.ts.map +1 -0
  293. package/lib/state/driver-usage-types.js +8 -0
  294. package/lib/state/driver-usage-types.js.map +1 -0
  295. package/lib/statusline.d.ts +63 -0
  296. package/lib/statusline.d.ts.map +1 -0
  297. package/lib/statusline.js +97 -0
  298. package/lib/statusline.js.map +1 -0
  299. package/lib/store/pickers.d.ts +34 -0
  300. package/lib/store/pickers.d.ts.map +1 -0
  301. package/lib/store/pickers.js +111 -0
  302. package/lib/store/pickers.js.map +1 -0
  303. package/lib/store/provider-panel.d.ts +107 -0
  304. package/lib/store/provider-panel.d.ts.map +1 -0
  305. package/lib/store/provider-panel.js +151 -0
  306. package/lib/store/provider-panel.js.map +1 -0
  307. package/lib/store/question.d.ts +21 -0
  308. package/lib/store/question.d.ts.map +1 -0
  309. package/lib/store/question.js +59 -0
  310. package/lib/store/question.js.map +1 -0
  311. package/lib/store/queue.d.ts +27 -0
  312. package/lib/store/queue.d.ts.map +1 -0
  313. package/lib/store/queue.js +34 -0
  314. package/lib/store/queue.js.map +1 -0
  315. package/lib/store/session.d.ts +73 -0
  316. package/lib/store/session.d.ts.map +1 -0
  317. package/lib/store/session.js +172 -0
  318. package/lib/store/session.js.map +1 -0
  319. package/lib/store/subagents.d.ts +16 -0
  320. package/lib/store/subagents.d.ts.map +1 -0
  321. package/lib/store/subagents.js +44 -0
  322. package/lib/store/subagents.js.map +1 -0
  323. package/lib/store/todos.d.ts +35 -0
  324. package/lib/store/todos.d.ts.map +1 -0
  325. package/lib/store/todos.js +68 -0
  326. package/lib/store/todos.js.map +1 -0
  327. package/lib/store/usage.d.ts +15 -0
  328. package/lib/store/usage.d.ts.map +1 -0
  329. package/lib/store/usage.js +27 -0
  330. package/lib/store/usage.js.map +1 -0
  331. package/lib/store/views.d.ts +419 -0
  332. package/lib/store/views.d.ts.map +1 -0
  333. package/lib/store/views.js +3 -0
  334. package/lib/store/views.js.map +1 -0
  335. package/lib/store.d.ts +19 -0
  336. package/lib/store.d.ts.map +1 -0
  337. package/lib/store.js +10 -0
  338. package/lib/store.js.map +1 -0
  339. package/lib/terminal/lease.d.ts +33 -0
  340. package/lib/terminal/lease.d.ts.map +1 -0
  341. package/lib/terminal/lease.js +99 -0
  342. package/lib/terminal/lease.js.map +1 -0
  343. package/lib/tool-card.d.ts +75 -0
  344. package/lib/tool-card.d.ts.map +1 -0
  345. package/lib/tool-card.js +109 -0
  346. package/lib/tool-card.js.map +1 -0
  347. package/lib/tool-verbs.d.ts +12 -0
  348. package/lib/tool-verbs.d.ts.map +1 -0
  349. package/lib/tool-verbs.js +29 -0
  350. package/lib/tool-verbs.js.map +1 -0
  351. package/lib/transcript.d.ts +40 -0
  352. package/lib/transcript.d.ts.map +1 -0
  353. package/lib/transcript.js +413 -0
  354. package/lib/transcript.js.map +1 -0
  355. package/lib/working-line.d.ts +44 -0
  356. package/lib/working-line.d.ts.map +1 -0
  357. package/lib/working-line.js +56 -0
  358. package/lib/working-line.js.map +1 -0
  359. package/package.json +72 -0
  360. package/presets/cc/.dsh-cc-managed.json +5 -0
  361. package/presets/cc/agent.cordis.yml +524 -0
  362. package/presets/cc/preset.yml +3 -0
  363. package/scripts/stage-preset.mjs +26 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Approval + user-question pipeline extracted from harness/driver.ts.
3
+ *
4
+ * Free-function collaborator: `createApprovalsSection` owns the modal FIFO
5
+ * (approvals and questions share one queue via createModalQueue) and takes a
6
+ * {@link DriverApprovalsCtx} instead of closing over createDriver's locals.
7
+ * Emits re-read the current view-model via `rt.state()` after every emit
8
+ * (createDriver rebinds `state` on emit). The section routes approvals from the
9
+ * host's `approval/request` hook, persists "always allow" rules through the
10
+ * settings provider, and answers questions through the host's userQuestions
11
+ * provider.
12
+ * @module @dsh-cc/tui/harness/driver-approvals
13
+ */
14
+ import { backspaceQuestionText, moveQuestionFocus, toggleQuestionOption, typeQuestionText, } from "../store.js";
15
+ import { PERMISSION_SETTINGS_NAMESPACE } from '@dsh-cc/permission-rules';
16
+ import { UserQuestionError, } from '@deepseek-ai/dsh-user-questions';
17
+ import { allowRuleOf, isSettingsConflict, payloadOf } from "./approval-preview.js";
18
+ import { createModalQueue } from "./driver-modal.js";
19
+ /**
20
+ * Build the approval/question pipeline. `answerApproval` threads the allow-rule
21
+ * write through {@link ModalAnswerDeps}; the modal FIFO lives here so approvals
22
+ * and user questions share a single queue. `current`/`state` are read live via
23
+ * the ctx — never captured snapshots.
24
+ */
25
+ export function createApprovalsSection(rt) {
26
+ const modal = createModalQueue({ emit: rt.emit, state: rt.state });
27
+ // --- Approvals ------------------------------------------------------------
28
+ // The head approval is parked in state.approval together with the
29
+ // recoverable payload preview. The "always" answer resolves the current call
30
+ // like a one-shot grant AND persists a derived permission rule through the
31
+ // settings provider (see writeAllowRule). Already-queued requests are decided
32
+ // one by one even after a rule lands — grants never apply retroactively.
33
+ // Requests from the current agent and from tracked subagents (their session
34
+ // id was seen on `subagent/start`, which fires before a subagent's first
35
+ // approval) queue here; anything else passes through to the next provider.
36
+ rt.ctx.on('approval/request', async (req, next) => {
37
+ const ownSessions = new Set(rt.state().subagents.map(run => run.sessionId));
38
+ ownSessions.add(String(rt.current.agent.session.id));
39
+ if (!ownSessions.has(String(req.agent.session.id)))
40
+ return next();
41
+ const preview = payloadOf(req);
42
+ const view = {
43
+ toolName: req.toolName,
44
+ ...req.reason === undefined ? {} : { reason: req.reason },
45
+ ...preview.kind === 'none' ? {} : { preview },
46
+ };
47
+ return await new Promise(resolve => {
48
+ const entry = {
49
+ kind: 'approval',
50
+ view,
51
+ resolve,
52
+ agent: req.agent,
53
+ ...req.signal === undefined ? {} : { signal: req.signal },
54
+ };
55
+ modal.push(entry);
56
+ req.signal?.addEventListener('abort', () => {
57
+ modal.dequeue(entry);
58
+ resolve('cancelled');
59
+ }, { once: true });
60
+ modal.publishHead();
61
+ });
62
+ });
63
+ /**
64
+ * Persist the allow rule an "always" answer grants: read the `permissions`
65
+ * namespace descriptor, merge the rule into the raw user section's allow
66
+ * list (re-attaching every passthrough field — `replace` overwrites the
67
+ * whole section), and write it back at the observed revision. One retry on
68
+ * a revision conflict (re-describe, re-merge, replace). Degradations
69
+ * (provider missing, namespace unregistered, write failure) leave the call
70
+ * allowed once and say so in a notice — never a crash after the fact.
71
+ */
72
+ async function writeAllowRule(toolName, preview) {
73
+ const rule = allowRuleOf(toolName, preview);
74
+ if (rule === undefined)
75
+ return;
76
+ const settings = rt.ctx.get('settings');
77
+ if (settings === undefined || settings.writable === false || typeof settings.describe !== 'function') {
78
+ rt.showNotice('Allowed once only — no writable settings provider is mounted.');
79
+ return;
80
+ }
81
+ for (let attempt = 0; attempt < 2; attempt += 1) {
82
+ const descriptor = settings.describe().find(entry => String(entry.ns) === String(PERMISSION_SETTINGS_NAMESPACE));
83
+ if (descriptor === undefined) {
84
+ rt.showNotice('Allowed once only — the "permissions" settings namespace is not mounted.');
85
+ return;
86
+ }
87
+ const user = descriptor.user !== null && typeof descriptor.user === 'object'
88
+ ? descriptor.user
89
+ : {};
90
+ const current = Array.isArray(user.allow) ? [...user.allow] : [];
91
+ const allow = current.includes(rule) ? current : [...current, rule];
92
+ try {
93
+ await settings.replace(PERMISSION_SETTINGS_NAMESPACE, { ...user, allow }, descriptor.revision);
94
+ rt.showNotice(`Always allow: ${rule}`);
95
+ return;
96
+ }
97
+ catch (error) {
98
+ if (attempt === 0 && isSettingsConflict(error))
99
+ continue;
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ rt.showNotice(`Allowed once only — saving the allow rule failed: ${message}`);
102
+ return;
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * Grant the derived rule to the requesting session's scoped allowlist
108
+ * (WS4-PR-B): the same derivation the "always" answer persists, but recorded
109
+ * on the permission engine's in-memory session allowlist with an audit
110
+ * event — never into the global `permissions` settings. Degradations (rule
111
+ * underivable, permission engine absent) leave the call allowed once and
112
+ * say so in a notice.
113
+ */
114
+ function addSessionRule(agent, toolName, preview) {
115
+ const rule = allowRuleOf(toolName, preview);
116
+ if (rule === undefined)
117
+ return;
118
+ const engine = rt.ctx.get('permissionRules');
119
+ if (agent === undefined || engine === undefined) {
120
+ rt.showNotice('Allowed once only — the permission engine is not mounted.');
121
+ return;
122
+ }
123
+ engine.addSessionAllow(agent, rule);
124
+ rt.showNotice(`Allowed for this session: ${rule}`);
125
+ }
126
+ // --- User questions -------------------------------------------------------
127
+ // A question from the host (agent ask for user input) renders as a modal
128
+ // entry behind any active approval; when the pipeline is empty it becomes
129
+ // the head and renders immediately.
130
+ const userQuestions = rt.ctx.get('userQuestions');
131
+ let questionsDispose;
132
+ if (userQuestions !== undefined) {
133
+ try {
134
+ questionsDispose = userQuestions.registerProvider({
135
+ ask: async (request) => {
136
+ const first = request.questions[0];
137
+ const view = {
138
+ header: first?.header ?? 'Question',
139
+ question: first?.question ?? '',
140
+ ...first?.detail === undefined ? {} : { detail: first.detail },
141
+ options: (first?.options ?? []).map(option => ({
142
+ label: option.label,
143
+ ...option.description === undefined ? {} : { description: option.description },
144
+ })),
145
+ multiSelect: first?.multiSelect === true,
146
+ ...first?.intent === undefined ? {} : { intent: first.intent },
147
+ focused: 0,
148
+ selected: [],
149
+ custom: '',
150
+ };
151
+ // Queue behind any active modal; when the pipeline is empty this
152
+ // entry becomes the head and renders immediately.
153
+ return await new Promise((resolve, reject) => {
154
+ const entry = {
155
+ kind: 'question',
156
+ id: first?.id ?? '',
157
+ view,
158
+ resolve: (answer) => resolve({
159
+ answers: answer.answers.map((item, index) => ({
160
+ id: request.questions[index]?.id ?? item.id,
161
+ selected: item.selected,
162
+ ...item.custom === undefined ? {} : { custom: item.custom },
163
+ })),
164
+ }),
165
+ reject,
166
+ ...request.signal === undefined ? {} : { signal: request.signal },
167
+ };
168
+ modal.push(entry);
169
+ request.signal?.addEventListener('abort', () => {
170
+ modal.dequeue(entry);
171
+ reject(new UserQuestionError('question cancelled', 'CANCELLED'));
172
+ }, { once: true });
173
+ modal.publishHead();
174
+ });
175
+ },
176
+ });
177
+ }
178
+ catch (error) {
179
+ if (error.code !== 'DUPLICATE_PROVIDER')
180
+ throw error;
181
+ }
182
+ }
183
+ /**
184
+ * Resolve the head question and advance the modal queue. Labels are echoed
185
+ * verbatim — the plan-review `intent.approve` contract requires the exact
186
+ * label string, never an inferred or re-indexed one.
187
+ */
188
+ function resolveQuestion(selected, custom) {
189
+ const head = modal.peekHead();
190
+ if (head === undefined || head.kind !== 'question')
191
+ return;
192
+ modal.shiftHead();
193
+ modal.publishHead();
194
+ head.resolve({
195
+ answers: [{
196
+ id: head.id,
197
+ selected: [...selected],
198
+ ...custom === undefined ? {} : { custom },
199
+ }],
200
+ });
201
+ }
202
+ return {
203
+ answerApproval(kind) {
204
+ modal.answerApproval(kind, { writeAllowRule, addSessionRule, showNotice: rt.showNotice });
205
+ },
206
+ questionMove(delta) {
207
+ rt.emit(moveQuestionFocus(rt.state(), delta));
208
+ },
209
+ questionToggle() {
210
+ const question = rt.state().question;
211
+ if (question === undefined)
212
+ return;
213
+ if (question.focused >= question.options.length) {
214
+ rt.emit(typeQuestionText(rt.state(), ' '));
215
+ return;
216
+ }
217
+ if (question.multiSelect) {
218
+ rt.emit(toggleQuestionOption(rt.state(), question.focused));
219
+ return;
220
+ }
221
+ resolveQuestion([question.options[question.focused].label]);
222
+ },
223
+ questionPick(index) {
224
+ const question = rt.state().question;
225
+ if (question === undefined)
226
+ return;
227
+ const option = question.options[index];
228
+ if (option === undefined)
229
+ return;
230
+ if (question.multiSelect) {
231
+ rt.emit(toggleQuestionOption(rt.state(), index));
232
+ return;
233
+ }
234
+ resolveQuestion([option.label]);
235
+ },
236
+ questionType(text) {
237
+ rt.emit(typeQuestionText(rt.state(), text));
238
+ },
239
+ questionBackspace() {
240
+ rt.emit(backspaceQuestionText(rt.state()));
241
+ },
242
+ questionSubmit() {
243
+ const question = rt.state().question;
244
+ if (question === undefined)
245
+ return;
246
+ const custom = question.custom.trim();
247
+ let selected;
248
+ if (question.selected.length > 0) {
249
+ selected = [...question.selected];
250
+ }
251
+ else if (custom.length > 0) {
252
+ selected = [];
253
+ }
254
+ else {
255
+ // Nothing chosen and no free text: enter resolves the focused option
256
+ // (the first option when the "Other" row holds focus) so the question
257
+ // always gets an answer.
258
+ const fallback = question.focused < question.options.length
259
+ ? question.options[question.focused].label
260
+ : question.options[0]?.label;
261
+ selected = fallback === undefined ? [] : [fallback];
262
+ }
263
+ resolveQuestion(selected, custom.length > 0 ? custom : undefined);
264
+ },
265
+ questionCancel() {
266
+ const question = rt.state().question;
267
+ resolveQuestion(question !== undefined && question.options.length > 0 ? [question.options[0].label] : []);
268
+ },
269
+ spliceAll() {
270
+ return modal.spliceAll();
271
+ },
272
+ dispose() {
273
+ questionsDispose?.();
274
+ },
275
+ };
276
+ }
277
+ //# sourceMappingURL=driver-approvals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver-approvals.js","sourceRoot":"","sources":["../../src/harness/driver-approvals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `!` shell-command execution extracted from harness/driver.ts. Free-function
3
+ * collaborator: takes a {@link DriverBashCtx} instead of closing over
4
+ * createDriver's locals, so the harness factory stays out of this leaf.
5
+ * @module @dsh-cc/tui/harness/driver-bash
6
+ */
7
+ import type { DriverBashCtx } from './driver-ctx.ts';
8
+ /**
9
+ * Run a `!` shell command: echo the `$ cmd` row, park the running notice, then
10
+ * dispatch through the mounted shell executor when present or a timed/budgeted
11
+ * `/bin/sh -c` child otherwise. Uses the CURRENT view-model via `rt.state()`,
12
+ * and emits rows + notice through `rt.emit`.
13
+ */
14
+ export declare function runShellCommand(rt: DriverBashCtx, raw: string): Promise<void>;
15
+ //# sourceMappingURL=driver-bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver-bash.d.ts","sourceRoot":"","sources":["../../src/harness/driver-bash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AASpD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDnF"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * `!` shell-command execution extracted from harness/driver.ts. Free-function
3
+ * collaborator: takes a {@link DriverBashCtx} instead of closing over
4
+ * createDriver's locals, so the harness factory stays out of this leaf.
5
+ * @module @dsh-cc/tui/harness/driver-bash
6
+ */
7
+ import { upsertRow, setNotice } from "../store.js";
8
+ import { BASH_RUNNING_NOTICE, BASH_STDOUT_MAX_BYTES, BASH_TIMEOUT_MS, execFileAsync, shellOutputRow, } from "./shell-output.js";
9
+ /**
10
+ * Run a `!` shell command: echo the `$ cmd` row, park the running notice, then
11
+ * dispatch through the mounted shell executor when present or a timed/budgeted
12
+ * `/bin/sh -c` child otherwise. Uses the CURRENT view-model via `rt.state()`,
13
+ * and emits rows + notice through `rt.emit`.
14
+ */
15
+ export async function runShellCommand(rt, raw) {
16
+ const command = raw.trim();
17
+ if (command.length === 0)
18
+ return;
19
+ rt.appendBashHistory(command);
20
+ // `state` is rebound by emit — re-read via rt.state() after every emit,
21
+ // matching the original live `let` in createDriver.
22
+ rt.emit(upsertRow(rt.state(), { kind: 'status', text: `$ ${command}` }));
23
+ rt.emit(setNotice(rt.state(), BASH_RUNNING_NOTICE));
24
+ try {
25
+ if (rt.shell === undefined) {
26
+ // Degraded path: no shell executor mounted. Non-zero exits, timeout
27
+ // kills, and spawn failures all arrive as rejections.
28
+ const result = await execFileAsync('/bin/sh', ['-c', command], {
29
+ cwd: rt.cwd,
30
+ timeout: BASH_TIMEOUT_MS,
31
+ maxBuffer: BASH_STDOUT_MAX_BYTES,
32
+ });
33
+ const row = shellOutputRow(result.stdout, result.stderr, { exitCode: 0, timedOut: false });
34
+ if (row.text.length > 0)
35
+ rt.emit(upsertRow(rt.state(), row));
36
+ }
37
+ else {
38
+ const result = await rt.shell.run(rt.shell.resolve({
39
+ command,
40
+ timeoutMs: BASH_TIMEOUT_MS,
41
+ stdoutMaxBytes: BASH_STDOUT_MAX_BYTES,
42
+ }));
43
+ const row = shellOutputRow(result.stdout.text, result.stderr.text, result);
44
+ if (row.text.length > 0)
45
+ rt.emit(upsertRow(rt.state(), row));
46
+ }
47
+ }
48
+ catch (error) {
49
+ const failure = error;
50
+ let row;
51
+ if (typeof failure.code === 'number') {
52
+ // Non-zero exit from the fallback child: output rides on the error.
53
+ row = shellOutputRow(failure.stdout ?? '', failure.stderr ?? '', { exitCode: failure.code, timedOut: false });
54
+ }
55
+ else if (failure.killed === true) {
56
+ // The fallback child hit the timeout and was killed.
57
+ row = shellOutputRow(failure.stdout ?? '', failure.stderr ?? '', { exitCode: null, timedOut: true });
58
+ }
59
+ else {
60
+ // Infrastructure fault (executor rejection, unwritable workdir, no
61
+ // /bin/sh): the message is all there is to show.
62
+ row = { kind: 'status', text: failure.message ?? String(error), error: true };
63
+ }
64
+ if (row.text.length > 0)
65
+ rt.emit(upsertRow(rt.state(), row));
66
+ }
67
+ finally {
68
+ // Drop the running indicator only if nothing replaced it meanwhile.
69
+ if (rt.state().notice === BASH_RUNNING_NOTICE)
70
+ rt.emit(setNotice(rt.state(), undefined));
71
+ }
72
+ }
73
+ //# sourceMappingURL=driver-bash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver-bash.js","sourceRoot":"","sources":["../../src/harness/driver-bash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Slash-command catalog + subagent lifecycle listeners extracted from
3
+ * harness/driver.ts. Free-function collaborator: takes a
4
+ * {@link DriverCatalogCtx} instead of closing over createDriver's locals, so
5
+ * the harness factory stays out of this leaf.
6
+ *
7
+ * The catalog merges four sources with command-name precedence:
8
+ * TUI-local commands, the harness command registry (`ctx.commands`), the
9
+ * optional cc-shell plugin-command service (`ctx.ccPlugins`, colon-form
10
+ * `plugin:command` names), and user-invocable skills (`ctx.skills.snapshot()`). Skill names are duck-typed
11
+ * against upstream `SkillRegistry.snapshot` — the TUI never imports
12
+ * `@deepseek-ai/dsh-skill`; skills are optional and a missing service only
13
+ * leaves the skill half empty. Publishing a new catalog array emits the
14
+ * current state so root.ts's reference-equality guard rebuilds the
15
+ * autocomplete provider.
16
+ *
17
+ * @module @dsh-cc/tui/harness/driver-catalog
18
+ */
19
+ import type { DriverCatalogCtx } from './driver-ctx.ts';
20
+ /** Duck-typed surface for the mounted commands service (matches CommandsLike). */
21
+ export interface CommandsLike {
22
+ list(agent: unknown): {
23
+ name: string;
24
+ description?: string;
25
+ input?: {
26
+ hint?: string;
27
+ };
28
+ }[];
29
+ }
30
+ /**
31
+ * Duck-typed surface for the optional skills registry — the shape of upstream
32
+ * `SkillRegistry.snapshot` (see `@deepseek-ai/dsh-skill`). Only the fields the
33
+ * catalog merge reads are named; a missing service simply contributes no
34
+ * skill entries.
35
+ */
36
+ export interface SkillsLike {
37
+ snapshot(opts: {
38
+ cwd?: string;
39
+ scope?: unknown;
40
+ }): Promise<{
41
+ skills: readonly {
42
+ name: string;
43
+ description: string;
44
+ invocation: {
45
+ modelInvocable: boolean;
46
+ userInvocable: boolean;
47
+ };
48
+ }[];
49
+ complete: boolean;
50
+ }>;
51
+ }
52
+ /**
53
+ * Duck-typed surface for the optional cc-shell plugin-commands service (see
54
+ * CcPluginsService in cc-shell). Plugin commands are exposed in the colon
55
+ * display form `plugin:command` (e.g. `codex:review`); a missing service
56
+ * simply contributes no plugin entries — the TUI never imports cc-shell.
57
+ */
58
+ export interface CcPluginsLike {
59
+ listPluginCommands(): readonly {
60
+ name: string;
61
+ plugin: string;
62
+ description: string;
63
+ argumentHint?: string;
64
+ }[];
65
+ }
66
+ /** One merged catalog entry (commands and skills share the shape). */
67
+ export interface CatalogItem {
68
+ name: string;
69
+ description?: string;
70
+ argumentHint?: string;
71
+ }
72
+ /**
73
+ * Build the slash-command catalog section: merges LOCAL_COMMANDS with the
74
+ * harness registry and user-invocable skills, subscribes to
75
+ * `commands/change` / `skills/change` and subagent lifecycle events. The
76
+ * cached array identity stays stable between refreshes so root.ts can detect
77
+ * a change by reference equality and rebuild the autocomplete provider only
78
+ * when needed.
79
+ */
80
+ export declare function createCatalogSection(rt: DriverCatalogCtx): {
81
+ listCommands(): readonly CatalogItem[];
82
+ refreshCatalog(): void;
83
+ };
84
+ //# sourceMappingURL=driver-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver-catalog.d.ts","sourceRoot":"","sources":["../../src/harness/driver-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,EAAE,CAAA;CAC1F;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;QACzD,MAAM,EAAE,SAAS;YACf,IAAI,EAAE,MAAM,CAAA;YACZ,WAAW,EAAE,MAAM,CAAA;YACnB,UAAU,EAAE;gBAAE,cAAc,EAAE,OAAO,CAAC;gBAAC,aAAa,EAAE,OAAO,CAAA;aAAE,CAAA;SAChE,EAAE,CAAA;QACH,QAAQ,EAAE,OAAO,CAAA;KAClB,CAAC,CAAA;CACH;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,kBAAkB,IAAI,SAAS;QAC7B,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,MAAM,CAAA;QACd,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,EAAE,CAAA;CACJ;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,gBAAgB,GAAG;IAC1D,YAAY,IAAI,SAAS,WAAW,EAAE,CAAA;IACtC,cAAc,IAAI,IAAI,CAAA;CACvB,CAiOA"}