tumwater 0.2.0 → 0.3.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 (446) hide show
  1. package/README.md +27 -13
  2. package/dist/build-info.json +2 -2
  3. package/dist/src/agent/agent-args.js +8 -9
  4. package/dist/src/agent/agent-backend.js +8 -6
  5. package/dist/src/agent/backend-traits.js +42 -25
  6. package/dist/src/agent/claude/claude-account.js +71 -204
  7. package/dist/src/agent/claude/claude-args.js +9 -6
  8. package/dist/src/agent/claude/claude-backend.js +10 -10
  9. package/dist/src/agent/claude/claude-env.js +1 -1
  10. package/dist/src/agent/claude/claude-stream.js +4 -3
  11. package/dist/src/agent/claude/claude-write-guard.js +49 -0
  12. package/dist/src/agent/claude/write-guard-hook.js +13 -0
  13. package/dist/src/agent/codex/codex-account.js +119 -0
  14. package/dist/src/agent/codex/codex-args.js +181 -0
  15. package/dist/src/agent/codex/codex-backend.js +279 -0
  16. package/dist/src/agent/codex/codex-catalog.js +97 -0
  17. package/dist/src/agent/codex/codex-env.js +18 -0
  18. package/dist/src/agent/codex/codex-hook-trust.js +246 -0
  19. package/dist/src/agent/codex/codex-patch-paths.js +36 -0
  20. package/dist/src/agent/codex/codex-rollout.js +179 -0
  21. package/dist/src/agent/codex/codex-stream.js +402 -0
  22. package/dist/src/agent/codex/codex-write-guard.js +86 -0
  23. package/dist/src/agent/codex/write-guard-hook.js +12 -0
  24. package/dist/src/agent/image-input.js +29 -24
  25. package/dist/src/agent/notes-shim.js +11 -12
  26. package/dist/src/agent/opencode/opencode-args.js +0 -1
  27. package/dist/src/agent/opencode/opencode-backend.js +12 -9
  28. package/dist/src/agent/opencode/opencode-catalog.js +55 -29
  29. package/dist/src/agent/opencode/opencode-config.js +19 -14
  30. package/dist/src/agent/opencode/opencode-env.js +0 -1
  31. package/dist/src/agent/opencode/opencode-session-id.js +1 -2
  32. package/dist/src/agent/opencode/opencode-stream.js +1 -1
  33. package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
  34. package/dist/src/agent/role-notes-write.js +5 -6
  35. package/dist/src/agent/run-agent.js +465 -448
  36. package/dist/src/agent/run-settle.js +214 -0
  37. package/dist/src/agent/session-ledger.js +86 -16
  38. package/dist/src/agent/subscription-account.js +220 -0
  39. package/dist/src/agent/write-guard.js +148 -0
  40. package/dist/src/backlog/backlog-archive.js +246 -55
  41. package/dist/src/backlog/backlog-cli-view.js +280 -0
  42. package/dist/src/backlog/backlog-cli.js +85 -274
  43. package/dist/src/backlog/backlog-commit.js +4 -5
  44. package/dist/src/backlog/backlog-eligibility.js +175 -242
  45. package/dist/src/backlog/backlog-index.js +149 -0
  46. package/dist/src/backlog/backlog-md.js +54 -6
  47. package/dist/src/backlog/backlog-parts.js +254 -0
  48. package/dist/src/backlog/backlog-release.js +117 -0
  49. package/dist/src/backlog/backlog-render.js +27 -0
  50. package/dist/src/backlog/backlog-structure.js +99 -156
  51. package/dist/src/backlog/backlog-write.js +40 -127
  52. package/dist/src/backlog/backlog.js +21 -6
  53. package/dist/src/backlog/question-answer.js +21 -15
  54. package/dist/src/baseline/main-baseline.js +89 -20
  55. package/dist/src/baseline/main-culprit.js +94 -0
  56. package/dist/src/baseline/main-guardrails.js +209 -0
  57. package/dist/src/baseline/main-red.js +139 -32
  58. package/dist/src/baseline/main-revert.js +133 -0
  59. package/dist/src/baseline/main-watch.js +184 -0
  60. package/dist/src/brief/brief-edit.js +9 -11
  61. package/dist/src/brief/brief.js +31 -51
  62. package/dist/src/budget/budget.js +30 -20
  63. package/dist/src/budget/fallback-breaker.js +26 -27
  64. package/dist/src/build/build-check-detect.js +23 -15
  65. package/dist/src/build/build-check-events.js +25 -6
  66. package/dist/src/build/build-check-report.js +49 -9
  67. package/dist/src/build/build-check-scoped.js +18 -11
  68. package/dist/src/build/build-check.js +2 -1
  69. package/dist/src/build/build-info.js +2 -3
  70. package/dist/src/build/build-stage.js +9 -14
  71. package/dist/src/build/dep-install.js +1 -2
  72. package/dist/src/change/change-data.js +123 -31
  73. package/dist/src/change/change-render.js +46 -5
  74. package/dist/src/cli/brief-command.js +3 -4
  75. package/dist/src/cli/cli-args.js +118 -33
  76. package/dist/src/cli/cli-command-args.js +46 -18
  77. package/dist/src/cli/cli-editor.js +2 -1
  78. package/dist/src/cli/cli-flag-specs.js +150 -45
  79. package/dist/src/cli/cli-init.js +51 -0
  80. package/dist/src/cli/cli-marker-commands.js +4 -4
  81. package/dist/src/cli/cli-query-commands.js +308 -590
  82. package/dist/src/cli/cli-repo-gate.js +11 -1
  83. package/dist/src/cli/cli-role-command.js +420 -0
  84. package/dist/src/cli/cli-start-summary.js +160 -0
  85. package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
  86. package/dist/src/cli/completion.js +149 -22
  87. package/dist/src/cli/config-commands.js +41 -18
  88. package/dist/src/cli/follow-view.js +75 -0
  89. package/dist/src/cli/help.js +189 -73
  90. package/dist/src/cli/log-commands.js +148 -82
  91. package/dist/src/cli/question-commands.js +205 -10
  92. package/dist/src/cli.js +106 -43
  93. package/dist/src/collections.js +26 -10
  94. package/dist/src/concurrency/check-permit.js +20 -3
  95. package/dist/src/concurrency/lock.js +17 -13
  96. package/dist/src/concurrency/provider-lease.js +44 -8
  97. package/dist/src/concurrency/semaphore.js +102 -26
  98. package/dist/src/config/config-aliases.js +0 -1
  99. package/dist/src/config/config-editable-keys.js +13 -1
  100. package/dist/src/config/config-fallbacks.js +93 -56
  101. package/dist/src/config/config-field-checks.js +40 -10
  102. package/dist/src/config/config-keys.js +30 -8
  103. package/dist/src/config/config-live.js +63 -24
  104. package/dist/src/config/config-request.js +137 -0
  105. package/dist/src/config/config-schema.js +31 -24
  106. package/dist/src/config/config-selector-checks.js +123 -0
  107. package/dist/src/config/config-validation-agents.js +80 -0
  108. package/dist/src/config/config-validation-model.js +116 -0
  109. package/dist/src/config/config-validation.js +141 -199
  110. package/dist/src/config/config-views.js +127 -53
  111. package/dist/src/config/config-write-core.js +135 -0
  112. package/dist/src/config/config-write.js +131 -264
  113. package/dist/src/config/config.js +48 -38
  114. package/dist/src/config/model-selector.js +34 -34
  115. package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
  116. package/dist/src/doctor/doctor-backlog-plans.js +263 -0
  117. package/dist/src/doctor/doctor-backlog.js +100 -496
  118. package/dist/src/doctor/doctor-check-names.js +81 -0
  119. package/dist/src/doctor/doctor-checks.js +52 -579
  120. package/dist/src/doctor/doctor-claude-checks.js +145 -0
  121. package/dist/src/doctor/doctor-codex-checks.js +279 -0
  122. package/dist/src/doctor/doctor-contention-checks.js +380 -0
  123. package/dist/src/doctor/doctor-holds.js +82 -66
  124. package/dist/src/doctor/doctor-install.js +2 -1
  125. package/dist/src/doctor/doctor-model-checks.js +236 -402
  126. package/dist/src/doctor/doctor-notify.js +3 -4
  127. package/dist/src/doctor/doctor-opencode-checks.js +162 -0
  128. package/dist/src/doctor/doctor-orphans.js +182 -63
  129. package/dist/src/doctor/doctor-project-checks.js +303 -0
  130. package/dist/src/doctor/doctor.js +121 -77
  131. package/dist/src/doctor/image-probe.js +21 -8
  132. package/dist/src/doctor/outcome.js +3 -2
  133. package/dist/src/doctor/probe.js +7 -11
  134. package/dist/src/events/event-format.js +181 -86
  135. package/dist/src/events/event-labels.js +12 -5
  136. package/dist/src/events/event-legacy.js +39 -15
  137. package/dist/src/events/event-read.js +39 -39
  138. package/dist/src/events/event-tally.js +16 -0
  139. package/dist/src/events/event-window.js +60 -24
  140. package/dist/src/events/events.js +30 -13
  141. package/dist/src/events/notify.js +7 -7
  142. package/dist/src/failure/failure-cluster.js +12 -12
  143. package/dist/src/failure/failure-data.js +56 -56
  144. package/dist/src/failure/failure-render.js +31 -23
  145. package/dist/src/failure/failure-state-change.js +17 -12
  146. package/dist/src/failure/time-spend.js +99 -35
  147. package/dist/src/files/files.js +111 -35
  148. package/dist/src/files/json-files.js +3 -3
  149. package/dist/src/files/json-object.js +28 -7
  150. package/dist/src/files/stat-cache.js +2 -2
  151. package/dist/src/files/tail.js +1 -1
  152. package/dist/src/gates/bootstrap-gates.js +4 -5
  153. package/dist/src/gates/budget-gates.js +177 -84
  154. package/dist/src/gates/disk-gate.js +1 -1
  155. package/dist/src/gates/gate-polls.js +108 -58
  156. package/dist/src/gates/maintenance-quota.js +10 -13
  157. package/dist/src/gates/pause-gates.js +28 -10
  158. package/dist/src/gates/readiness.js +7 -3
  159. package/dist/src/gates/role-cap-gates.js +8 -8
  160. package/dist/src/gates/startup-gate.js +94 -32
  161. package/dist/src/gates/streak-gate.js +54 -30
  162. package/dist/src/git/commit-message.js +77 -46
  163. package/dist/src/git/git-diff.js +16 -10
  164. package/dist/src/git/git-run.js +79 -38
  165. package/dist/src/git/git.js +36 -34
  166. package/dist/src/git/slot-salvage.js +253 -0
  167. package/dist/src/git/slots-state.js +6 -6
  168. package/dist/src/git/worktree-pool.js +132 -38
  169. package/dist/src/git/worktree-use.js +4 -11
  170. package/dist/src/git/worktree.js +94 -37
  171. package/dist/src/gui/gui-admin-endpoints.js +96 -0
  172. package/dist/src/gui/gui-args.js +79 -8
  173. package/dist/src/gui/gui-backlog-commands.js +42 -18
  174. package/dist/src/gui/gui-backlog-endpoints.js +155 -0
  175. package/dist/src/gui/gui-command.js +8 -13
  176. package/dist/src/gui/gui-config-commands.js +94 -72
  177. package/dist/src/gui/gui-endpoint-commands.js +4 -3
  178. package/dist/src/gui/gui-endpoint-common.js +4 -4
  179. package/dist/src/gui/gui-endpoints.js +11 -380
  180. package/dist/src/gui/gui-history-endpoints.js +301 -0
  181. package/dist/src/gui/gui-operator-commands.js +108 -13
  182. package/dist/src/gui/gui-prompt-commands.js +11 -14
  183. package/dist/src/gui/gui-report-endpoints.js +90 -0
  184. package/dist/src/gui/gui-server.js +11 -4
  185. package/dist/src/gui/gui-team-commands.js +7 -7
  186. package/dist/src/gui/http-body.js +1 -1
  187. package/dist/src/history/history-data.js +122 -234
  188. package/dist/src/history/history-queued.js +147 -0
  189. package/dist/src/history/history-render.js +42 -22
  190. package/dist/src/history/history.js +193 -49
  191. package/dist/src/inbox/inbox-attachments.js +29 -30
  192. package/dist/src/inbox/inbox-cancel.js +10 -11
  193. package/dist/src/inbox/inbox-edit.js +9 -9
  194. package/dist/src/inbox/inbox-submit.js +18 -18
  195. package/dist/src/inbox/inbox-top.js +25 -9
  196. package/dist/src/inbox/inbox.js +42 -43
  197. package/dist/src/inbox/pending-prompt.js +26 -26
  198. package/dist/src/inbox/prompt-commands.js +62 -49
  199. package/dist/src/inbox/prompt-not-before.js +2 -2
  200. package/dist/src/init/init-templates.js +1 -2
  201. package/dist/src/init/init.js +28 -23
  202. package/dist/src/merge/backlog-conflicts.js +215 -35
  203. package/dist/src/merge/merge-batch.js +14 -8
  204. package/dist/src/merge/merge-cancel.js +53 -0
  205. package/dist/src/merge/merge-check-failures.js +44 -22
  206. package/dist/src/merge/merge-core.js +81 -32
  207. package/dist/src/merge/merge-diff.js +5 -4
  208. package/dist/src/merge/merge-drain.js +150 -11
  209. package/dist/src/merge/merge-git.js +177 -38
  210. package/dist/src/merge/merge-pipeline.js +15 -3
  211. package/dist/src/merge/merge-post-review.js +90 -0
  212. package/dist/src/merge/merge-queue-render.js +49 -11
  213. package/dist/src/merge/merge-queue.js +31 -15
  214. package/dist/src/merge/merge-requeue.js +102 -0
  215. package/dist/src/merge/merge-slot.js +61 -16
  216. package/dist/src/merge/merge-stack.js +33 -11
  217. package/dist/src/merge/merge-to-main.js +86 -27
  218. package/dist/src/merge/merge-top.js +69 -0
  219. package/dist/src/merge/merge-verify.js +12 -10
  220. package/dist/src/notes-cli.js +30 -15
  221. package/dist/src/operator/operator-commands.js +192 -81
  222. package/dist/src/operator/operator-intent.js +69 -42
  223. package/dist/src/operator/operator-requests.js +35 -40
  224. package/dist/src/operator/retire.js +5 -6
  225. package/dist/src/operator/revert.js +142 -34
  226. package/dist/src/orchestrator/orchestrator-launch.js +60 -52
  227. package/dist/src/orchestrator/orchestrator-poll.js +320 -0
  228. package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
  229. package/dist/src/orchestrator/orchestrator.js +128 -369
  230. package/dist/src/orchestrator/retention.js +42 -8
  231. package/dist/src/orchestrator/scheduling-admit.js +116 -0
  232. package/dist/src/orchestrator/scheduling-scope.js +201 -0
  233. package/dist/src/orchestrator/scheduling-skip.js +185 -0
  234. package/dist/src/orchestrator/startup-migration-steps.js +8 -7
  235. package/dist/src/orchestrator/startup-migrations.js +11 -7
  236. package/dist/src/paths.js +116 -49
  237. package/dist/src/pi/command-shape.js +12 -1
  238. package/dist/src/pi/pi-args.js +6 -4
  239. package/dist/src/pi/pi-backend.js +6 -6
  240. package/dist/src/pi/pi-bin.js +54 -63
  241. package/dist/src/pi/pi-listed-models.js +53 -0
  242. package/dist/src/pi/pi-models.js +63 -30
  243. package/dist/src/pi/pi-run-result.js +1 -1
  244. package/dist/src/pi/pi-settings.js +1 -1
  245. package/dist/src/pi/pi-stream.js +6 -6
  246. package/dist/src/pi/pi-watchdogs.js +18 -19
  247. package/dist/src/pi-extension/bounded-output.js +5 -3
  248. package/dist/src/pi-extension/context-budget.js +2 -2
  249. package/dist/src/pi-extension/context-shake.js +1 -1
  250. package/dist/src/pi-extension/context-window.js +0 -1
  251. package/dist/src/pi-extension/full-output.js +3 -10
  252. package/dist/src/pi-extension/strip-thinking.js +0 -1
  253. package/dist/src/pi-extension/trim-system-prompt.js +3 -4
  254. package/dist/src/pi-extension/write-guard.js +37 -0
  255. package/dist/src/process/launch-services.js +1 -2
  256. package/dist/src/process/node-bin.js +16 -0
  257. package/dist/src/process/process-group.js +8 -18
  258. package/dist/src/process/process.js +41 -2
  259. package/dist/src/process/run-marker.js +18 -6
  260. package/dist/src/process/supervisor.js +22 -21
  261. package/dist/src/prompt/dialect.js +17 -2
  262. package/dist/src/prompt/gate-notes.js +203 -0
  263. package/dist/src/prompt/gate-prompts.js +121 -211
  264. package/dist/src/prompt/notes-backlog.js +181 -0
  265. package/dist/src/prompt/principles.js +1 -2
  266. package/dist/src/prompt/prompt-followup.js +19 -14
  267. package/dist/src/prompt/prompt.js +129 -204
  268. package/dist/src/redeploy/redeploy-policy.js +24 -19
  269. package/dist/src/redeploy/redeploy-probes.js +1 -1
  270. package/dist/src/redeploy/redeploy.js +2 -3
  271. package/dist/src/redeploy/redeployer.js +20 -20
  272. package/dist/src/redeploy/self-reload.js +2 -1
  273. package/dist/src/report/report-data.js +161 -77
  274. package/dist/src/report/report-fold.js +129 -52
  275. package/dist/src/report/report-main-red.js +55 -0
  276. package/dist/src/report/report-render.js +133 -64
  277. package/dist/src/report/report-types.js +1 -0
  278. package/dist/src/report/report.js +26 -9
  279. package/dist/src/request-timeouts.js +2 -2
  280. package/dist/src/review/known-flakes.js +100 -1
  281. package/dist/src/review/post-merge-review.js +106 -0
  282. package/dist/src/review/protected-edits.js +4 -5
  283. package/dist/src/review/review-followup.js +8 -8
  284. package/dist/src/review/review-precheck.js +66 -23
  285. package/dist/src/review/review-run.js +395 -0
  286. package/dist/src/review/review-verdict.js +2 -2
  287. package/dist/src/review/review.js +155 -360
  288. package/dist/src/review/secret-leaks.js +36 -16
  289. package/dist/src/review/suite-rerun.js +0 -1
  290. package/dist/src/roles/legacy-role-migration.js +80 -7
  291. package/dist/src/roles/role-catalog.js +69 -12
  292. package/dist/src/roles/role-guidance.js +55 -20
  293. package/dist/src/roles/role-labels.js +1 -2
  294. package/dist/src/roles/role-render.js +67 -50
  295. package/dist/src/roles/role-view.js +59 -47
  296. package/dist/src/roles/roles.js +31 -31
  297. package/dist/src/roles/runner-ids.js +97 -0
  298. package/dist/src/run/acceptance-greps.js +119 -0
  299. package/dist/src/run/feedback-filings.js +51 -0
  300. package/dist/src/{tick → run}/qa-coverage.js +9 -27
  301. package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
  302. package/dist/src/run/run-detail-data.js +179 -0
  303. package/dist/src/run/run-detail-render.js +98 -0
  304. package/dist/src/run/run-detail.js +168 -0
  305. package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -60
  306. package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
  307. package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +108 -73
  308. package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
  309. package/dist/src/{tick/tick-stage.js → run/run-stage.js} +108 -50
  310. package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
  311. package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
  312. package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +91 -56
  313. package/dist/src/run/selfcheck-digest.js +40 -0
  314. package/dist/src/run/stage-backlog-checks.js +249 -0
  315. package/dist/src/run/stage-check.js +172 -0
  316. package/dist/src/run/stage-path-checks.js +730 -0
  317. package/dist/src/{loop → runner}/leftover.js +80 -25
  318. package/dist/src/{loop → runner}/model-fallback.js +12 -12
  319. package/dist/src/runner/revision.js +202 -0
  320. package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
  321. package/dist/src/runner/runner-outcome.js +107 -0
  322. package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
  323. package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +21 -15
  324. package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
  325. package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
  326. package/dist/src/runner/runner-state.js +102 -0
  327. package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
  328. package/dist/src/scheduling/backoff.js +38 -38
  329. package/dist/src/scheduling/claims.js +35 -22
  330. package/dist/src/scheduling/once-round.js +22 -22
  331. package/dist/src/scheduling/quiet-hours.js +5 -6
  332. package/dist/src/scheduling/scheduling.js +74 -64
  333. package/dist/src/scheduling/work-merged-cache.js +2 -2
  334. package/dist/src/status/status-budget.js +55 -47
  335. package/dist/src/status/status-data.js +43 -16
  336. package/dist/src/status/status-inbox.js +2 -2
  337. package/dist/src/status/status-install.js +0 -1
  338. package/dist/src/status/status-polls.js +28 -28
  339. package/dist/src/status/status-roles.js +39 -13
  340. package/dist/src/team/error-storm.js +8 -8
  341. package/dist/src/team/failure-spread.js +2 -2
  342. package/dist/src/team/orchestrator-info.js +15 -9
  343. package/dist/src/team/reclaim.js +5 -6
  344. package/dist/src/team/team-hold.js +7 -7
  345. package/dist/src/team/team-polls.js +91 -50
  346. package/dist/src/team/team-state.js +8 -2
  347. package/dist/src/text/datetime.js +63 -17
  348. package/dist/src/text/format.js +48 -11
  349. package/dist/src/text/markdown.js +8 -5
  350. package/dist/src/text/phrases.js +57 -23
  351. package/dist/src/text/suggest.js +1 -1
  352. package/dist/src/text/text.js +67 -13
  353. package/dist/src/ui/badges.js +65 -37
  354. package/dist/src/ui/gui/gui-client-backlog.js +292 -0
  355. package/dist/src/ui/gui/gui-client-boot.js +32 -26
  356. package/dist/src/ui/gui/gui-client-composer.js +8 -9
  357. package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
  358. package/dist/src/ui/gui/gui-client-drawer.js +126 -285
  359. package/dist/src/ui/gui/gui-client-feed.js +271 -0
  360. package/dist/src/ui/gui/gui-client-history.js +434 -67
  361. package/dist/src/ui/gui/gui-client-labels.js +1 -2
  362. package/dist/src/ui/gui/gui-client-markdown.js +1 -2
  363. package/dist/src/ui/gui/gui-client-model.js +27 -36
  364. package/dist/src/ui/gui/gui-client-operator.js +55 -51
  365. package/dist/src/ui/gui/gui-client-pending.js +227 -23
  366. package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
  367. package/dist/src/ui/gui/gui-client-report.js +87 -427
  368. package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
  369. package/dist/src/ui/gui/gui-client-settings.js +56 -4
  370. package/dist/src/ui/gui/gui-client-team.js +25 -465
  371. package/dist/src/ui/gui/gui-client.js +27 -25
  372. package/dist/src/ui/gui/gui-icons.js +0 -2
  373. package/dist/src/ui/gui/gui-page.js +9 -7
  374. package/dist/src/ui/gui/gui-styles.js +34 -34
  375. package/dist/src/ui/progress-data.js +9 -11
  376. package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
  377. package/dist/src/ui/status-model.js +133 -125
  378. package/dist/src/ui/status-payload.js +136 -49
  379. package/dist/src/ui/status-render.js +101 -82
  380. package/dist/src/ui/team-alerts.js +248 -57
  381. package/dist/src/ui/tone.js +5 -6
  382. package/dist/src/ui/transcript-run.js +58 -0
  383. package/dist/src/ui/transcript-tail.js +28 -20
  384. package/dist/src/ui/transcript.js +63 -23
  385. package/dist/src/ui/tui/tui-app.js +0 -1
  386. package/dist/src/ui/tui/tui-backlog.js +51 -14
  387. package/dist/src/ui/tui/tui-editor-answer.js +27 -31
  388. package/dist/src/ui/tui/tui-editor-attach.js +3 -5
  389. package/dist/src/ui/tui/tui-editor-backends.js +132 -0
  390. package/dist/src/ui/tui/tui-editor-brief.js +10 -12
  391. package/dist/src/ui/tui/tui-editor-budget.js +35 -31
  392. package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
  393. package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
  394. package/dist/src/ui/tui/tui-editor-config.js +86 -0
  395. package/dist/src/ui/tui/tui-editor-entry.js +36 -47
  396. package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
  397. package/dist/src/ui/tui/tui-editor-instances.js +37 -0
  398. package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
  399. package/dist/src/ui/tui/tui-editor-interval.js +11 -9
  400. package/dist/src/ui/tui/tui-editor-model.js +29 -0
  401. package/dist/src/ui/tui/tui-editor-notes.js +3 -5
  402. package/dist/src/ui/tui/tui-editor-notify.js +25 -0
  403. package/dist/src/ui/tui/tui-editor-pause.js +48 -59
  404. package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
  405. package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
  406. package/dist/src/ui/tui/tui-editor-queued.js +5 -9
  407. package/dist/src/ui/tui/tui-editor-quiet.js +99 -35
  408. package/dist/src/ui/tui/tui-editor-retire.js +4 -6
  409. package/dist/src/ui/tui/tui-editor-role-key.js +76 -0
  410. package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
  411. package/dist/src/ui/tui/tui-editor-search.js +45 -33
  412. package/dist/src/ui/tui/tui-editor-session.js +60 -34
  413. package/dist/src/ui/tui/tui-editor-slots.js +23 -0
  414. package/dist/src/ui/tui/tui-editors.js +35 -2
  415. package/dist/src/ui/tui/tui-frame.js +56 -11
  416. package/dist/src/ui/tui/tui-history.js +8 -9
  417. package/dist/src/ui/tui/tui-input.js +13 -11
  418. package/dist/src/ui/tui/tui-keymap.js +0 -1
  419. package/dist/src/ui/tui/tui-keys.js +24 -9
  420. package/dist/src/ui/tui/tui-pane-activity.js +14 -11
  421. package/dist/src/ui/tui/tui-pane-backlog.js +171 -126
  422. package/dist/src/ui/tui/tui-pane-brief.js +0 -1
  423. package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
  424. package/dist/src/ui/tui/tui-pane-health.js +58 -8
  425. package/dist/src/ui/tui/tui-pane-history.js +402 -82
  426. package/dist/src/ui/tui/tui-pane-pending.js +308 -13
  427. package/dist/src/ui/tui/tui-pane-queued.js +71 -55
  428. package/dist/src/ui/tui/tui-pane-report.js +46 -14
  429. package/dist/src/ui/tui/tui-pane-session.js +25 -6
  430. package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
  431. package/dist/src/ui/tui/tui-pane.js +80 -23
  432. package/dist/src/ui/tui/tui-panes.js +100 -30
  433. package/dist/src/ui/tui/tui.js +14 -14
  434. package/dist/src/verdict/fix-claim.js +82 -32
  435. package/dist/src/verdict/no-change.js +4 -4
  436. package/dist/src/verdict/refusal.js +40 -16
  437. package/dist/src/verdict/reply-contract.js +42 -31
  438. package/dist/src/version.js +0 -1
  439. package/package.json +2 -1
  440. package/dist/src/loop/revision.js +0 -70
  441. package/dist/src/roles/loop-ids.js +0 -77
  442. package/dist/src/tick/stage-check.js +0 -419
  443. package/dist/src/tick/telemetry-digest.js +0 -25
  444. package/dist/src/tick/tick-detail-data.js +0 -108
  445. package/dist/src/tick/tick-detail.js +0 -163
  446. package/dist/src/ui/gui/gui-client-sound.js +0 -53
