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
@@ -1,6 +1,8 @@
1
+ // vocabulary: plain
1
2
  /** The dashboard's Settings view, browser-side: the curated top-level config keys
2
3
  * (EDITABLE_CONFIG_KEYS's set, mirrored here for the labels) as label + current value +
3
- * inline field + Save + Clear, one row per key. Values load once through GET /api/config when
4
+ * inline field + Save + Clear, one row per key (the Notify row also has Send test, which
5
+ * posts to POST /api/notify-test). Values load once through GET /api/config when
4
6
  * the view is first opened — no polling loop of its own; a re-click of the tab refetches, like
5
7
  * the other views' refresh-on-open. Save posts {key, value} to POST /api/config-set — the
6
8
  * same setConfigKey write path `tumwater config set` uses — and Clear posts {key} to
@@ -9,8 +11,18 @@
9
11
  * success/error toast pattern the composer's send uses (showFlash). Spliced into
10
12
  * gui-client.ts's script, reaching its helpers (esc, $, getJson, postJson, showFlash) through
11
13
  * that concatenation. A second card, "Health check", runs the same checks as `tumwater doctor`
12
- * through GET /api/doctor on each open (and on its Re-run button) and paints the report. */
14
+ * through GET /api/doctor on each open (and on its Re-run button) and paints the report; a
15
+ * third, "Disabled roles", lists every disabled role (GET /api/retire), each with an Enable
16
+ * button (POST /api/role-enable) and — for a role that still keeps worktree/branch leftovers — a
17
+ * two-click Retire button (POST /api/retire). */
13
18
  export const GUI_CLIENT_SETTINGS_JS = String.raw ` // settings-view:start
19
+ // One home for turning a thrown value into the message a flash shows: the fetch/parse/post
20
+ // helpers throw the server's JSON-decoded value, which for the server's own errors is an
21
+ // {error} object (its message on the .message field) — the three Save/Clear/Brief catch
22
+ // blocks that flash the outcome share this coercion so the wording cannot drift.
23
+ function clientErrorMessage(err) {
24
+ return err && err.message ? err.message : String(err);
25
+ }
14
26
  // The curated keys, in display order: [key, label]. Mirrors the server's
15
27
  // EDITABLE_CONFIG_KEYS (src/config/config-editable-keys.ts) by hand — the settings test pins
16
28
  // this list's keys and order to that constant.
@@ -21,7 +33,7 @@ export const GUI_CLIENT_SETTINGS_JS = String.raw ` // settings-view:start
21
33
  ["maxDailyCostUsd", "Daily spend cap (USD)"],
22
34
  ["quietHours", "Quiet hours"],
23
35
  ["notify", "Notify hook"],
24
- ["agents", "Agent backends (JSON)"],
36
+ ["backends", "Agent backends (JSON)"],
25
37
  ];
26
38
  // One row per key: the current value into an inline field (esc'd, like every rendered
27
39
  // value on the page), Save submits the row's form. A null (unset) key renders empty —
