@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 @@
1
+ {"version":3,"file":"statusline.d.ts","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACnE,+CAA+C;IAC/C,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE,OAAO,CAAA;CACd;AAUD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUnD;AAKD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CA+B1F"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Footer status line for the CC-mode TUI.
3
+ * @module @dsh-cc/tui/statusline
4
+ */
5
+ import { homedir } from 'node:os';
6
+ function shortenCwd(cwd) {
7
+ const home = homedir();
8
+ if (home.length > 0 && (cwd === home || cwd.startsWith(`${home}/`))) {
9
+ return `~${cwd.slice(home.length)}`;
10
+ }
11
+ return cwd;
12
+ }
13
+ /**
14
+ * Compact a session id to its `prefix-first8hex` form (e.g.
15
+ * `tui-abcdef01-…` → `tui-abcdef01`). Falls back to the full id when the
16
+ * shape doesn't match. Shared by the footer and `/agents`.
17
+ */
18
+ export function shortenSession(sessionId) {
19
+ const match = sessionId.match(/^([a-z]+-[0-9a-f]{8})/i);
20
+ return match?.[1] ?? sessionId;
21
+ }
22
+ /**
23
+ * Compact a token count for the footer: exact below 1k, one decimal below
24
+ * 100k (`12.3k`), integer above (`123k`), and `m` past a million. Negative
25
+ * and non-finite inputs clamp to `0` — the line stays total on bad data.
26
+ */
27
+ export function formatTokens(tokens) {
28
+ if (!Number.isFinite(tokens) || tokens < 0)
29
+ return '0';
30
+ if (tokens < 1000)
31
+ return String(Math.round(tokens));
32
+ const scaled = (divisor, suffix) => {
33
+ const value = tokens / divisor;
34
+ const compact = value >= 100 ? Math.round(value) : Math.round(value * 10) / 10;
35
+ return `${compact}${suffix}`;
36
+ };
37
+ if (tokens < 1_000_000)
38
+ return scaled(1000, 'k');
39
+ return scaled(1_000_000, 'm');
40
+ }
41
+ /** Key-hint tail segments shared by the built-in line and the mode row. */
42
+ const MODE_HINTS = ['shift+tab', '/quit'];
43
+ /**
44
+ * The client-drawn permission-mode row appended under a custom statusline
45
+ * (`<mode> · shift+tab · /quit`); shares the hint constants with the
46
+ * built-in line so the formats cannot drift.
47
+ */
48
+ export function formatModeLine(permissionMode) {
49
+ return [permissionMode, ...MODE_HINTS].join(' · ');
50
+ }
51
+ /**
52
+ * Compact footer: `cwd [branch] · session · mode · model · ctx NN% ·
53
+ * ↑in ↓out tok` plus the busy marker and key hints. Absent optional fields
54
+ * drop their segments; the function is pure and total on undefined inputs.
55
+ *
56
+ * When the context window is known the ctx segment grows an exact
57
+ * `(used/window)` detail. `opts.width` is a terminal-width hint: when the
58
+ * assembled line would overflow it, only that parenthetical detail is dropped
59
+ * and the bare `ctx NN%` survives (other segments are never elided).
60
+ */
61
+ export function formatStatusLine(input, opts) {
62
+ const left = input.branch === undefined || input.branch.length === 0
63
+ ? shortenCwd(input.cwd)
64
+ : `${shortenCwd(input.cwd)} [${input.branch}]`;
65
+ const build = (withDetail) => {
66
+ const parts = [
67
+ left,
68
+ shortenSession(input.sessionId),
69
+ input.permissionMode,
70
+ ];
71
+ if (input.model !== undefined && input.model.length > 0)
72
+ parts.push(input.model);
73
+ if (input.effort !== undefined && input.effort.length > 0)
74
+ parts.push(`effort: ${input.effort}`);
75
+ if (input.contextPercent !== undefined) {
76
+ const percent = Math.max(0, Math.min(100, Math.round(input.contextPercent)));
77
+ const tokens = input.contextTokens;
78
+ const detail = withDetail && tokens !== undefined && tokens.window !== undefined && tokens.window > 0
79
+ ? ` (${formatTokens(tokens.used)}/${formatTokens(tokens.window)})`
80
+ : '';
81
+ parts.push(`ctx ${percent}%${detail}`);
82
+ }
83
+ if (input.tokens !== undefined) {
84
+ parts.push(`↑${formatTokens(input.tokens.input)} ↓${formatTokens(input.tokens.output)} tok`);
85
+ }
86
+ if (input.busy)
87
+ parts.push('working');
88
+ parts.push(...MODE_HINTS);
89
+ return parts.join(' · ');
90
+ };
91
+ const line = build(true);
92
+ const width = opts?.width;
93
+ if (width !== undefined && width > 0 && line.length > width)
94
+ return build(false);
95
+ return line;
96
+ }
97
+ //# sourceMappingURL=statusline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusline.js","sourceRoot":"","sources":["../src/statusline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { EffortPickerView, ModelPickerView, PermissionPickerView, SessionSwitcherView, TuiState, WorktreeExitView } from './views.ts';
2
+ /** Park or clear the `/model` picker overlay. */
3
+ export declare function setModelPicker(state: TuiState, picker: ModelPickerView | undefined): TuiState;
4
+ /** Focus a model-picker row by index, clamped to [0, entries.length-1]. */
5
+ export declare function focusModelPicker(state: TuiState, index: number): TuiState;
6
+ /** Move the model-picker focus by one row (clamped; no wrap). */
7
+ export declare function moveModelPickerFocus(state: TuiState, delta: -1 | 1): TuiState;
8
+ /** Park or clear the `/effort` picker overlay. */
9
+ export declare function setEffortPicker(state: TuiState, picker: EffortPickerView | undefined): TuiState;
10
+ /** Focus an effort-picker row by index, clamped to [0, entries.length-1]. */
11
+ export declare function focusEffortPicker(state: TuiState, index: number): TuiState;
12
+ /** Move the effort-picker focus by one row (clamped; no wrap). */
13
+ export declare function moveEffortPickerFocus(state: TuiState, delta: -1 | 1): TuiState;
14
+ /** Park or clear the `/permissions` picker overlay. */
15
+ export declare function setPermissionPicker(state: TuiState, picker: PermissionPickerView | undefined): TuiState;
16
+ /**
17
+ * Focus a permission-picker row by index, clamped to [0, entries.length-1].
18
+ * Always drops `confirmingBypass` so the risk-gate flag cannot stick to a
19
+ * non-bypass row after the user moves.
20
+ */
21
+ export declare function focusPermissionPicker(state: TuiState, index: number): TuiState;
22
+ /** Move the permission-picker focus by one row (clamped; no wrap). */
23
+ export declare function movePermissionPickerFocus(state: TuiState, delta: -1 | 1): TuiState;
24
+ /** Park or clear the `/resume` session-switcher overlay. */
25
+ export declare function setSessionSwitcher(state: TuiState, switcher: SessionSwitcherView | undefined): TuiState;
26
+ /** Focus a session-switcher row by index, clamped to [0, sessions.length-1]. */
27
+ export declare function focusSessionSwitcher(state: TuiState, index: number): TuiState;
28
+ /** Move the session-switcher focus by one row (clamped; no wrap). */
29
+ export declare function moveSessionSwitcherFocus(state: TuiState, delta: -1 | 1): TuiState;
30
+ /** Park or clear the `/quit` worktree-exit confirmation overlay. */
31
+ export declare function setWorktreeExit(state: TuiState, view: WorktreeExitView | undefined): TuiState;
32
+ /** Move the worktree-exit focus by one row (clamped; no wrap). */
33
+ export declare function moveWorktreeExitFocus(state: TuiState, delta: -1 | 1): TuiState;
34
+ //# sourceMappingURL=pickers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pickers.d.ts","sourceRoot":"","sources":["../../src/store/pickers.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE1I,iDAAiD;AACjD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,GAAG,SAAS,GAAG,QAAQ,CAG7F;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAMzE;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAI7E;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,QAAQ,CAG/F;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAM1E;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAI9E;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,oBAAoB,GAAG,SAAS,GAAG,QAAQ,CAGvG;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAQ9E;AAED,sEAAsE;AACtE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAIlF;AAED,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,mBAAmB,GAAG,SAAS,GAAG,QAAQ,CAGvG;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAM7E;AAED,qEAAqE;AACrE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAIjF;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAgB,GAAG,SAAS,GAAG,QAAQ,CAG7F;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAK9E"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Overlay picker reducers (/model, /effort, /permissions, /resume): a shared
3
+ * park-or-clear plus clamped focus/move pattern per picker overlay.
4
+ * @module @dsh-cc/tui/store/pickers
5
+ */
6
+ import { WORKTREE_EXIT_OPTION_COUNT } from "./views.js";
7
+ /** Park or clear the `/model` picker overlay. */
8
+ export function setModelPicker(state, picker) {
9
+ const { modelPicker: _dropped, ...rest } = state;
10
+ return picker === undefined ? rest : { ...rest, modelPicker: picker };
11
+ }
12
+ /** Focus a model-picker row by index, clamped to [0, entries.length-1]. */
13
+ export function focusModelPicker(state, index) {
14
+ const picker = state.modelPicker;
15
+ if (picker === undefined || picker.entries.length === 0)
16
+ return state;
17
+ const max = picker.entries.length - 1;
18
+ const focused = Math.max(0, Math.min(index, max));
19
+ return setModelPicker(state, { ...picker, focused });
20
+ }
21
+ /** Move the model-picker focus by one row (clamped; no wrap). */
22
+ export function moveModelPickerFocus(state, delta) {
23
+ const picker = state.modelPicker;
24
+ if (picker === undefined)
25
+ return state;
26
+ return focusModelPicker(state, picker.focused + delta);
27
+ }
28
+ /** Park or clear the `/effort` picker overlay. */
29
+ export function setEffortPicker(state, picker) {
30
+ const { effortPicker: _dropped, ...rest } = state;
31
+ return picker === undefined ? rest : { ...rest, effortPicker: picker };
32
+ }
33
+ /** Focus an effort-picker row by index, clamped to [0, entries.length-1]. */
34
+ export function focusEffortPicker(state, index) {
35
+ const picker = state.effortPicker;
36
+ if (picker === undefined || picker.entries.length === 0)
37
+ return state;
38
+ const max = picker.entries.length - 1;
39
+ const focused = Math.max(0, Math.min(index, max));
40
+ return setEffortPicker(state, { ...picker, focused });
41
+ }
42
+ /** Move the effort-picker focus by one row (clamped; no wrap). */
43
+ export function moveEffortPickerFocus(state, delta) {
44
+ const picker = state.effortPicker;
45
+ if (picker === undefined)
46
+ return state;
47
+ return focusEffortPicker(state, picker.focused + delta);
48
+ }
49
+ /** Park or clear the `/permissions` picker overlay. */
50
+ export function setPermissionPicker(state, picker) {
51
+ const { permissionPicker: _dropped, ...rest } = state;
52
+ return picker === undefined ? rest : { ...rest, permissionPicker: picker };
53
+ }
54
+ /**
55
+ * Focus a permission-picker row by index, clamped to [0, entries.length-1].
56
+ * Always drops `confirmingBypass` so the risk-gate flag cannot stick to a
57
+ * non-bypass row after the user moves.
58
+ */
59
+ export function focusPermissionPicker(state, index) {
60
+ const picker = state.permissionPicker;
61
+ if (picker === undefined || picker.entries.length === 0)
62
+ return state;
63
+ const max = picker.entries.length - 1;
64
+ const focused = Math.max(0, Math.min(index, max));
65
+ if (focused === picker.focused && picker.confirmingBypass === undefined)
66
+ return state;
67
+ const { confirmingBypass: _dropped, ...rest } = picker;
68
+ return setPermissionPicker(state, { ...rest, focused });
69
+ }
70
+ /** Move the permission-picker focus by one row (clamped; no wrap). */
71
+ export function movePermissionPickerFocus(state, delta) {
72
+ const picker = state.permissionPicker;
73
+ if (picker === undefined)
74
+ return state;
75
+ return focusPermissionPicker(state, picker.focused + delta);
76
+ }
77
+ /** Park or clear the `/resume` session-switcher overlay. */
78
+ export function setSessionSwitcher(state, switcher) {
79
+ const { sessionSwitcher: _dropped, ...rest } = state;
80
+ return switcher === undefined ? rest : { ...rest, sessionSwitcher: switcher };
81
+ }
82
+ /** Focus a session-switcher row by index, clamped to [0, sessions.length-1]. */
83
+ export function focusSessionSwitcher(state, index) {
84
+ const sw = state.sessionSwitcher;
85
+ if (sw === undefined || sw.sessions.length === 0)
86
+ return state;
87
+ const max = sw.sessions.length - 1;
88
+ const focused = Math.max(0, Math.min(index, max));
89
+ return setSessionSwitcher(state, { ...sw, focused });
90
+ }
91
+ /** Move the session-switcher focus by one row (clamped; no wrap). */
92
+ export function moveSessionSwitcherFocus(state, delta) {
93
+ const sw = state.sessionSwitcher;
94
+ if (sw === undefined)
95
+ return state;
96
+ return focusSessionSwitcher(state, sw.focused + delta);
97
+ }
98
+ /** Park or clear the `/quit` worktree-exit confirmation overlay. */
99
+ export function setWorktreeExit(state, view) {
100
+ const { worktreeExit: _dropped, ...rest } = state;
101
+ return view === undefined ? rest : { ...rest, worktreeExit: view };
102
+ }
103
+ /** Move the worktree-exit focus by one row (clamped; no wrap). */
104
+ export function moveWorktreeExitFocus(state, delta) {
105
+ const view = state.worktreeExit;
106
+ if (view === undefined)
107
+ return state;
108
+ const focused = Math.max(0, Math.min(view.focused + delta, WORKTREE_EXIT_OPTION_COUNT - 1));
109
+ return setWorktreeExit(state, { ...view, focused });
110
+ }
111
+ //# sourceMappingURL=pickers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pickers.js","sourceRoot":"","sources":["../../src/store/pickers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * `/provider` panel reducer (design doc §4.2–§4.4): pure phase transitions for
3
+ * the list / detail / wizard / confirm-remove overlay. No I/O — rows and steps
4
+ * arrive from the caller (see provider-flow.ts for the list merge rule).
5
+ * @module @dsh-cc/tui/store/provider-panel
6
+ */
7
+ import type { MoreProviderRow, ProviderRow } from '../provider-flow.ts';
8
+ import type { TuiState } from './views.ts';
9
+ /**
10
+ * Park or clear the open `/provider` overlay in the aggregate state. The
11
+ * panel phase/cursor/rows come from this module's pure reducers; the driver
12
+ * re-parks the whole state after each transition.
13
+ */
14
+ export declare function setProviderOverlay(state: TuiState, panel: ProviderPanelState | undefined): TuiState;
15
+ export type ProviderPanelState = {
16
+ phase: 'list' | 'detail' | 'wizard' | 'confirm-remove';
17
+ cursor: number;
18
+ rows: readonly ProviderRow[];
19
+ /** Directory tail collapsed under "More providers…" (§4.2 merge rule). */
20
+ more: readonly MoreProviderRow[];
21
+ /** Route the detail / wizard / confirm views target. */
22
+ selected?: string;
23
+ wizard?: {
24
+ kind: 'preset' | 'custom' | 'rotate';
25
+ route: string;
26
+ displayName?: string;
27
+ steps: readonly string[];
28
+ stepIndex: number;
29
+ /** Non-secret answers only (§6): the API key never lands here. */
30
+ answers: Record<string, string>;
31
+ /** Selection cursor for single-choice steps (protocol pick). */
32
+ selectIndex?: number;
33
+ /** Verify-step outcome (§4.3.2). */
34
+ verify?: {
35
+ status: 'pending' | 'ok' | 'failed' | 'skipped';
36
+ message?: string;
37
+ };
38
+ /** Per-entry model-list parse errors (§4.6). */
39
+ modelErrors?: string[];
40
+ note?: string;
41
+ };
42
+ /** Detail-view facts (§4.4), computed by the runtime at enter time. */
43
+ detail?: {
44
+ profileJson: string;
45
+ endpoint: string;
46
+ api: string;
47
+ modelCount: number;
48
+ credentialLine: string;
49
+ };
50
+ /** Detail action rows, precomputed by the runtime (disabled carries its reason). */
51
+ actions?: readonly {
52
+ id: string;
53
+ label: string;
54
+ disabled?: boolean;
55
+ reason?: string;
56
+ }[];
57
+ actionCursor?: number;
58
+ /** Remove double-confirm stage: the unset confirm, then the managed-credential drop offer. */
59
+ stage?: 'confirm' | 'drop-credential';
60
+ message?: string;
61
+ };
62
+ /** Open the overlay on its list home (§4.2). */
63
+ export declare function openProviderPanel(rows: readonly ProviderRow[], more?: readonly MoreProviderRow[]): ProviderPanelState;
64
+ /** Move the list cursor by one row, clamped without wrapping. */
65
+ export declare function moveCursor(state: ProviderPanelState, delta: -1 | 1): ProviderPanelState;
66
+ /** Enter the manage view (§4.4) for the focused configured row. */
67
+ export declare function enterDetail(state: ProviderPanelState): ProviderPanelState;
68
+ /** Back to the list (esc from detail/confirm); clears the selection, any message, and action state. */
69
+ export declare function backToList(state: ProviderPanelState): ProviderPanelState;
70
+ /** Begin the add flow (§4.3/§4.6) for a preset or custom route with its ordered steps. */
71
+ export declare function startWizardFor(state: ProviderPanelState, route: string, steps: readonly string[], opts?: {
72
+ kind?: 'preset' | 'custom' | 'rotate';
73
+ displayName?: string;
74
+ answers?: Record<string, string>;
75
+ }): ProviderPanelState;
76
+ /** Record one wizard answer without mutating prior state. */
77
+ export declare function wizardSetAnswer(state: ProviderPanelState, key: string, value: string): ProviderPanelState;
78
+ /** Advance one wizard step, clamped at the last (the caller completes from there). */
79
+ export declare function wizardNext(state: ProviderPanelState): ProviderPanelState;
80
+ /** Step back one wizard step; clamped at the first. */
81
+ export declare function wizardBack(state: ProviderPanelState): ProviderPanelState;
82
+ /** Leave the wizard back to the list (esc path); drops wizard state. */
83
+ export declare function backFromWizard(state: ProviderPanelState): ProviderPanelState;
84
+ /** Arm the remove double-confirm (§4.4) from the detail view. */
85
+ export declare function startRemove(state: ProviderPanelState): ProviderPanelState;
86
+ /** Move the detail action cursor by one row, clamped without wrapping. */
87
+ export declare function moveDetailCursor(state: ProviderPanelState, delta: -1 | 1): ProviderPanelState;
88
+ /** Park the detail facts + action rows computed by the runtime. */
89
+ export declare function setDetail(state: ProviderPanelState, detail: ProviderPanelState['detail'], actions: ProviderPanelState['actions']): ProviderPanelState;
90
+ /** Wizard single-choice cursor (protocol pick). */
91
+ export declare function wizardSetSelectIndex(state: ProviderPanelState, index: number): ProviderPanelState;
92
+ /** Park the verify-step outcome (§4.3.2). */
93
+ export declare function wizardSetVerify(state: ProviderPanelState, verify: {
94
+ status: 'pending' | 'ok' | 'failed' | 'skipped';
95
+ message?: string;
96
+ } | undefined): ProviderPanelState;
97
+ /** Park per-entry model-list parse errors (§4.6). */
98
+ export declare function wizardSetModelErrors(state: ProviderPanelState, errors: string[]): ProviderPanelState;
99
+ /** Park a wizard note (env-skip line, validator refusal, verify reason). */
100
+ export declare function wizardSetNote(state: ProviderPanelState, note: string | undefined): ProviderPanelState;
101
+ /** Move the remove confirm between the unset confirm and the credential-drop offer. */
102
+ export declare function setRemoveStage(state: ProviderPanelState, stage: NonNullable<ProviderPanelState['stage']>): ProviderPanelState;
103
+ /** Cancel the remove confirmation (esc path) — back to the detail view. */
104
+ export declare function cancelRemove(state: ProviderPanelState): ProviderPanelState;
105
+ /** Show a one-line note (e.g. "N models reachable", verify-failure reason). */
106
+ export declare function setMessage(state: ProviderPanelState, message: string | undefined): ProviderPanelState;
107
+ //# sourceMappingURL=provider-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-panel.d.ts","sourceRoot":"","sources":["../../src/store/provider-panel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Park or clear the open `/provider` overlay in the aggregate state. The
3
+ * panel phase/cursor/rows come from this module's pure reducers; the driver
4
+ * re-parks the whole state after each transition.
5
+ */
6
+ export function setProviderOverlay(state, panel) {
7
+ if (panel === undefined) {
8
+ if (state.providerPanel === undefined)
9
+ return state;
10
+ const { providerPanel: _dropped, ...rest } = state;
11
+ return rest;
12
+ }
13
+ return { ...state, providerPanel: panel };
14
+ }
15
+ /** Open the overlay on its list home (§4.2). */
16
+ export function openProviderPanel(rows, more = []) {
17
+ return { phase: 'list', cursor: 0, rows, more };
18
+ }
19
+ /** Move the list cursor by one row, clamped without wrapping. */
20
+ export function moveCursor(state, delta) {
21
+ if (state.phase !== 'list' || state.rows.length === 0)
22
+ return state;
23
+ return { ...state, cursor: Math.max(0, Math.min(state.cursor + delta, state.rows.length - 1)) };
24
+ }
25
+ /** Enter the manage view (§4.4) for the focused configured row. */
26
+ export function enterDetail(state) {
27
+ const row = state.rows[state.cursor];
28
+ if (state.phase !== 'list' || row === undefined)
29
+ return state;
30
+ return { ...state, phase: 'detail', selected: row.route };
31
+ }
32
+ /** Back to the list (esc from detail/confirm); clears the selection, any message, and action state. */
33
+ export function backToList(state) {
34
+ if (state.phase !== 'detail' && state.phase !== 'confirm-remove')
35
+ return state;
36
+ const { selected: _s, message: _m, stage: _st, detail: _d, actions: _a, actionCursor: _c, ...rest } = state;
37
+ return { ...rest, phase: 'list' };
38
+ }
39
+ /** Begin the add flow (§4.3/§4.6) for a preset or custom route with its ordered steps. */
40
+ export function startWizardFor(state, route, steps, opts = {}) {
41
+ if (steps.length === 0)
42
+ return state;
43
+ return {
44
+ ...state,
45
+ phase: 'wizard',
46
+ wizard: {
47
+ kind: opts.kind ?? 'preset',
48
+ route,
49
+ ...(opts.displayName === undefined ? {} : { displayName: opts.displayName }),
50
+ steps,
51
+ stepIndex: 0,
52
+ answers: opts.answers ?? {},
53
+ selectIndex: 0,
54
+ },
55
+ };
56
+ }
57
+ /** Record one wizard answer without mutating prior state. */
58
+ export function wizardSetAnswer(state, key, value) {
59
+ if (state.wizard === undefined)
60
+ return state;
61
+ return { ...state, wizard: { ...state.wizard, answers: { ...state.wizard.answers, [key]: value } } };
62
+ }
63
+ /** Advance one wizard step, clamped at the last (the caller completes from there). */
64
+ export function wizardNext(state) {
65
+ const wizard = state.wizard;
66
+ if (state.phase !== 'wizard' || wizard === undefined)
67
+ return state;
68
+ return { ...state, wizard: { ...wizard, stepIndex: Math.min(wizard.stepIndex + 1, wizard.steps.length - 1) } };
69
+ }
70
+ /** Step back one wizard step; clamped at the first. */
71
+ export function wizardBack(state) {
72
+ const wizard = state.wizard;
73
+ if (state.phase !== 'wizard' || wizard === undefined)
74
+ return state;
75
+ return { ...state, wizard: { ...wizard, stepIndex: Math.max(wizard.stepIndex - 1, 0) } };
76
+ }
77
+ /** Leave the wizard back to the list (esc path); drops wizard state. */
78
+ export function backFromWizard(state) {
79
+ if (state.phase !== 'wizard')
80
+ return state;
81
+ const { wizard: _w, message: _m, ...rest } = state;
82
+ return { ...rest, phase: 'list' };
83
+ }
84
+ /** Arm the remove double-confirm (§4.4) from the detail view. */
85
+ export function startRemove(state) {
86
+ if (state.phase !== 'detail' || state.selected === undefined)
87
+ return state;
88
+ return { ...state, phase: 'confirm-remove', stage: 'confirm' };
89
+ }
90
+ /** Move the detail action cursor by one row, clamped without wrapping. */
91
+ export function moveDetailCursor(state, delta) {
92
+ const count = state.actions?.length ?? 0;
93
+ if (state.phase !== 'detail' || count === 0)
94
+ return state;
95
+ const cursor = Math.max(0, Math.min((state.actionCursor ?? 0) + delta, count - 1));
96
+ return { ...state, actionCursor: cursor };
97
+ }
98
+ /** Park the detail facts + action rows computed by the runtime. */
99
+ export function setDetail(state, detail, actions) {
100
+ if (state.phase !== 'detail')
101
+ return state;
102
+ return { ...state, ...(detail === undefined ? {} : { detail }), ...(actions === undefined ? {} : { actions }), actionCursor: state.actionCursor ?? 0 };
103
+ }
104
+ /** Wizard single-choice cursor (protocol pick). */
105
+ export function wizardSetSelectIndex(state, index) {
106
+ if (state.wizard === undefined)
107
+ return state;
108
+ return { ...state, wizard: { ...state.wizard, selectIndex: index } };
109
+ }
110
+ /** Park the verify-step outcome (§4.3.2). */
111
+ export function wizardSetVerify(state, verify) {
112
+ if (state.wizard === undefined)
113
+ return state;
114
+ const { verify: _dropped, ...wizard } = state.wizard;
115
+ return { ...state, wizard: verify === undefined ? wizard : { ...wizard, verify } };
116
+ }
117
+ /** Park per-entry model-list parse errors (§4.6). */
118
+ export function wizardSetModelErrors(state, errors) {
119
+ if (state.wizard === undefined)
120
+ return state;
121
+ const { modelErrors: _dropped, ...wizard } = state.wizard;
122
+ return { ...state, wizard: errors.length === 0 ? wizard : { ...wizard, modelErrors: errors } };
123
+ }
124
+ /** Park a wizard note (env-skip line, validator refusal, verify reason). */
125
+ export function wizardSetNote(state, note) {
126
+ if (state.wizard === undefined)
127
+ return state;
128
+ const { note: _dropped, ...wizard } = state.wizard;
129
+ return { ...state, wizard: note === undefined ? wizard : { ...wizard, note } };
130
+ }
131
+ /** Move the remove confirm between the unset confirm and the credential-drop offer. */
132
+ export function setRemoveStage(state, stage) {
133
+ if (state.phase !== 'confirm-remove')
134
+ return state;
135
+ return { ...state, stage };
136
+ }
137
+ /** Cancel the remove confirmation (esc path) — back to the detail view. */
138
+ export function cancelRemove(state) {
139
+ if (state.phase !== 'confirm-remove')
140
+ return state;
141
+ return { ...state, phase: 'detail' };
142
+ }
143
+ /** Show a one-line note (e.g. "N models reachable", verify-failure reason). */
144
+ export function setMessage(state, message) {
145
+ if (message === undefined) {
146
+ const { message: _dropped, ...rest } = state;
147
+ return rest;
148
+ }
149
+ return { ...state, message };
150
+ }
151
+ //# sourceMappingURL=provider-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-panel.js","sourceRoot":"","sources":["../../src/store/provider-panel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Ask-user-question reducers: focus/toggle/type navigation over QuestionView.
3
+ * @module @dsh-cc/tui/store/question
4
+ */
5
+ import type { QuestionView, TuiState } from './views.ts';
6
+ /** Park or clear an ask-user prompt. */
7
+ export declare function setQuestion(state: TuiState, question: QuestionView | undefined): TuiState;
8
+ /** Focus a question row by index, clamped to [0, options.length]. */
9
+ export declare function focusQuestionOption(state: TuiState, index: number): TuiState;
10
+ /** Move the question focus by one row (clamped; no wrap). */
11
+ export declare function moveQuestionFocus(state: TuiState, delta: -1 | 1): TuiState;
12
+ /**
13
+ * Focus an option row and toggle its label in `selected` (multi-select).
14
+ * Out-of-range indexes are a no-op returning the same state reference.
15
+ */
16
+ export declare function toggleQuestionOption(state: TuiState, index: number): TuiState;
17
+ /** Append free text to the "Other" buffer and focus that row. */
18
+ export declare function typeQuestionText(state: TuiState, text: string): TuiState;
19
+ /** Drop the last character of the "Other" buffer (keeps focus on that row). */
20
+ export declare function backspaceQuestionText(state: TuiState): TuiState;
21
+ //# sourceMappingURL=question.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"question.d.ts","sourceRoot":"","sources":["../../src/store/question.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAExD,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,QAAQ,CAGzF;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAK5E;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,CAI1E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAS7E;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAQxE;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAQ/D"}
@@ -0,0 +1,59 @@
1
+ /** Park or clear an ask-user prompt. */
2
+ export function setQuestion(state, question) {
3
+ const { question: _dropped, ...rest } = state;
4
+ return question === undefined ? rest : { ...rest, question };
5
+ }
6
+ /** Focus a question row by index, clamped to [0, options.length]. */
7
+ export function focusQuestionOption(state, index) {
8
+ const question = state.question;
9
+ if (question === undefined)
10
+ return state;
11
+ const focused = Math.max(0, Math.min(index, question.options.length));
12
+ return setQuestion(state, { ...question, focused });
13
+ }
14
+ /** Move the question focus by one row (clamped; no wrap). */
15
+ export function moveQuestionFocus(state, delta) {
16
+ const question = state.question;
17
+ if (question === undefined)
18
+ return state;
19
+ return focusQuestionOption(state, question.focused + delta);
20
+ }
21
+ /**
22
+ * Focus an option row and toggle its label in `selected` (multi-select).
23
+ * Out-of-range indexes are a no-op returning the same state reference.
24
+ */
25
+ export function toggleQuestionOption(state, index) {
26
+ const question = state.question;
27
+ if (question === undefined)
28
+ return state;
29
+ const option = question.options[index];
30
+ if (option === undefined)
31
+ return state;
32
+ const selected = question.selected.includes(option.label)
33
+ ? question.selected.filter(label => label !== option.label)
34
+ : [...question.selected, option.label];
35
+ return setQuestion(state, { ...question, focused: index, selected });
36
+ }
37
+ /** Append free text to the "Other" buffer and focus that row. */
38
+ export function typeQuestionText(state, text) {
39
+ const question = state.question;
40
+ if (question === undefined || text.length === 0)
41
+ return state;
42
+ return setQuestion(state, {
43
+ ...question,
44
+ custom: question.custom + text,
45
+ focused: question.options.length,
46
+ });
47
+ }
48
+ /** Drop the last character of the "Other" buffer (keeps focus on that row). */
49
+ export function backspaceQuestionText(state) {
50
+ const question = state.question;
51
+ if (question === undefined || question.custom.length === 0)
52
+ return state;
53
+ return setQuestion(state, {
54
+ ...question,
55
+ custom: question.custom.slice(0, -1),
56
+ focused: question.options.length,
57
+ });
58
+ }
59
+ //# sourceMappingURL=question.js.map