@@ -1,8 +1,8 @@
1
1
  import { fail } from "./cli-output.js";
2
- import { BRANCH_VALUE_ERROR, ROLE_VALUE_ERROR } from "./cli-flag-specs.js";
2
+ import { BRANCH_VALUE_ERROR, ROLE_VALUE_ERROR, TOKEN_VALUE_ERROR } from "./cli-flag-specs.js";
3
3
  import { knownRoleIdsCached } from "../config/config.js";
4
4
  import { allRoleIds, unknownRoleMessage } from "../roles/roles.js";
5
- import { gotSuffix, parsePositiveInt } from "../text/text.js";
5
+ import { gotSuffix, parsePositiveInt, splitCommaList } from "../text/text.js";
6
6
  import { canonicalRoleId } from "../roles/legacy-role-ids.js";
7
7
  /** CLI argument parsing and validation, shared by every command in cli.ts. The execution
8
8
  * layer calls these before running a command, so a bad flag fails fast with an actionable
@@ -29,17 +29,68 @@ export function flagValue(args, flag) {
29
29
  const i = args.indexOf(flag);
30
30
  return i < 0 ? null : args[i + 1];
31
31
  }
32
+ /** The one validation of a `--token <secret>` value, shared by `tumwater gui` (cmdGui) and
33
+ * `tumwater start --gui` (cmdStart) so the value checks and their wording cannot drift
34
+ * between the two callers. Returns null when the token is fine (or absent), the error text
35
+ * the caller `fail()`s otherwise: TOKEN_VALUE_ERROR for a valueless or empty `--token`, and a
36
+ * flag-looking-value message when the value starts with `--` (a valued flag claims the next
37
+ * token even when it is a known flag, so `--token --all-interfaces` would otherwise serve with
38
+ * the literal secret "--all-interfaces"). `example` names the command form the operator
39
+ * typed (e.g. "tumwater gui" or "tumwater start --gui") in the copyable fix, so the
40
+ * message names whichever command the secret was meant for. */
41
+ export function tokenValueProblem(args, example) {
42
+ const raw = flagValue(args, "--token");
43
+ if (raw === null)
44
+ return null;
45
+ if (raw === undefined || raw === "")
46
+ return TOKEN_VALUE_ERROR;
47
+ if (raw.startsWith("--"))
48
+ return `--token got the flag-looking value "${raw}" instead of a secret — write the secret as its own argument (e.g. \`${example} --token s3cret --all-interfaces\`)`;
49
+ return null;
50
+ }
32
51
  /** The "each flag at most once" rule at a flag fold: fail the occurrence after the first with
33
52
  * the shared wording (`<flag> may only be given once`), `seen` being the caller's accumulator
34
53
  * for that flag. One home for the wording the spec-driven gate (cli-flag-specs.ts), the
35
54
  * free-form parsers' pre-scan (cli-command-args.ts), and the bespoke command shells
36
- * (backlog-cli.ts, cli-query-commands.ts) all apply, so a repeat cannot be reported as a
37
- * different error on one surface. Called per occurrence rather than pre-scanned at every site,
55
+ * (backlog-cli.ts, backlog-cli-view.ts, cli-query-commands.ts) all apply, so a repeat cannot be
56
+ * reported as a different error on one surface. Called per occurrence rather than pre-scanned
57
+ * at every site,
38
58
  * so a malformed invocation still reports whichever error its token order reaches first. */