@@ -39,38 +51,124 @@ export const GUI_CLIENT_SETTINGS_JS = String.raw ` // settings-view:start
39
51
  "<input class='field' id='set-" + k[0] + "' value='" + esc(settingsFieldValue(d[k[0]])) + "'>" +
40
52
  "<button type='submit' class='btn btn-sm'>Save</button>" +
41
53
  "<button type='button' class='btn btn-sm rowaction' data-action='unset'>Clear</button>" +
54
+ (k[0] === "notify" ? "<button type='button' class='btn btn-sm rowaction' data-action='notify-test' title='Runs the saved hook once with a synthetic merge_failed event'>Send test</button>" : "") +
42
55
  "</form>").join("");
43
56
  }
44
57
  // The view's one panel: built once, values fetched on each open of the tab (the boot's
45
58
  // switchView calls fetchSettings) — no polling loop of its own.
46
59
  function buildSettingsView() {
47
60
  buildOnce("settings-view", "<div class='view-head'><div><h1>Settings</h1>" +
48
- "<p>The fleet-wide settings an operator edits from here; everything else lives in tumwater.json or the CLI.</p></div></div>" +
61
+ "<p>The team-wide settings you edit from here; everything else lives in tumwater.json or the CLI.</p></div></div>" +
49
62
  "<div class='card' id='settingscard'><div class='empty'>Loading…</div></div>" +
50
- "<div class='card' id='doctorcard'><div class='settings-row'><strong>Health check</strong>" +
63
+ "<div class='card' id='doctorcard'><div class='settings-row'><strong>Health</strong>" +
51
64
  "<span>The same checks as <code>tumwater doctor</code>.</span>" +
65
+ "<label><input type='checkbox' data-action='doctor-problems'> Problems only</label>" +
52
66
  "<button type='button' class='btn btn-sm' data-action='doctor-rerun'>Re-run</button></div>" +
53
- "<div id='doctorbody'><div class='empty'>Checking…</div></div></div>");
67
+ "<div id='doctorbody'><div class='empty'>Checking…</div></div></div>" +
68
+ "<div class='card' id='retirecard'><div class='empty'>Loading…</div></div>" +
69
+ "<div class='card' id='briefcard'><div class='empty'>Loading…</div></div>");
54
70
  }
55
71
  // The Health check card's body: header, one row per check (level badge, name, detail), the
56
72
  // verdict — everything esc'd. The pill is built inline (gui-client.ts's pill sits outside
57
- // this region). A missing checks array renders no rows.
58
- function renderDoctorReport(d) {
73
+ // this region). A missing checks array renders no rows. With problems (the Problems only
74
+ // checkbox), only the warn and fail rows render and a hidden-count line names how many ok
75
+ // rows were cut, mirroring tumwater doctor --problems's problemsOnly/renderDoctorProblems.
76
+ function renderDoctorReport(d, problems) {
59
77
  const tones = { ok: "green", warn: "amber", fail: "red" };
60
- const rows = (Array.isArray(d.checks) ? d.checks : []).map((c) =>
78
+ const all = Array.isArray(d.checks) ? d.checks : [];
79
+ const checks = problems ? all.filter((c) => c.level !== "ok") : all;
80
+ const hidden = all.length - checks.length;
81
+ const rows = checks.map((c) =>
61
82
  "<div class='settings-row'><span class='pill t-" + (tones[c.level] || "amber") + "'>" + esc(c.level) + "</span>" +
62
83
  "<strong>" + esc(c.name) + "</strong><span>" + esc(c.detail) + "</span></div>").join("");
63
- return "<p>" + esc(d.header) + "</p>" + rows + "<p>" + esc(d.verdict) + "</p>";
84
+ return "<p>" + esc(d.header) + "</p>" + rows +
85
+ (problems && hidden > 0 ? "<p class='empty'>" + hidden + " " + (hidden === 1 ? "ok check" : "ok checks") + " hidden</p>" : "") +
86
+ "<p>" + esc(d.verdict) + "</p>";
64
87
  }
88
+ // The last resolved doctor report and whether the card paints only its problems; the
89
+ // Problems only checkbox toggles the latter and repaints the cached body without rerunning
90
+ // the checks.
91
+ let lastDoctor = null;
92
+ let doctorProblems = false;
65
93
  async function fetchDoctor() {
66
94
  buildSettingsView();
67
95
  const body = $("doctorbody");
68
96
  body.innerHTML = "<div class='empty'>Checking…</div>";
69
97
  try {
70
- body.innerHTML = renderDoctorReport(await getJson("/api/doctor"));
98
+ const report = await getJson("/api/doctor");
99
+ lastDoctor = report;
100
+ body.innerHTML = renderDoctorReport(report, doctorProblems);
101
+ } catch (err) {
102
+ body.innerHTML = errorPanel("Health checks could not run", err, "empty");
103
+ }
104
+ }
105
+ function toggleDoctorProblems(checked) {
106
+ doctorProblems = checked;
107
+ const body = $("doctorbody");
108
+ if (lastDoctor !== null) body.innerHTML = renderDoctorReport(lastDoctor, doctorProblems);
109
+ }
110
+ // The Disabled roles card: every role set to enabled: false (GET /api/retire), each with an
111
+ // Enable button (POST /api/role-enable) and — for a role that still keeps a worktree, branch,
112
+ // merge ref, or paused marker — a two-click Retire button (POST /api/retire), the same removal
113
+ // as tumwater retire --role <id>. A role the safety rails object to shows the objections and
114
+ // the CLI's --force command instead: the dashboard never forces.
115
+ let lastRetirable = null;
116
+ const retireSlot = confirmSlot(paintRetirable);
117
+ function renderRetirable(d, armed) {
118
+ const rows = (d.roles || []).map((r) => {
119
+ const hasLeftovers = (r.wouldRemove || []).length > 0;
120
+ const head = "<strong>" + esc(r.role) + "</strong>" +
121
+ (hasLeftovers ? "<span>would remove " + r.phrases.map(esc).join(", ") + "</span>" : "<span>no leftovers to remove</span>") +
122
+ "<button type='button' class='btn btn-sm' data-action='enable' data-role='" + esc(r.role) + "'>Enable</button>";
123
+ if (r.objections.length > 0) {
124
+ return "<div class='settings-row'>" + head + r.objections.map((o) => "<span>" + esc(o) + "</span>").join("") +
125
+ "<code>tumwater retire --role " + esc(r.role) + " --force</code></div>";
126
+ }
127
+ const retireBtn = hasLeftovers ? "<button type='button' class='btn btn-sm' data-action='retire' data-role='" + esc(r.role) + "'>" +
128
+ (armed(r.role) ? "Confirm retire" : "Retire") + "</button>" : "";
129
+ return "<div class='settings-row'>" + head + retireBtn + "</div>";
130
+ }).join("");
131
+ return "<div class='settings-row'><strong>Disabled roles</strong><span>Roles set to enabled: false — re-enable one, or remove the leftovers " +
132
+ "the same way <code>tumwater retire --role &lt;id&gt;</code> does.</span></div>" +
133
+ (rows || "<div class='empty'>No role is disabled.</div>");
134
+ }
135
+ function paintRetirable() {
136
+ if (lastRetirable) $("retirecard").innerHTML = renderRetirable(lastRetirable, retireSlot.armed);
137
+ }
138
+ async function fetchRetirable() {
139
+ buildSettingsView();
140
+ try {
141
+ lastRetirable = await getJson("/api/retire");
142
+ paintRetirable();
143
+ } catch (err) {
144
+ $("retirecard").innerHTML = errorPanel("Disabled roles could not load", err, "empty");
145
+ }
146
+ }
147
+ // The row's Enable button: re-enable the role through POST /api/role-enable (writing
148
+ // roles.<base>.enabled), flash the server's message, and refetch so the card drops the row.
149
+ async function enableRole(role) {
150
+ try {
151
+ const d = await postJson("/api/role-enable", { role: role });
152
+ showFlash(d.message);
153
+ } catch (err) {
154
+ showFlash("error: " + clientErrorMessage(err));
155
+ }
156
+ await fetchRetirable();
157
+ }
158
+ // First click arms the role's button; a second within the confirm window posts the retire.
159
+ async function confirmRetire(role) {
160
+ if (!retireSlot.armed(role)) {
161
+ retireSlot.arm(role);
162
+ return;
163
+ }
164
+ retireSlot.disarm();
165
+ try {
166
+ const d = await postJson("/api/retire", { role: role });
167
+ showFlash(d.message);
71
168
  } catch (err) {
72
- body.innerHTML = errorPanel("Health check could not run", err, "empty");
169
+ showFlash("error: " + clientErrorMessage(err));
73
170
  }
171
+ await fetchRetirable();
74
172
  }
75
173
  async function fetchSettings() {
76
174
  buildSettingsView();
@@ -101,7 +199,7 @@ export const GUI_CLIENT_SETTINGS_JS = String.raw ` // settings-view:start
101
199
  const d = await postJson("/api/config-set", { key: key, value: value });
