tumwater 0.1.2 → 0.2.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 (361) hide show
  1. package/README.md +74 -108
  2. package/dist/build-info.json +2 -2
  3. package/dist/src/agent/agent-args.js +24 -0
  4. package/dist/src/agent/agent-backend.js +2 -2
  5. package/dist/src/agent/backend-traits.js +60 -0
  6. package/dist/src/agent/claude/claude-account.js +61 -8
  7. package/dist/src/agent/claude/claude-args.js +12 -15
  8. package/dist/src/agent/claude/claude-backend.js +51 -41
  9. package/dist/src/agent/claude/claude-env.js +7 -3
  10. package/dist/src/agent/claude/claude-stream.js +7 -16
  11. package/dist/src/agent/image-input.js +107 -0
  12. package/dist/src/agent/notes-shim.js +41 -0
  13. package/dist/src/agent/opencode/opencode-args.js +61 -0
  14. package/dist/src/agent/opencode/opencode-backend.js +255 -0
  15. package/dist/src/agent/opencode/opencode-catalog.js +184 -0
  16. package/dist/src/agent/opencode/opencode-config.js +188 -0
  17. package/dist/src/agent/opencode/opencode-env.js +36 -0
  18. package/dist/src/agent/opencode/opencode-session-id.js +37 -0
  19. package/dist/src/agent/opencode/opencode-stream.js +278 -0
  20. package/dist/src/agent/role-notes-write.js +16 -32
  21. package/dist/src/agent/run-agent.js +95 -18
  22. package/dist/src/agent/session-ledger.js +57 -1
  23. package/dist/src/backlog/backlog-archive.js +296 -0
  24. package/dist/src/backlog/backlog-cli.js +573 -0
  25. package/dist/src/backlog/backlog-commit.js +31 -0
  26. package/dist/src/backlog/backlog-eligibility.js +357 -33
  27. package/dist/src/backlog/backlog-md.js +98 -18
  28. package/dist/src/backlog/backlog-render.js +62 -11
  29. package/dist/src/backlog/backlog-structure.js +261 -58
  30. package/dist/src/backlog/backlog-write.js +197 -319
  31. package/dist/src/backlog/backlog.js +113 -16
  32. package/dist/src/backlog/question-answer.js +339 -0
  33. package/dist/src/baseline/main-baseline.js +75 -88
  34. package/dist/src/baseline/main-red.js +38 -30
  35. package/dist/src/brief/brief-edit.js +43 -0
  36. package/dist/src/{brief.js → brief/brief.js} +66 -10
  37. package/dist/src/budget/budget.js +32 -15
  38. package/dist/src/budget/fallback-breaker.js +8 -7
  39. package/dist/src/build/build-check-detect.js +8 -7
  40. package/dist/src/build/build-check-events.js +68 -22
  41. package/dist/src/build/build-check-report.js +22 -23
  42. package/dist/src/build/build-check-scoped.js +51 -62
  43. package/dist/src/build/build-check.js +15 -14
  44. package/dist/src/build/build-info.js +2 -1
  45. package/dist/src/build/build-stage.js +23 -22
  46. package/dist/src/build/dep-install.js +22 -21
  47. package/dist/src/build/host-sleep.js +1 -1
  48. package/dist/src/change/change-data.js +25 -14
  49. package/dist/src/change/change-render.js +11 -10
  50. package/dist/src/cli/brief-command.js +58 -0
  51. package/dist/src/cli/cli-args.js +25 -5
  52. package/dist/src/cli/cli-command-args.js +46 -14
  53. package/dist/src/cli/cli-editor.js +64 -0
  54. package/dist/src/cli/cli-flag-specs.js +54 -16
  55. package/dist/src/cli/cli-marker-commands.js +13 -10
  56. package/dist/src/cli/cli-output.js +9 -0
  57. package/dist/src/cli/cli-query-commands.js +458 -49
  58. package/dist/src/cli/cli-repo-gate.js +1 -1
  59. package/dist/src/cli/cli-run.js +208 -59
  60. package/dist/src/cli/completion.js +207 -0
  61. package/dist/src/cli/config-commands.js +14 -11
  62. package/dist/src/cli/help.js +305 -110
  63. package/dist/src/cli/log-commands.js +127 -21
  64. package/dist/src/cli/notify-command.js +33 -18
  65. package/dist/src/cli/question-commands.js +29 -224
  66. package/dist/src/cli.js +121 -40
  67. package/dist/src/collections.js +66 -16
  68. package/dist/src/concurrency/check-permit.js +16 -17
  69. package/dist/src/concurrency/lock.js +6 -5
  70. package/dist/src/concurrency/provider-lease.js +69 -0
  71. package/dist/src/concurrency/semaphore.js +258 -36
  72. package/dist/src/config/config-aliases.js +106 -0
  73. package/dist/src/config/config-editable-keys.js +3 -3
  74. package/dist/src/config/config-fallbacks.js +379 -0
  75. package/dist/src/config/config-field-checks.js +19 -10
  76. package/dist/src/config/config-keys.js +160 -0
  77. package/dist/src/config/config-live.js +64 -12
  78. package/dist/src/config/config-schema.js +34 -22
  79. package/dist/src/config/config-validation.js +132 -48
  80. package/dist/src/config/config-views.js +119 -337
  81. package/dist/src/config/config-write.js +138 -177
  82. package/dist/src/config/config.js +60 -49
  83. package/dist/src/config/model-selector.js +28 -2
  84. package/dist/src/doctor/doctor-backlog.js +546 -49
  85. package/dist/src/doctor/doctor-checks.js +534 -56
  86. package/dist/src/doctor/doctor-holds.js +193 -53
  87. package/dist/src/doctor/doctor-install.js +30 -0
  88. package/dist/src/doctor/doctor-launch-services.js +2 -2
  89. package/dist/src/doctor/doctor-model-checks.js +549 -157
  90. package/dist/src/doctor/doctor-notify.js +27 -0
  91. package/dist/src/doctor/doctor-orphans.js +10 -9
  92. package/dist/src/doctor/doctor-render.js +36 -9
  93. package/dist/src/doctor/doctor.js +80 -22
  94. package/dist/src/doctor/image-probe.js +244 -0
  95. package/dist/src/doctor/probe.js +64 -0
  96. package/dist/src/events/event-format.js +226 -102
  97. package/dist/src/events/event-labels.js +116 -0
  98. package/dist/src/events/event-legacy.js +140 -0
  99. package/dist/src/events/event-read.js +58 -22
  100. package/dist/src/events/event-window.js +27 -7
  101. package/dist/src/events/events.js +18 -14
  102. package/dist/src/events/notify.js +137 -38
  103. package/dist/src/failure/failure-cluster.js +12 -9
  104. package/dist/src/failure/failure-data.js +96 -48
  105. package/dist/src/failure/failure-render.js +69 -58
  106. package/dist/src/failure/failure-state-change.js +33 -26
  107. package/dist/src/failure/time-spend.js +79 -59
  108. package/dist/src/files/file-queue.js +16 -4
  109. package/dist/src/files/files.js +18 -6
  110. package/dist/src/files/json-object.js +18 -3
  111. package/dist/src/files/tail.js +1 -1
  112. package/dist/src/gates/bootstrap-gates.js +5 -4
  113. package/dist/src/gates/budget-gates.js +250 -34
  114. package/dist/src/gates/disk-gate.js +18 -18
  115. package/dist/src/gates/gate-polls.js +117 -69
  116. package/dist/src/gates/maintenance-quota.js +29 -29
  117. package/dist/src/gates/pause-gates.js +11 -11
  118. package/dist/src/gates/readiness.js +2 -1
  119. package/dist/src/gates/role-cap-gates.js +16 -21
  120. package/dist/src/gates/startup-gate.js +75 -31
  121. package/dist/src/gates/streak-gate.js +18 -16
  122. package/dist/src/git/commit-message.js +12 -5
  123. package/dist/src/git/git-diff.js +16 -16
  124. package/dist/src/git/git-run.js +8 -8
  125. package/dist/src/git/git.js +86 -55
  126. package/dist/src/git/slots-state.js +14 -5
  127. package/dist/src/git/worktree-pool.js +25 -18
  128. package/dist/src/git/worktree-use.js +15 -14
  129. package/dist/src/git/worktree.js +18 -18
  130. package/dist/src/gui/gui-args.js +10 -14
  131. package/dist/src/gui/gui-backlog-commands.js +273 -0
  132. package/dist/src/gui/gui-command.js +1 -1
  133. package/dist/src/gui/gui-config-commands.js +440 -0
  134. package/dist/src/gui/gui-endpoint-commands.js +16 -669
  135. package/dist/src/gui/gui-endpoint-common.js +49 -0
  136. package/dist/src/gui/gui-endpoints.js +116 -56
  137. package/dist/src/gui/gui-operator-commands.js +145 -0
  138. package/dist/src/gui/gui-prompt-commands.js +234 -0
  139. package/dist/src/gui/gui-server.js +28 -8
  140. package/dist/src/gui/gui-team-commands.js +164 -0
  141. package/dist/src/gui/http-body.js +17 -1
  142. package/dist/src/history/history-data.js +194 -98
  143. package/dist/src/history/history-render.js +76 -0
  144. package/dist/src/history/history.js +37 -58
  145. package/dist/src/inbox/inbox-attachments.js +75 -14
  146. package/dist/src/inbox/inbox-cancel.js +7 -5
  147. package/dist/src/inbox/inbox-edit.js +1 -1
  148. package/dist/src/inbox/inbox-submit.js +44 -4
  149. package/dist/src/inbox/inbox-top.js +83 -0
  150. package/dist/src/inbox/inbox.js +8 -2
  151. package/dist/src/inbox/pending-prompt.js +1 -1
  152. package/dist/src/inbox/prompt-commands.js +170 -80
  153. package/dist/src/init/init-templates.js +16 -14
  154. package/dist/src/init/init.js +12 -11
  155. package/dist/src/loop/leftover.js +28 -27
  156. package/dist/src/loop/loop-fallback.js +2 -2
  157. package/dist/src/loop/loop-pi.js +106 -52
  158. package/dist/src/loop/loop-recovery.js +15 -15
  159. package/dist/src/loop/loop-state.js +139 -13
  160. package/dist/src/loop/loop-tick.js +194 -86
  161. package/dist/src/loop/loop.js +72 -36
  162. package/dist/src/loop/model-fallback.js +3 -2
  163. package/dist/src/loop/revision.js +16 -7
  164. package/dist/src/merge/backlog-conflicts.js +155 -0
  165. package/dist/src/{landing/landing-batch.js → merge/merge-batch.js} +90 -89
  166. package/dist/src/{landing/landing-check-failures.js → merge/merge-check-failures.js} +87 -41
  167. package/dist/src/{landing/landing-core.js → merge/merge-core.js} +119 -95
  168. package/dist/src/{landing/landing-diff.js → merge/merge-diff.js} +1 -1
  169. package/dist/src/merge/merge-drain.js +212 -0
  170. package/dist/src/{landing/landing-git.js → merge/merge-git.js} +94 -21
  171. package/dist/src/merge/merge-pipeline.js +99 -0
  172. package/dist/src/{landing/landing-questions.js → merge/merge-questions.js} +9 -6
  173. package/dist/src/merge/merge-queue-render.js +75 -0
  174. package/dist/src/{landing/landing-queue.js → merge/merge-queue.js} +95 -36
  175. package/dist/src/merge/merge-slot.js +340 -0
  176. package/dist/src/{landing/landing-stack.js → merge/merge-stack.js} +66 -62
  177. package/dist/src/{landing/landing-merge.js → merge/merge-to-main.js} +72 -62
  178. package/dist/src/merge/merge-verify.js +212 -0
  179. package/dist/src/notes-cli.js +97 -0
  180. package/dist/src/operator/operator-commands.js +154 -47
  181. package/dist/src/operator/operator-intent.js +87 -49
  182. package/dist/src/operator/operator-requests.js +52 -52
  183. package/dist/src/operator/retire.js +62 -27
  184. package/dist/src/operator/revert.js +71 -0
  185. package/dist/src/orchestrator/orchestrator-launch.js +74 -14
  186. package/dist/src/orchestrator/orchestrator-scheduling.js +129 -44
  187. package/dist/src/orchestrator/orchestrator.js +158 -100
  188. package/dist/src/orchestrator/retention.js +29 -12
  189. package/dist/src/orchestrator/startup-migration-steps.js +51 -0
  190. package/dist/src/orchestrator/startup-migrations.js +40 -0
  191. package/dist/src/paths.js +128 -37
  192. package/dist/src/pi/pi-args.js +26 -3
  193. package/dist/src/pi/pi-backend.js +15 -23
  194. package/dist/src/pi/pi-bin.js +18 -12
  195. package/dist/src/pi/pi-event-line.js +17 -1
  196. package/dist/src/pi/pi-failure.js +87 -0
  197. package/dist/src/pi/pi-models.js +126 -38
  198. package/dist/src/pi/pi-run-result.js +1 -1
  199. package/dist/src/pi/pi-settings.js +86 -0
  200. package/dist/src/pi/pi-stream.js +131 -107
  201. package/dist/src/pi/pi-watchdogs.js +47 -43
  202. package/dist/src/pi-extension/bounded-output.js +20 -5
  203. package/dist/src/pi-extension/context-budget.js +3 -1
  204. package/dist/src/pi-extension/context-shake.js +54 -21
  205. package/dist/src/pi-extension/context-window.js +37 -0
  206. package/dist/src/pi-extension/full-output.js +2 -2
  207. package/dist/src/pi-extension/strip-thinking.js +80 -0
  208. package/dist/src/pi-extension/trim-system-prompt.js +38 -0
  209. package/dist/src/process/launch-services.js +11 -10
  210. package/dist/src/process/process-table.js +1 -1
  211. package/dist/src/process/process.js +7 -7
  212. package/dist/src/process/run-marker.js +29 -6
  213. package/dist/src/process/supervisor.js +47 -25
  214. package/dist/src/prompt/dialect.js +30 -10
  215. package/dist/src/prompt/gate-prompts.js +170 -67
  216. package/dist/src/prompt/principles.js +1 -0
  217. package/dist/src/prompt/prompt-followup.js +35 -20
  218. package/dist/src/prompt/prompt.js +249 -91
  219. package/dist/src/redeploy/redeploy-policy.js +10 -10
  220. package/dist/src/redeploy/redeploy.js +6 -4
  221. package/dist/src/redeploy/redeployer.js +63 -55
  222. package/dist/src/redeploy/self-reload.js +1 -1
  223. package/dist/src/report/report-data.js +264 -255
  224. package/dist/src/report/report-fold.js +353 -0
  225. package/dist/src/report/report-render.js +270 -33
  226. package/dist/src/request-timeouts.js +1 -1
  227. package/dist/src/review/known-flakes.js +34 -14
  228. package/dist/src/review/protected-edits.js +33 -0
  229. package/dist/src/review/review-followup.js +16 -4
  230. package/dist/src/review/review-precheck.js +14 -13
  231. package/dist/src/review/review-verdict.js +14 -0
  232. package/dist/src/review/review.js +81 -39
  233. package/dist/src/review/secret-leaks.js +127 -0
  234. package/dist/src/review/suite-rerun.js +4 -3
  235. package/dist/src/roles/legacy-role-ids.js +21 -0
  236. package/dist/src/roles/legacy-role-migration.js +62 -0
  237. package/dist/src/roles/loop-ids.js +19 -2
  238. package/dist/src/roles/role-catalog.js +125 -135
  239. package/dist/src/roles/role-guidance.js +64 -31
  240. package/dist/src/roles/role-labels.js +10 -0
  241. package/dist/src/roles/role-render.js +194 -18
  242. package/dist/src/roles/role-view.js +216 -17
  243. package/dist/src/roles/roles.js +18 -15
  244. package/dist/src/scheduling/backoff.js +29 -19
  245. package/dist/src/scheduling/claims.js +25 -9
  246. package/dist/src/scheduling/once-round.js +11 -11
  247. package/dist/src/scheduling/quiet-hours.js +25 -32
  248. package/dist/src/scheduling/scheduling.js +43 -24
  249. package/dist/src/scheduling/{work-landed-cache.js → work-merged-cache.js} +14 -14
  250. package/dist/src/status/status-budget.js +115 -0
  251. package/dist/src/status/status-data.js +77 -184
  252. package/dist/src/status/status-inbox.js +47 -0
  253. package/dist/src/status/status-install.js +27 -0
  254. package/dist/src/status/status-polls.js +68 -33
  255. package/dist/src/status/status-roles.js +105 -0
  256. package/dist/src/{fleet → team}/error-storm.js +10 -10
  257. package/dist/src/{fleet → team}/failure-spread.js +8 -8
  258. package/dist/src/{fleet → team}/orchestrator-info.js +86 -18
  259. package/dist/src/{fleet → team}/reclaim.js +5 -4
  260. package/dist/src/{fleet/fleet-hold.js → team/team-hold.js} +55 -21
  261. package/dist/src/{fleet/fleet-polls.js → team/team-polls.js} +116 -65
  262. package/dist/src/{fleet/fleet-state.js → team/team-state.js} +62 -37
  263. package/dist/src/text/datetime.js +42 -2
  264. package/dist/src/text/format.js +10 -1
  265. package/dist/src/text/markdown.js +1 -1
  266. package/dist/src/text/phrases.js +35 -34
  267. package/dist/src/text/suggest.js +3 -2
  268. package/dist/src/text/text.js +2 -2
  269. package/dist/src/tick/qa-coverage.js +2 -1
  270. package/dist/src/tick/stage-check.js +147 -26
  271. package/dist/src/tick/telemetry-digest.js +10 -9
  272. package/dist/src/tick/tick-apply.js +101 -72
  273. package/dist/src/tick/tick-detail-data.js +32 -18
  274. package/dist/src/tick/tick-detail.js +62 -21
  275. package/dist/src/tick/tick-finalize.js +29 -22
  276. package/dist/src/tick/tick-outcome.js +2 -1
  277. package/dist/src/tick/tick-prompt.js +94 -26
  278. package/dist/src/tick/tick-resume.js +29 -13
  279. package/dist/src/tick/tick-stage.js +91 -47
  280. package/dist/src/tick/tick-timing.js +60 -59
  281. package/dist/src/tick/tick-usage.js +53 -23
  282. package/dist/src/tick/tick-verdict.js +76 -10
  283. package/dist/src/ui/badges.js +118 -67
  284. package/dist/src/ui/gui/gui-client-boot.js +209 -30
  285. package/dist/src/ui/gui/gui-client-composer.js +102 -23
  286. package/dist/src/ui/gui/gui-client-drawer.js +330 -75
  287. package/dist/src/ui/gui/gui-client-history.js +96 -38
  288. package/dist/src/ui/gui/gui-client-labels.js +24 -0
  289. package/dist/src/ui/gui/gui-client-loops.js +94 -52
  290. package/dist/src/ui/gui/gui-client-markdown.js +1 -0
  291. package/dist/src/ui/gui/gui-client-model.js +63 -43
  292. package/dist/src/ui/gui/gui-client-operator.js +129 -39
  293. package/dist/src/ui/gui/gui-client-pending.js +36 -32
  294. package/dist/src/ui/gui/gui-client-report.js +339 -46
  295. package/dist/src/ui/gui/gui-client-settings.js +148 -14
  296. package/dist/src/ui/gui/gui-client-sound.js +2 -1
  297. package/dist/src/ui/gui/{gui-client-fleet.js → gui-client-team.js} +196 -72
  298. package/dist/src/ui/gui/gui-client.js +26 -20
  299. package/dist/src/ui/gui/gui-page.js +19 -19
  300. package/dist/src/ui/gui/gui-styles.js +12 -4
  301. package/dist/src/ui/progress-data.js +5 -3
  302. package/dist/src/ui/status-model.js +184 -122
  303. package/dist/src/ui/status-payload.js +119 -32
  304. package/dist/src/ui/status-render.js +122 -52
  305. package/dist/src/ui/team-alerts.js +341 -0
  306. package/dist/src/ui/tick-progress-model.js +14 -14
  307. package/dist/src/ui/tone.js +11 -8
  308. package/dist/src/ui/transcript-tail.js +1 -0
  309. package/dist/src/ui/transcript.js +23 -16
  310. package/dist/src/ui/tui/tui-app.js +1 -0
  311. package/dist/src/ui/tui/tui-backlog.js +85 -11
  312. package/dist/src/ui/tui/tui-editor-answer.js +97 -0
  313. package/dist/src/ui/tui/tui-editor-attach.js +107 -0
  314. package/dist/src/ui/tui/tui-editor-brief.js +107 -0
  315. package/dist/src/ui/tui/tui-editor-budget.js +155 -0
  316. package/dist/src/ui/tui/tui-editor-ctx.js +1 -0
  317. package/dist/src/ui/tui/tui-editor-entry.js +230 -0
  318. package/dist/src/ui/tui/tui-editor-interval.js +122 -0
  319. package/dist/src/ui/tui/tui-editor-notes.js +114 -0
  320. package/dist/src/ui/tui/tui-editor-pause.js +266 -0
  321. package/dist/src/ui/tui/tui-editor-prompt.js +95 -0
  322. package/dist/src/ui/tui/tui-editor-queued.js +98 -0
  323. package/dist/src/ui/tui/tui-editor-quiet.js +106 -0
  324. package/dist/src/ui/tui/tui-editor-retire.js +83 -0
  325. package/dist/src/ui/tui/tui-editor-search.js +73 -0
  326. package/dist/src/ui/tui/tui-editor-session.js +97 -0
  327. package/dist/src/ui/tui/tui-editors.js +152 -0
  328. package/dist/src/ui/tui/tui-frame.js +67 -55
  329. package/dist/src/ui/tui/tui-history.js +12 -7
  330. package/dist/src/ui/tui/tui-input.js +49 -44
  331. package/dist/src/ui/tui/tui-keymap.js +1 -0
  332. package/dist/src/ui/tui/tui-keys.js +91 -1704
  333. package/dist/src/ui/tui/tui-pane-activity.js +99 -0
  334. package/dist/src/ui/tui/tui-pane-backlog.js +224 -0
  335. package/dist/src/ui/tui/tui-pane-brief.js +30 -0
  336. package/dist/src/ui/tui/tui-pane-ctx.js +11 -0
  337. package/dist/src/ui/tui/tui-pane-health.js +124 -0
  338. package/dist/src/ui/tui/tui-pane-history.js +316 -0
  339. package/dist/src/ui/tui/tui-pane-pending.js +74 -0
  340. package/dist/src/ui/tui/tui-pane-queued.js +143 -0
  341. package/dist/src/ui/tui/tui-pane-report.js +122 -0
  342. package/dist/src/ui/tui/tui-pane-session.js +101 -0
  343. package/dist/src/ui/tui/tui-pane-transcript.js +150 -0
  344. package/dist/src/ui/tui/tui-pane.js +66 -28
  345. package/dist/src/ui/tui/tui-panes.js +294 -0
  346. package/dist/src/ui/tui/tui.js +45 -25
  347. package/dist/src/verdict/fix-claim.js +141 -38
  348. package/dist/src/verdict/no-change.js +19 -0
  349. package/dist/src/verdict/refusal.js +92 -8
  350. package/dist/src/verdict/reply-contract.js +17 -5
  351. package/dist/src/version.js +3 -2
  352. package/package.json +4 -2
  353. package/dist/src/agent/mcp/role-notes-server.js +0 -160
  354. package/dist/src/landing/backlog-conflicts.js +0 -116
  355. package/dist/src/landing/landing-drain.js +0 -204
  356. package/dist/src/landing/landing-pipeline.js +0 -96
  357. package/dist/src/landing/landing-queue-render.js +0 -31
  358. package/dist/src/landing/landing-slot.js +0 -246
  359. package/dist/src/landing/landing-vetting.js +0 -196
  360. package/dist/src/pi-extension/role-notes.js +0 -40
  361. package/dist/src/ui/fleet-alerts.js +0 -174