39
59
  export function rejectRepeatFlag(seen, flag) {
40
60
  if (seen)
41
61
  fail(`${flag} may only be given once`);
42
62
  }
63
+ /** Refuse a `--`-token in a valued flag's position — `--result --last` must not treat `--last`
64
+ * as its value. Both `history` forms used to swallow the following `--` token in the value
65
+ * slot: the trail's `--result`/`--model` then failed downstream with a misleading "--result
66
+ * needs --last" wording — the operator DID write `--last` — and the listing's `--model`
67
+ * silently treated `--last` as a model filter and matched no rows. Returns the value
68
+ * unchanged when it is not a `--` token; only a `--` token reads as a flag, so a single-dash
69
+ * token and the intentional-text filters (grep, type) are not refused. `flag` names the
70
+ * valued flag the way its missing-value error names the command (e.g. `history --model`). */
71
+ export function rejectFlagLookingValue(flag, value) {
72
+ if (typeof value === "string" && value.startsWith("--"))
73
+ fail(`${flag} needs a value (the next token ${JSON.stringify(value)} is a flag, not a value)`);
74
+ return value;
75
+ }
76
+ /** The shared body of the `parse*Flag` helpers (grep, type, result, model): the flag's
77
+ * value (null when absent) alongside `rest`, the args with the value token removed, failing
78
+ * with `missingValueError` when the flag is valueless or its value is empty.
79
+ * `guardFlagValue` opts the flag into rejectFlagLookingValue, the same refusal the history
80
+ * listing (cmdHistory) applies to its own `--result`/`--model` and `role <id>`'s write flags
81
+ * and `config set` make. The value-scored filters (grep, type) deliberately keep a
82
+ * flag-shaped token as filter text and so stay off this guard. */
83
+ function takeValuedFlag(args, flag, missingValueError, guardFlagValue = false) {
84
+ const i = args.indexOf(flag);
85
+ const rest = i >= 0 ? args.filter((_, j) => j !== i + 1) : args;
86
+ const raw = flagValue(args, flag);
87
+ if (raw === null)
88
+ return { rest, value: null };
89
+ const checked = guardFlagValue ? rejectFlagLookingValue(flag, raw) : raw;
90
+ if (checked === undefined || checked === "")
91
+ fail(missingValueError);
92
+ return { rest, value: checked };
93
+ }
43
94
  /** Parse an optional `--grep <text>` filter flag for the filtering views (logs, history): the
44
95
  * substring pattern, or null when absent, returned alongside `rest` — the args with the
45
96
  * flag's value token removed. The value token leaves the list because a flag-shaped token
@@ -51,14 +102,8 @@ export function rejectRepeatFlag(seen, flag) {
51
102
  * case. Lives beside flagValue, whose indexOf/value pairing it builds on, so the views'
52
103
  * scans cannot drift apart. */