102
200
  showFlash(d && d.oldValue === null ? "Saved " + key + " (was unset)" : "Saved " + key);
103
201
  } catch (err) {
104
- showFlash("error: " + (err && err.message ? err.message : String(err)));
202
+ showFlash("error: " + clientErrorMessage(err));
105
203
  }
106
204
  }
107
205
  // The row's Clear button: retract the key through /api/config-unset, then refetch so the
@@ -115,7 +213,43 @@ export const GUI_CLIENT_SETTINGS_JS = String.raw ` // settings-view:start
115
213
  showFlash(d && d.oldValue !== undefined ? "Unset " + key + " (was " + JSON.stringify(d.oldValue) + ")" : "Nothing to unset for " + key + " — it was already the default");
116
214
  await fetchSettings();
117
215
  } catch (err) {
118
- showFlash("error: " + (err && err.message ? err.message : String(err)));
216
+ showFlash("error: " + clientErrorMessage(err));
217
+ }
218
+ }
219
+ // The Notify row's Send test button: POST /api/notify-test runs the saved hook once, the same
220
+ // test that "tumwater notify --test" runs. The hook can take up to 10 s, so say so first.
221
+ async function testNotify() {
222
+ showFlash("Sending a test notification…");
223
+ try {
224
+ const d = await postJson("/api/notify-test", {});
225
+ showFlash((d.passed ? "" : "error: ") + d.message);
226
+ } catch (err) {
227
+ showFlash("error: " + clientErrorMessage(err));
228
+ }
229
+ }
230
+ // The Brief card: the brief file's name and the prompt in a textarea, filled from
231
+ // GET /api/brief on each open. The form is deliberately not a settings-row, so the boot's
232
+ // delegated settings submit listener never routes it to saveSetting.
233
+ async function fetchBrief() {
234
+ buildSettingsView();
235
+ const card = $("briefcard");
236
+ try {
237
+ const d = await getJson("/api/brief");
238
+ card.innerHTML = "<form class='brief-form'><strong>Brief</strong> <span class='settings-key'>" + esc(d.file) + "</span>" +
239
+ "<textarea class='field' id='brief-text' rows='12'>" + esc(d.prompt) + "</textarea>" +
240
+ "<button type='submit' class='btn btn-sm'>Save</button></form>";
241
+ } catch (err) {
242
+ card.innerHTML = errorPanel("Brief could not load", err, "empty");
243
+ }
244
+ }
245
+ // Save posts the textarea's text to POST /api/brief — the same checks and commit as
246
+ // tumwater brief --file — and flashes the outcome.
247
+ async function saveBrief(form) {
248
+ try {
249
+ const d = await postJson("/api/brief", { prompt: form.querySelector("textarea").value });
250
+ showFlash(!d.changed ? "Brief unchanged" : d.committed ? "Brief saved (committed to main)" : "Brief saved");
251
+ } catch (err) {
252
+ showFlash("error: " + clientErrorMessage(err));
119
253
  }
120
254
  }
121
255
  // settings-view:end
@@ -1,6 +1,7 @@
1
+ // vocabulary: plain
1
2
  /** The dashboard's sound layer, browser-side: one short synthesized cue when a new needs-you
2
3
  * alert appears (a failing loop, a red main, a spent budget, a lost server), scoped from
3
- * docs/feature-gui-audio-sound-effects.md to the alerts cue — the one moment the fleet
4
+ * docs/feature-gui-audio-sound-effects.md to the alerts cue — the one moment the team
4
5
  * genuinely needs a human. Client-side only: Web Audio is a browser built-in, so the zero
5
6
  * runtime dependencies principle holds, and every path degrades to silence — no AudioContext,
6
7
  * no user gesture yet, or a muted preference all leave the page quiet and error-free. Spliced