@@ -0,0 +1,207 @@
1
+ // vocabulary: plain
2
+ /** Shell completion derived from the help text. The spec is parsed from the same HELP stanzas
3
+ * `tumwater help <command>` and the unknown-command suggestion use, so a new command or flag
4
+ * completes the moment it gains a help stanza and can never drift from the listing. */
5
+ import { customLoopNames, knownRoleIds, loadConfig } from "../config/config.js";
6
+ import { AGENT_IDS, AGENT_KEYS, CLAUDE_AGENT_KEYS, MODEL_TIERS, ROLE_ENTRY_KEYS, TOP_LEVEL_KEYS } from "../config/config-schema.js";
7
+ import { DOTTED_MAP_KEYS } from "../config/config-keys.js";
8
+ import { HISTORY_RESULT_FLAG_NAMES } from "../history/history-data.js";
9
+ import { templateIds } from "../init/init-templates.js";
10
+ import { allRoleIds } from "../roles/roles.js";
11
+ import { EVENT_TYPE_LABELS } from "../events/event-labels.js";
12
+ import { HELP, helpStanzas } from "./help.js";
13
+ export const SUPPORTED_SHELLS = ["bash", "zsh", "fish"];
14
+ /** The completable words of a stanza's usage part: the text after `tumwater <command>` up to the
15
+ * description column (two or more spaces). Bare lowercase words count inside `[...]` and as the
16
+ * leading run directly after the command; outside brackets the first other token ends the run, so
17
+ * a single-space description (`role <id> --clear-notes Clear that notebook`) adds nothing. */
18
+ function usageWords(firstLine, command) {
19
+ const rest = firstLine.replace(new RegExp(`^ {2}tumwater ${command}`), "");
20
+ // Usage arguments follow the command after a single space; two or more spaces start the
21
+ // description.
22
+ const usage = /^ {2,}/.test(rest) ? "" : (rest.split(/ {2,}/)[0] ?? "");
23
+ const words = [];
24
+ let depth = 0;
25
+ let leading = true;
26
+ for (const token of usage.split(/\s+/).filter(Boolean)) {
27
+ // An angle-bracket alternation of plain words — `<bash|zsh|fish>`, the completion
28
+ // command's shell positional — expands to each alternative as a subcommand word, so
29
+ // `tumwater completion <TAB>` lists exactly the shells the command accepts. A bare
30
+ // placeholder like `<id>` or `<k>` carries no `|` and so stays a placeholder, skipped
31
+ // as before (its `<`/`>` never leave the token, so it never looked like a word).
32
+ const alternation = /^<([a-z][a-z-]*(?:\|[a-z][a-z-]*)+)>$/.exec(token);
33
+ if (alternation && leading) {
34
+ for (const alt of alternation[1].split("|"))
35
+ words.push(alt);
36
+ continue;
37
+ }
38
+ const bare = token.replace(/[[\]|]/g, "");
39
+ const isWord = /^[a-z][a-z-]*$/.test(bare);
40
+ if (isWord && (depth > 0 || token.startsWith("[") || leading))
41
+ words.push(bare);
42
+ else if (depth === 0 && !token.startsWith("[") && bare !== "")
43
+ leading = false;
44
+ for (const ch of token)
45
+ depth += ch === "[" ? 1 : ch === "]" ? -1 : 0;
46
+ }
47
+ return words;
48
+ }
49
+ export function completionSpec(help = HELP) {
50
+ const stanzas = helpStanzas(help);
51
+ const commands = [...new Set(stanzas.map((s) => s.command))];
52
+ const subcommands = {};
53
+ const flags = {};
54
+ for (const command of commands) {
55
+ const own = stanzas.filter((s) => s.command === command);
56
+ const flagSet = new Set(["--help"]);
57
+ const subs = new Set();
58
+ for (const stanza of own) {
59
+ for (const match of stanza.text.matchAll(/--[a-z][a-z-]*/g))
60
+ flagSet.add(match[0]);
61
+ for (const word of usageWords(stanza.text.split("\n")[0] ?? "", command))
62
+ subs.add(word);
63
+ }
64
+ flags[command] = [...flagSet].sort();
65
+ subcommands[command] = command === "help" ? commands : [...subs];
66
+ }
67
+ return { commands, subcommands, flags };
68
+ }
69
+ /** The ids `--role` completes: this repo's loop ids, or the built-in catalog when tumwater.json is
70
+ * unreadable (a broken config must not write errors into the operator's prompt). */
71
+ export function completionRoleIds(root) {
72
+ try {
73
+ return knownRoleIds(loadConfig(root));
74
+ }
75
+ catch {
76
+ return allRoleIds();
77
+ }
78
+ }
79
+ /** The keys `config get|set|unset` complete: every form parseConfigKey accepts, with the
80
+ * role-scoped keys of this repo's base roles and custom loops (not instance ids like
81
+ * `feature-2`). A broken tumwater.json falls back to the built-in catalog rather than writing
82
+ * errors into the prompt. */
83
+ export function completionConfigKeys(root) {
84
+ let roleIds;
85
+ try {
86
+ roleIds = [...allRoleIds(), ...customLoopNames(loadConfig(root))];
87
+ }
88
+ catch {
89
+ roleIds = allRoleIds();
90
+ }
91
+ const keys = [
92
+ ...TOP_LEVEL_KEYS,
93
+ ...MODEL_TIERS.map((tier) => `model.${tier}`),
94
+ ...AGENT_IDS.flatMap((id) => (id === "claude" ? CLAUDE_AGENT_KEYS : AGENT_KEYS).map((field) => `backends.${id}.${field}`)),
95
+ ...DOTTED_MAP_KEYS.flatMap((map) => roleIds.map((id) => `${map}.${id}`)),
96
+ ...roleIds.flatMap((id) => ROLE_ENTRY_KEYS.map((field) => `roles.${id}.${field}`)),
97
+ ];
98
+ return [...new Set(keys)];
99
+ }
100
+ /** Flags whose value is a file path: completion offers file names after them. */
101
+ const PATH_FLAGS = ["--file", "--attach", "--notes-file", "--instructions-file"];
102
+ /** The event-type codes `logs --type` filters by: the keys of the labels map, so a new event
103
+ * type completes the moment it gains a label. Sorted for a stable, alphabetical offer of a
104
+ * vocabulary too large to recall offhand — the same reason `--role`, `--template`, and
105
+ * `--result` complete their values. */
106
+ const EVENT_TYPE_CODES = Object.keys(EVENT_TYPE_LABELS).sort();
107
+ function bashScript(help) {
108
+ const spec = completionSpec(help);
109
+ const arms = spec.commands.map((command) => {
110
+ const subs = spec.subcommands[command] ?? [];
111
+ const flags = spec.flags[command] ?? [];
112
+ return [
113
+ ` ${command})`,
114
+ ` if [[ "$cur" == -* ]]; then`,
115
+ ` COMPREPLY=( $(compgen -W "${flags.join(" ")}" -- "$cur") )`,
116
+ ...(subs.length > 0
117
+ ? [
118
+ ` elif [ "$COMP_CWORD" -eq 2 ]; then`,
119
+ ` COMPREPLY=( $(compgen -W "${subs.join(" ")}" -- "$cur") )`,
120
+ ]
121
+ : []),
122
+ ` fi`,
123
+ ` ;;`,
124
+ ].join("\n");
125
+ });
126
+ return [
127
+ `# tumwater completion (generated from \`tumwater help\`)`,
128
+ `_tumwater() {`,
129
+ ` local cur="\${COMP_WORDS[COMP_CWORD]}"`,
130
+ ` local prev="\${COMP_WORDS[COMP_CWORD-1]}"`,
131
+ ` COMPREPLY=()`,
132
+ ` if [ "$prev" = "--role" ] || { [ "$COMP_CWORD" -eq 2 ] && [[ "\${COMP_WORDS[1]}" == role || "\${COMP_WORDS[1]}" == history ]] && [[ "$cur" != -* ]]; }; then`,
133
+ ` COMPREPLY=( $(compgen -W "$(tumwater completion --roles 2>/dev/null)" -- "$cur") )`,
134
+ ` return 0`,
135
+ ` fi`,
136
+ ` case "$prev" in ${PATH_FLAGS.join("|")})`,
137
+ ` COMPREPLY=( $(compgen -f -- "$cur") )`,
138
+ ` return 0`,
139
+ ` ;;`,
140
+ ` esac`,
141
+ ` if [ "$prev" = "--template" ]; then`,
142
+ ` COMPREPLY=( $(compgen -W "${templateIds().join(" ")}" -- "$cur") )`,
143
+ ` return 0`,
144
+ ` fi`,
145
+ ` if [ "$prev" = "--result" ]; then`,
146
+ ` COMPREPLY=( $(compgen -W "${Object.values(HISTORY_RESULT_FLAG_NAMES).join(" ")}" -- "$cur") )`,
147
+ ` return 0`,
148
+ ` fi`,
149
+ ` if [ "$prev" = "--type" ]; then`,
150
+ ` COMPREPLY=( $(compgen -W "${EVENT_TYPE_CODES.join(" ")}" -- "$cur") )`,
151
+ ` return 0`,
152
+ ` fi`,
153
+ ` if [ "$COMP_CWORD" -eq 3 ] && [ "\${COMP_WORDS[1]}" = config ] && [[ "\${COMP_WORDS[2]}" == get || "\${COMP_WORDS[2]}" == set || "\${COMP_WORDS[2]}" == unset ]] && [[ "$cur" != -* ]]; then`,
154
+ ` COMPREPLY=( $(compgen -W "$(tumwater completion --config-keys 2>/dev/null)" -- "$cur") )`,
155
+ ` return 0`,
156
+ ` fi`,
157
+ ` if [ "$COMP_CWORD" -eq 1 ]; then`,
158
+ ` COMPREPLY=( $(compgen -W "${spec.commands.join(" ")}" -- "$cur") )`,
159
+ ` return 0`,
160
+ ` fi`,
161
+ ` case "\${COMP_WORDS[1]}" in`,
162
+ ...arms,
163
+ ` esac`,
164
+ ` return 0`,
165
+ `}`,
166
+ `complete -F _tumwater tumwater`,
167
+ ``,
168
+ ].join("\n");
169
+ }
170
+ /** The value suffix a fish flag line carries: what completes after the flag. */
171
+ function fishFlagValue(flag) {
172
+ if (flag === "--role")
173
+ return ` -x -a "(tumwater completion --roles 2>/dev/null)"`;
174
+ if (PATH_FLAGS.includes(flag))
175
+ return ` -r -F`;
176
+ if (flag === "--template")
177
+ return ` -x -a "${templateIds().join(" ")}"`;
178
+ if (flag === "--result")
179
+ return ` -x -a "${Object.values(HISTORY_RESULT_FLAG_NAMES).join(" ")}"`;
180
+ if (flag === "--type")
181
+ return ` -x -a "${EVENT_TYPE_CODES.join(" ")}"`;
182
+ return "";
183
+ }
184
+ function fishScript(help) {
185
+ const spec = completionSpec(help);
186
+ const lines = [
187
+ `# tumwater completion (generated from \`tumwater help\`)`,
188
+ `complete -c tumwater -f`,
189
+ `function __tumwater_argc; count (commandline -opc); end`,
190
+ `complete -c tumwater -n __fish_use_subcommand -a "${spec.commands.join(" ")}"`,
191
+ ];
192
+ for (const command of spec.commands) {
193
+ const subs = spec.subcommands[command] ?? [];
194
+ if (subs.length > 0)
195
+ lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from ${command}; and test (__tumwater_argc) -eq 2" -a "${subs.join(" ")}"`);
196
+ for (const flag of spec.flags[command] ?? [])
197
+ lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from ${command}" -l ${flag.slice(2)}${fishFlagValue(flag)}`);
198
+ }
199
+ lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from role history; and test (__tumwater_argc) -eq 2" -a "(tumwater completion --roles 2>/dev/null)"`, `complete -c tumwater -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from get set unset; and test (__tumwater_argc) -eq 3" -a "(tumwater completion --config-keys 2>/dev/null)"`, ``);
200
+ return lines.join("\n");
201
+ }
202
+ export function completionScript(shell, help = HELP) {
203
+ if (shell === "fish")
204
+ return fishScript(help);
205
+ const bash = bashScript(help);
206
+ return shell === "zsh" ? `autoload -U +X bashcompinit && bashcompinit\n${bash}` : bash;
207
+ }
@@ -1,12 +1,15 @@
1
+ // vocabulary: plain
1
2
  import { loadConfigSafe, knownRoleIds } from "../config/config.js";
2
3
  import { fail, say, sayJson, sayJsonLine } from "./cli-output.js";
3
- import { setConfigKey, unsetConfigKey, parseConfigKey, unknownConfigKeyError, unknownRoleFieldError, } from "../config/config-write.js";
4
+ import { setConfigKey, unsetConfigKey, } from "../config/config-write.js";
5
+ import { canonicalConfigKey } from "../config/config-aliases.js";
6
+ import { parseConfigKey, unknownConfigKeyError, unknownRoleFieldError } from "../config/config-keys.js";
4
7
  import { modelTierMap } from "../config/config-schema.js";
5
8
  import { unknownRoleMessage } from "../roles/roles.js";
6
9
  /** The `tumwater config` command's CLI layer (split out of operator/operator-commands.ts, which
7
10
  * keeps the other operator-command bodies): with no arguments, print the effective merged
8
11
  * config — exactly what `loadConfig(root)` returns — as pretty JSON, so an operator
9
- * debugging scheduling or custom-loop wiring sees what the fleet would actually load instead
12
+ * debugging scheduling or custom-loop wiring sees what the team would actually load instead
10
13
  * of overlaying defaults onto tumwater.json by hand. A query, not a writer: no redaction (the
11
14
  * config holds no secrets — provider keys belong to pi's own env) and no transformation,
12
15
  * including the per-role entries custom loops merge into. `get <key>` prints that one key's
@@ -17,7 +20,7 @@ import { unknownRoleMessage } from "../roles/roles.js";
17
20
  * not parseable JSON for a script and indistinguishable from a crash for a human. `set <key>
18
21
  * <value>` writes one top-level key through setConfigKey and prints one confirmation line
19
22
  * naming the key and its new value; `unset <key>` removes one value through unsetConfigKey
20
- * (the inverse of set) and confirms what, if anything, was removed. A running fleet picks the
23
+ * (the inverse of set) and confirms what, if anything, was removed. A running team picks the
21
24
  * change up on its next ~2 s config poll (newLiveConfigReload). A malformed or invalid
22
25
  * tumwater.json fails with validateConfig's actionable message and prints no JSON — the same
23
26
  * surfacing doctor's config check produces. The reading/writing halves live beside it in
@@ -30,12 +33,13 @@ export const CONFIG_USAGE = "usage: tumwater config [get <key> | set <key> <valu
30
33
  /** The key screens `config get` and `config unset` run before resolving or removing a value:
31
34
  * the shape parser's own error; the shared unknown-top-level-key message; then, for a dotted
32
35
  * key, the catalog's known-role check and the shared unknown-role-field message. A dotted key
33
- * naming a role the catalog (plus customLoops) does not know can never resolve, and a silent
36
+ * naming a role the catalog (plus customRoles) does not know can never resolve, and a silent
34
37
  * `null`/removal for it would read as a real unset when the operator misspelled the id. Fails
35
38
  * the process with whichever message applies; returns the parsed key and the freshly loaded
36
39
  * config for the caller's own read/mutation. (An unknown role id in the FILE is already a
37
40
  * validation error — this is the same rule at the CLI boundary.) */
38
- function screenOperableKey(root, k) {
41
+ function screenOperableKey(root, key) {
42
+ const k = canonicalConfigKey(key);
39
43
  const parsed = parseConfigKey(k); // shape only — the verbs below own the unknown-key wording
40
44
  if (parsed.kind === "error")
41
45
  fail(parsed.error);
@@ -65,18 +69,17 @@ function screenOperableKey(root, k) {
65
69
  export async function cmdConfig(root, args = []) {
66
70
  const [sub, key, ...rest] = args;
67
71
  if (sub === "get") {
68
- const k = key ?? "";
69
- const { parsed, config } = screenOperableKey(root, k);
72
+ const { parsed, config } = screenOperableKey(root, key ?? "");
70
73
  const record = config;
71
74
  const value = parsed.kind === "map"
72
75
  ? record[parsed.map]?.[parsed.role]
73
76
  : parsed.kind === "tier"
74
77
  ? modelTierMap(record.model)[parsed.tier] // a string is shorthand for { default }
75
78
  : parsed.kind === "agent"
76
- ? record.agents?.[parsed.id]?.[parsed.field]
79
+ ? record.backends?.[parsed.id]?.[parsed.field]
77
80
  : parsed.kind === "role"
78
81
  ? record.roles?.[parsed.id]?.[parsed.field]
79
- : record[k];
82
+ : record[canonicalConfigKey(key ?? "")];
80
83
  sayJsonLine(value === undefined ? null : value); // Absent optional key → JSON null.
81
84
  return;
82
85
  }
@@ -85,7 +88,7 @@ export async function cmdConfig(root, args = []) {
85
88
  // this is the defensive tail for a direct caller, matching the bare-config tail below.
86
89
  if (key === undefined)
87
90
  fail(CONFIG_USAGE);
88
- const k = key;
91
+ const k = canonicalConfigKey(key);
89
92
  // The same screens get runs first, so a typo'd top-level key, role id, or role field
90
93
  // fails identically — unsetConfigKey's own parse/field checks are the mutation-side
91
94
  // backstop, not the wording the operator sees.
@@ -112,7 +115,7 @@ export async function cmdConfig(root, args = []) {
112
115
  const result = setConfigKey(root, key ?? "", raw);
113
116
  if (!result.ok)
114
117
  fail(result.error);
115
- say(`set ${key} to ${JSON.stringify(result.value)}`);
118
+ say(`set ${canonicalConfigKey(key ?? "")} to ${JSON.stringify(result.value)}`);
116
119
  // A bare `roles` set replaces the FILE's section, but the built-in catalog always merges
117
120
  // per entry at load, so the replacement cannot disable a role by omission. Say so here
118
121
  // rather than let the confirmation imply the role is gone.