53
104
  export function parseGrepFlag(args, missingValueError) {
54
- const i = args.indexOf("--grep");
55
- const rest = i >= 0 ? args.filter((_, j) => j !== i + 1) : args;
56
- const raw = flagValue(args, "--grep");
57
- if (raw === null)
58
- return { rest, pattern: null };
59
- if (raw === undefined || raw === "")
60
- fail(missingValueError);
61
- return { rest, pattern: raw };
105
+ const { rest, value } = takeValuedFlag(args, "--grep", missingValueError);
106
+ return { rest, pattern: value };
62
107
  }
63
108
  /** Parse an optional `--type <eventType>` exact-type filter flag for the event feed view
64
109
  * (logs): the exact type id, or null when absent, returned alongside `rest` — the args with
@@ -69,14 +114,24 @@ export function parseGrepFlag(args, missingValueError) {
69
114
  * caller's wording (each view names its own command) — the same error the `--type` gate spec
70
115
  * (typeFlagSpec) reports earlier for the trailing-no-value case. */
71
116
  export function parseTypeFlag(args, missingValueError) {
72
- const i = args.indexOf("--type");
73
- const rest = i >= 0 ? args.filter((_, j) => j !== i + 1) : args;
74
- const raw = flagValue(args, "--type");
75
- if (raw === null)
76
- return { rest, type: null };
77
- if (raw === undefined || raw === "")
78
- fail(missingValueError);
79
- return { rest, type: raw };
117
+ const { rest, value } = takeValuedFlag(args, "--type", missingValueError);
118
+ return { rest, type: value };
119
+ }
120
+ /** Parse an optional `--result <class>[,...]` flag for the history trail form: the raw value
121
+ * (null when absent) alongside `rest`, the args with the value token removed so a class name
122
+ * cannot be read as a positional. Validation of the classes belongs to the caller
123
+ * (parseHistoryResultList); a valueless or empty value fails with `missingValueError`. */
124
+ export function parseResultFlag(args, missingValueError) {
125
+ const { rest, value } = takeValuedFlag(args, "--result", missingValueError, true);
126
+ return { rest, raw: value };
127
+ }
128
+ /** Parse an optional `--model <selector>[,...]` flag for the history trail form: the raw value
129
+ * (null when absent) alongside `rest`, the args with the value token removed so a selector
130
+ * cannot be read as a positional. Validation belongs to the caller (parseHistoryModelList); a
131
+ * valueless or empty value fails with `missingValueError`. */
132
+ export function parseModelFlag(args, missingValueError) {
133
+ const { rest, value } = takeValuedFlag(args, "--model", missingValueError, true);
134
+ return { rest, raw: value };
80
135
  }
81
136
  /** Parse a `-n`-style count flag value: a positive integer, or fail with a clear message.
82
137
  * Unvalidated, NaN/0/negative limits make readEvents' `slice(-limit)` dump the whole log
@@ -111,18 +166,47 @@ export function parsePositionFlag(flag, raw, example) {
111
166
  return n;
112
167
  }
113
168
  /** Resolve a read-only command's `--role <id>` scope: the role id, or null when the flag is
114
- * absent. The id is validated against built-ins PLUS user-defined loops, read through
169
+ * absent. The id is validated against built-ins PLUS user-defined roles, read through
115
170
  * loadConfigCached (which never throws) so a transiently broken tumwater.json cannot take a
116
171
  * read-only view down — a broken file falls back to the built-in catalog rather than refusing
117
172
  * every id. Without --role no config is read. (State-changing commands instead resolve --role
118
173
  * against loadConfig and fail loudly on a broken file, as operator/operator-commands.ts and
119
174
  * prompt-commands.ts do.) The id
120
175
  * set comes from config.knownRoleIdsCached, the one home of the cached-with-built-in-fallback
121
- * rule. Shared by the tail views that scope their output to one loop (cmdLogs, cmdHistory). */
122
- export function parseRoleScope(root, args) {
123
- if (!args.includes("--role"))
176
+ * rule. Shared by the tail views that scope their output to one role (cmdLogs, cmdHistory). */
177
+ export function parseRoleScope(root, args, flag = "--role", missingValue = ROLE_VALUE_ERROR) {
178
+ if (!args.includes(flag))
124
179
  return null;
125
- return parseRoleFlag(args, knownRoleIdsCached(root));
180
+ return parseRoleFlag(args, knownRoleIdsCached(root), flag, missingValue);
181
+ }
182
+ /** Resolve `history --role <id>[,<id>...]`: the listed role ids (canonical, deduplicated,
183
+ * first-seen order), or null when the flag is absent (no config read then, as parseRoleScope).
184
+ * Each piece is validated like parseRoleScope's id; empty pieces are dropped, and a value with
185
+ * no piece left fails with ROLE_VALUE_ERROR. */
186
+ export function parseRoleListScope(root, args) {
187
+ return args.includes("--role") ? parseRoleListFlag(args, knownRoleIdsCached(root)) : null;
188
+ }
189
+ /** Parse `--role <id>[,<id>...]`: the listed role ids (canonical, deduplicated, first-seen
190
+ * order), or null when the flag is absent. Empty pieces are dropped, and a value with no piece
191
+ * left fails with ROLE_VALUE_ERROR. `validIds` defaults to the built-in catalog, as
192
+ * parseRoleFlag. */
193
+ export function parseRoleListFlag(args, validIds) {
194
+ const typed = flagValue(args, "--role");
195
+ if (typed === null)
196
+ return null;
197
+ const pieces = splitCommaList(typed ?? "");
198
+ if (pieces.length === 0)
199
+ fail(ROLE_VALUE_ERROR);
200
+ const ids = validIds ?? allRoleIds();
201
+ const out = [];
202
+ for (const piece of pieces) {
203
+ const role = canonicalRoleId(piece);
204
+ if (!ids.includes(role))
205
+ fail(unknownRoleMessage(role, ids));
206
+ if (!out.includes(role))
207
+ out.push(role);
208
+ }
209
+ return out;
126
210
  }
127
211
  /** Parse the `--port` flag value: an integer in 1..65535, or fail with a clear message.
128
212
  * Port 0 would make Node pick an ephemeral port while the CLI prints :0 — a URL that
@@ -241,9 +325,10 @@ export function failRivalShapes(subject, rival, why) {
241
325
  * "logs --since …" instead of the malformed and missing-value forms naming a bare "--since".
242
326
  * Rival-flag rules stay in each command body, checked on the returned non-null value — so a
243
327
  * malformed or over-cap `--since` fails on its own wording before a rival-flag check fires,
244
- * the same precedence a command with only --since shows. */
245
- export function parseSinceFlag(args, label, maxMs) {
246
- const raw = flagValue(args, "--since");
328
+ * the same precedence a command with only --since shows. `flag` defaults to `--since`; logs,
329
+ * history and report read their `--until` bound through the same idiom. */
330
+ export function parseSinceFlag(args, label, maxMs, flag = "--since") {
331
+ const raw = flagValue(args, flag);
247
332
  if (raw === null)
248
333
  return null;
249
334
  const ms = parseDurationFlag(label, raw);
@@ -251,17 +336,17 @@ export function parseSinceFlag(args, label, maxMs) {
251
336
  return ms;
252
337
  }
253
338
  /** Parse an optional `--role <id>` flag: the validated role id, or null when absent.
254
- * Shared by every command that scopes to one loop so their validation and error messages
339
+ * Shared by every command that scopes to one role so their validation and error messages
255
340
  * cannot drift. `validIds` is the set of ids this command accepts — callers pass
256
- * knownRoleIds(config) so user-defined loops are accepted like built-ins; it defaults to the
341
+ * knownRoleIds(config) so user-defined roles are accepted like built-ins; it defaults to the
257
342
  * catalog alone, which keeps in-process callers (and tests) that have no config working.
258
343
  */
259
- export function parseRoleFlag(args, validIds) {
260
- const typed = flagValue(args, "--role");
344
+ export function parseRoleFlag(args, validIds, flag = "--role", missingValue = ROLE_VALUE_ERROR) {
345
+ const typed = flagValue(args, flag);
261
346
  if (typed === null)
262
347
  return null;
263
348
  if (!typed)
264
- fail(ROLE_VALUE_ERROR);
349
+ fail(missingValue);
265
350
  const role = canonicalRoleId(typed);
266
351
  const ids = validIds ?? allRoleIds();
267
352
  if (!ids.includes(role))
@@ -1,9 +1,8 @@
1
- // vocabulary: plain
2
1
  /** The free-form-prompt commands' bespoke argument parsers: `tumwater init` and
3
2
  * `tumwater prompt`, whose positionals are prompt TEXT rather than a token list. Every
4
3
  * shared helper in cli/cli-args.ts assumes flags claim their tokens and rejects whatever is
5
4
  * left over — exactly wrong here, where a misspelled flag must fail instead of being
6
- * silently baked into the prompt that every loop then ticks from. Both parsers therefore
5
+ * silently baked into the prompt that every role then runs from. Both parsers therefore
7
6
  * hand-roll the same discipline (a double-dash token must be a known flag, given at most
8
7
  * once; single-dash tokens are content) and share failStrayArg, so they live together
9
8
  * apart from cli/cli-args.ts's generic machinery — which also keeps that module, minus these
@@ -13,14 +12,16 @@ import { failOverDurationCap, parseBranchFlag, parseDurationFlag, parsePositionF
13
12
  import { PAUSE_FOR_MAX_MS } from "../operator/operator-intent.js";
14
13
  import { JSON_FLAG, ROLE_FLAG, ROLE_VALUE_ERROR, rejectUnknownDoubleDash, } from "./cli-flag-specs.js";
15
14
  import { fail } from "./cli-output.js";
15
+ import { DOCTOR_CHECK_NAMES } from "../doctor/doctor-check-names.js";
16
+ import { typoSuffix } from "../text/suggest.js";
16
17
  import { templateIds, unknownTemplateError } from "../init/init-templates.js";
17
18
  import { errorMessage } from "../text/text.js";
18
19
  /** Peel a positional-first command's bare tokens off the argument list: every flag-shaped
19
20
  * token rides in rest for rejectUnknownArgs, every bare token is a positional. For commands
20
- * with no valued flags (tick: `--json` alone; bug/plan via fileAndAnnounce) the split is a
21
- * prefix test — a negative tick number (`tick bugfix -3`) arrives flag-shaped and fails the
21
+ * with no valued flags (history: `--json` alone; bug/plan via fileAndAnnounce) the split is a
22
+ * prefix test — a negative run number (`history bugfix -3`) arrives flag-shaped and fails the
22
23
  * unknown-arg gate, which is the right answer for a non-positive n anyway. Lives here with
23
- * the CLI's other argument helpers, shared by cli.ts's tick case and
24
+ * the CLI's other argument helpers, shared by cli.ts's history case and
24
25
  * backlog-cli.ts's fileAndAnnounce. */
25
26
  export function peelPositionals(args) {
26
27
  const positionals = [];
@@ -29,17 +30,34 @@ export function peelPositionals(args) {
29
30
  (arg.startsWith("-") ? rest : positionals).push(arg);
30
31
  return { positionals, rest };
31
32
  }
33
+ /** Map `tumwater doctor`'s bare tokens to check names (case-insensitive, deduplicated, in the
34
+ * order named); undefined for none, which runs every check. An unknown name fails with the
35
+ * closest check as a hint. */
36
+ export function parseDoctorChecks(positionals) {
37
+ if (positionals.length === 0)
38
+ return undefined;
39
+ const names = new Set();
40
+ for (const token of positionals) {
41
+ const name = DOCTOR_CHECK_NAMES.find((n) => n.toLowerCase() === token.toLowerCase());
42
+ if (name === undefined)
43
+ fail(`tumwater doctor: unknown check "${token}"${typoSuffix(token, DOCTOR_CHECK_NAMES)} (\`tumwater doctor\` lists every check by name)`);
44
+ else
45
+ names.add(name);
46
+ }
47
+ return [...names];
48
+ }
32
49
  /** The `history` listing flags that take a separate value token. */
33
- const HISTORY_LISTING_VALUED_FLAGS = ["-n", "--since", "--grep", "--result", "--role"];
50
+ const HISTORY_LISTING_VALUED_FLAGS = ["-n", "--since", "--until", "--grep", "--result", "--role", "--model", "--by"];
34
51
  /** True when `history`'s args are the one-run trail form (`history <role> <n>`, `history
35
- * <role> --last`): a token that is neither a flag nor the value of a listing-form valued flag.
36
- * A valued flag's value is skipped by position, so `--grep -x` stays a listing. */
52
+ * <role> --last`, bare `history --last`): `--last`, or a token that is neither a flag nor the
53
+ * value of a listing-form valued flag. A valued flag's value is skipped by position, so
54
+ * `--grep -x` stays a listing. */
37
55
  export function historyTrailForm(args) {
38
56
  for (let i = 0; i < args.length; i++) {
39
57
  const arg = args[i];
40
58
  if (HISTORY_LISTING_VALUED_FLAGS.includes(arg))
41
59
  i++;
42
- else if (!arg.startsWith("-"))
60
+ else if (!arg.startsWith("-") || arg === "--last")
43
61
  return true;
44
62
  }
45
63
  return false;
@@ -69,9 +87,10 @@ function readPromptFile(file) {
69
87
  }
70
88
  }
71
89
  /** A `--file <path>` value that must be present: the one home of the missing-value refusal
72
- * shared by the init and prompt parsers (two call sites — parseInitArgs' and parsePromptArgs'
73
- * --file branches), so the wording cannot drift between them. The flag token itself is
74
- * claimed by each parser's stray-argument accounting; this helper only owns the value. */
90
+ * shared by every `--file`-taking parser — init, prompt's edit and enqueue branches, plan/bug
91
+ * add and edit (fileAndAnnounce / editAndAnnounce), and the questions command — so the wording
92
+ * cannot drift between them. The flag token itself is claimed by each parser's stray-argument
93
+ * accounting; this helper only owns the value. */
75
94
  export function promptFileValue(file) {
76
95
  if (!file)
77
96
  fail("--file needs a path");
@@ -90,7 +109,7 @@ function readPromptFileChecked(file) {
90
109
  /** Fail when a read `--file` prompt holds no text: an empty (or whitespace-only) file reads
91
110
  * as an empty prompt, which the bare-init path would then treat as "re-seed from README.md"
92
111
  * (the operator's --file argument silently ignored on an initialized repo), and a generic
93
- * "an initial prompt is required" (which never names the file) on a fresh one; the prompt
112
+ * "a brief is required" (which never names the file) on a fresh one; the prompt
94
113
  * queue would enqueue nothing. Names the file, like every other bad --file shape. Shared by
95
114
  * the init and prompt parsers, so the message cannot drift between them. */
96
115
  function failEmptyPromptFile(file, contents) {
@@ -129,7 +148,7 @@ function rejectDuplicateFlags(args, flags) {
129
148
  * once; with `--file` present nothing but the other flags may accompany it; a `--branch
130
149
  * <name>` pair and the valueless flags are never prompt content; single-dash positionals are
131
150
  * prompt content, not flags. Without these checks a misspelled --file would be baked into the
132
- * initial prompt — injected into every tick of every loop until someone edits the project
151
+ * brief text — injected into every run of every role until someone edits the project
133
152
  * brief. */
134
153
  export function parseInitArgs(args) {
135
154
  const known = INIT_FLAG_SPECS.flatMap((s) => s.names);
@@ -226,11 +245,12 @@ const PROMPT_FLAG_SPECS = [
226
245
  { names: ["--file"], value: true, valueName: "<path>" },
227
246
  { names: ["--at"], value: true, valueName: "<duration>" },
228
247
  { names: ["--attach"], value: true, valueName: "<path>" },
248
+ { names: ["--grep"], value: true, valueName: "<text>" },
229
249
  ];
230
250
  /** `tumwater prompt` argument handling, following parseInitArgs' pattern. Like init's,
231
251
  * positionals are free-form prompt content — but a double-dash token must be a real flag
232
- * (`--role <id>`, `--list`, `--json`, `--cancel <n>`, `--edit <n>`, `--top <n>`, `--file <path>`,
233
- * `--at <duration>`), or
252
+ * (`--role <id>`, `--list`, `--json`, `--grep <text>`, `--cancel <n>`, `--edit <n>`,
253
+ * `--top <n>`, `--file <path>`, `--at <duration>`), or
234
254
  * it would be baked into the queued prompt (the same class of bug parseInitArgs fixed: today
235
255
  * `tumwater prompt --foo text` enqueues "--foo text"). Single-dash positionals remain prompt
236
256
  * content. `--list`, `--cancel`, `--edit` and `--top` are mutually exclusive and may
@@ -252,6 +272,7 @@ export function parsePromptArgs(args) {
252
272
  const topFlag = args.indexOf("--top");
253
273
  const fileFlag = args.indexOf("--file");
254
274
  const atFlag = args.indexOf("--at");
275
+ const grepFlag = args.indexOf("--grep");
255
276
  // --attach is repeatable: every occurrence claims itself and its value token, like --role's
256
277
  // single pair, so the pairs ride out of the prompt text in every mode.
257
278
  const attachFlags = args.flatMap((a, i) => (a === "--attach" ? [i] : []));
@@ -281,6 +302,13 @@ export function parsePromptArgs(args) {
281
302
  // prompt text (or beside a state change), so it is refused before either branch runs.
282
303
  if (jsonFlags.length > 0 && listFlag < 0)
283
304
  fail("--json only applies to --list");
305
+ if (grepFlag >= 0 && listFlag < 0)
306
+ fail("--grep only applies to --list");
307
+ const grepRaw = grepFlag >= 0 ? args[grepFlag + 1] : undefined;
308
+ if (grepFlag >= 0 && (!grepRaw || grepRaw.startsWith("--"))) {
309
+ fail("--grep needs text (usage: tumwater prompt --list --grep <text>)");
310
+ }
311
+ const grepClaim = grepFlag >= 0 ? [grepFlag, grepFlag + 1] : [];
284
312
  // The queue-only flags --file and --at have nothing to mean in the read-only and destructive
285
313
  // modes (--list and --cancel): --file is the file-shaped twin of free-form text (--edit
286
314
  // accepts it as its replacement text, so the editFlag test below exempts that one mode), and
@@ -317,8 +345,8 @@ export function parsePromptArgs(args) {
317
345
  failOverDurationCap("--at", atDelayMs, PAUSE_FOR_MAX_MS);
318
346
  }
319
347
  if (listFlag >= 0) {
320
- failStrayArg(args, "with --list there is no prompt text", listFlag, ...jsonFlags, ...roleClaim);
321
- return { mode: "list", role, json: jsonFlags.length > 0 };
348
+ failStrayArg(args, "with --list there is no prompt text", listFlag, ...jsonFlags, ...roleClaim, ...grepClaim);
349
+ return { mode: "list", role, json: jsonFlags.length > 0, grep: grepRaw ?? null };
322
350
  }
323
351
  if (cancelFlag >= 0) {
324
352
  const n = parsePositionFlag("--cancel", args[cancelFlag + 1], "--cancel 2");
@@ -4,6 +4,7 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { spawnSync } from "node:child_process";
6
6
  import { fail } from "./cli-output.js";
7
+ import { removeTree } from "../files/files.js";
7
8
  /** Signal number → name, for the shell's 128+n convention: a shell that does not re-raise a
8
9
  * signal-killed child (dash on Linux) exits with 128+signo, so node sees an exit status where
9
10
  * bash on macOS lets it see the signal. Keyed by number, so a later alias (SIGABRT over SIGIOT)
@@ -55,7 +56,7 @@ export function editInEditor(initial, fileName, fallback = "pass the new text or
55
56
  }
56
57
  }
57
58
  finally {
58
- fs.rmSync(dir, { recursive: true, force: true });
59
+ removeTree(dir);
59
60
  }
60
61
  // fail() exits the process, which would skip the finally above, so it runs after cleanup.
61
62
  if (failure !== undefined)