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,13 +1,15 @@
1
+ // vocabulary: plain
1
2
  import { spawn } from "node:child_process";
3
+ import { TUMWATER_SOURCE } from "../events/events.js";
2
4
  import { RESTART_EXIT_CODE } from "../redeploy/redeploy-policy.js";
3
5
  import { childEnv, runOnAbort } from "./process.js";
4
6
  /** The respawn loop behind `tumwater run`. The command runs as two processes: this supervisor (the
5
7
  * one the operator started, holding the terminal) and a child that actually runs the orchestrator.
6
8
  * When the child rebuilt dist/ onto a newer main (src/redeploy/redeployer.ts) it exits
7
9
  * RESTART_EXIT_CODE and the supervisor respawns it — the same script path, now holding the new
8
- * code — so a self-hosting fleet picks up its own changes without anyone at the keyboard. Any
9
- * other exit ends the supervisor with the child's code — and when nobody asked for it, the fleet
10
- * is down with nobody at the keyboard either, so that exit is recorded first (onFleetDown). Ctrl+C
10
+ * code — so a self-hosting team picks up its own changes without anyone at the keyboard. Any
11
+ * other exit ends the supervisor with the child's code — and when nobody asked for it, the team
12
+ * is down with nobody at the keyboard either, so that exit is recorded first (onTeamDown). Ctrl+C
11
13
  * reaches both processes from the terminal (same foreground group), so the supervisor forwards only
12
14
  * SIGTERM, which a plain `kill` delivers to it alone. */
13
15
  /** Marks the child: `tumwater run` with this set runs the orchestrator instead of supervising. */
@@ -18,6 +20,13 @@ export const SUPERVISED_ENV = "TUMWATER_SUPERVISED";
18
20
  * arms — still counts as gone (the dashboard's DASHBOARD_CHILD_ENV carries the same mark for its
19
21
  * reload watch). */
20
22
  export const SUPERVISOR_PID_ENV = "TUMWATER_SUPERVISOR_PID";
23
+ /** Marks a `run --for` window's start (epoch ms), set once by the supervisor and handed to every
24
+ * orchestrator generation, so a self-redeploy continues the window instead of opening a new one. */
25
+ export const RUN_WINDOW_START_ENV = "TUMWATER_RUN_WINDOW_START";
26
+ /** The exit code of a `run --once` round that finished and found failed ticks (cli-run.ts's
27
+ * onceFailures): an asked-for ending, so the supervisor passes it through without paging the
28
+ * team-down hook. */
29
+ export const ONCE_FAILED_EXIT_CODE = 3;
21
30
  /** How often the supervised generation checks that its supervisor still lives (ms). */
22
31
  const PARENT_POLL_MS = 5_000;
23
32
  /** The default poll: `check` every `intervalMs`, on a timer unref'd so an idle watch never holds
@@ -32,10 +41,10 @@ function intervalPoll(intervalMs) {
32
41
  /** Parent-death watch for the supervised generation. The supervisor forwards only SIGTERM —
33
42
  * SIGKILL (the OOM killer, `kill -9`) cannot be trapped or forwarded, and an uncaught supervisor
34
43
  * crash forwards nothing either — so a supervisor that dies outright leaves the generation
35
- * reparented (on macOS to launchd) and ticking the fleet unattended, with nothing left to sweep
44
+ * reparented (on macOS to launchd) and ticking the team unattended, with nothing left to sweep
36
45
  * it. The watch polls the parent pid on an interval: once it changes, the supervisor is gone
37
- * without having stopped the fleet, and `onGone` runs the same graceful stop a forwarded SIGTERM
38
- * would have run — a killed supervisor takes its fleet down with it. The timer is unref'd so it
46
+ * without having stopped the team, and `onGone` runs the same graceful stop a forwarded SIGTERM
47
+ * would have run — a killed supervisor takes its team down with it. The timer is unref'd so it
39
48
  * never holds the generation's event loop open past its real work. Returns the stop that
40
49
  * disarms the watch (a no-op once it fired or was already stopped). */
41
50
  export function startParentDeathWatch(onGone, opts = {}) {
@@ -91,12 +100,12 @@ export async function superviseRun(opts, signal) {
91
100
  const now = opts.now ?? Date.now;
92
101
  let generation = 1;
93
102
  const recentRespawns = [];
94
- const fleetDown = async (down) => {
103
+ const teamDown = async (down) => {
95
104
  try {
96
- await opts.onFleetDown?.(down);
105
+ await opts.onTeamDown?.(down);
97
106
  }
98
107
  catch {
99
- // Best-effort (see onFleetDown): a trace that cannot be written must not change the exit.
108
+ // Best-effort (see onTeamDown): a trace that cannot be written must not change the exit.
100
109
  }
101
110
  };
102
111
  try {
@@ -104,9 +113,11 @@ export async function superviseRun(opts, signal) {
104
113
  const exit = await opts.spawnChild(signal);
105
114
  if (exit.code !== RESTART_EXIT_CODE || opts.stopping()) {
106
115
  // A clean exit (a child stopped by its own SIGTERM logs orchestrator_stop) and anything
107
- // while the operator is stopping are asked-for endings; everything else is the fleet dying.
108
- if (exitCodeOf(exit) !== 0 && !opts.stopping())
109
- await fleetDown({ generation, exit, crashLoop: false });
116
+ // while the operator is stopping are asked-for endings, and so is a once round that
117
+ // finished with failed ticks; everything else is the team dying.
118
+ const code = exitCodeOf(exit);
119
+ if (code !== 0 && code !== ONCE_FAILED_EXIT_CODE && !opts.stopping())
120
+ await teamDown({ generation, exit, crashLoop: false });
110
121
  return exitCodeOf(exit);
111
122
  }
112
123
  const t = now();
@@ -115,7 +126,7 @@ export async function superviseRun(opts, signal) {
115
126
  recentRespawns.push(t);
116
127
  if (recentRespawns.length > MAX_RAPID_RESPAWNS) {
117
128
  opts.onCrashLoop?.();
118
- await fleetDown({ generation, exit, crashLoop: true });
129
+ await teamDown({ generation, exit, crashLoop: true });
119
130
  return 1;
120
131
  }
121
132
  generation += 1;
@@ -132,17 +143,17 @@ export async function superviseRun(opts, signal) {
132
143
  }
133
144
  }
134
145
  }
135
- /** The `supervisor_exit` event for a fleet that went down (see onFleetDown). `diagnosis` is the
146
+ /** The `supervisor_exit` event for a team that went down (see onTeamDown). `diagnosis` is the
136
147
  * startup gate re-asked after the death (startup-gate.ts's runStartupProblem): the likeliest
137
148
  * reason a generation dies right after a respawn is an environment that no longer boots, and the
138
149
  * child's own message reached only the terminal. Null when every precondition passes — the event
139
150
  * then carries no reason rather than a guess. A crash loop's reason is the guard itself. */
140
- export function fleetDownEvent(down, diagnosis) {
151
+ export function teamDownEvent(down, diagnosis) {
141
152
  const reason = down.crashLoop
142
153
  ? `restarted itself more than ${MAX_RAPID_RESPAWNS} times within ${RESPAWN_WINDOW_MS / 1000}s — giving up`
143
154
  : diagnosis;
144
155
  return {
145
- loop: "harness",
156
+ source: TUMWATER_SOURCE,
146
157
  type: "supervisor_exit",
147
158
  generation: down.generation,
148
159
  code: down.exit.code,
@@ -156,29 +167,40 @@ export function fleetDownEvent(down, diagnosis) {
156
167
  * same branch) — stdio shared (the child's event stream is what the operator sees), and
157
168
  * SUPERVISED_ENV set so it runs the orchestrator instead of supervising again, plus
158
169
  * SUPERVISOR_PID_ENV naming this supervisor so the child's own parent-death watch fires even if
159
- * this process is killed before the child reads its first ppid. */
160
- export function spawnRunChild(signal, extraArgs = []) {
170
+ * this process is killed before the child reads its first ppid. `env` carries extra marks, e.g.
171
+ * RUN_WINDOW_START_ENV for a `--for` window. `stdio` defaults to `"inherit"` (the child's
172
+ * event stream is what a plain `run` operator sees); `run --tui` passes silent stdio instead,
173
+ * because the observer TUI owns the terminal and the child must not paint over its render. */
174
+ export function spawnRunChild(signal, extraArgs = [], env = {}, stdio = "inherit") {
175
+ // Spawn `run`, never `start`: the supervisor runs the build it started on, but each child
176
+ // loads dist/src/cli.js, which a redeploy replaces with main's newest build. Every build from
177
+ // the `start` rename on accepts `run`, and older builds accept only `run`, so `run` works
178
+ // against whatever build the child meets, even after a rollback; spawning `start` would make
179
+ // an updated supervisor's respawn fail with "unknown command" on a reverted build.
161
180
  return spawnSupervised(["run", ...extraArgs], signal, {
162
181
  [SUPERVISED_ENV]: "1",
163
182
  [SUPERVISOR_PID_ENV]: String(process.pid),
164
- });
183
+ ...env,
184
+ }, stdio);
165
185
  }
166
186
  /** The production dashboard spawner for `run --gui`: a `tumwater gui` child on its defaults,
167
- * stdio shared so a terminal Ctrl+C reaches it exactly as it reaches the orchestrator child.
187
+ * stdio shared so a terminal Ctrl+C reaches it exactly as it reaches the orchestrator child —
188
+ * unless `--tui` is hosted, when the caller passes silent stdio so the dashboard's
189
+ * `tumwater gui at http://…` banner cannot paint over the observer TUI's full-screen render.
168
190
  * `env` carries the caller's mark — in production DASHBOARD_CHILD_ENV naming this supervisor's
169
191
  * pid — so the child's own reload watch (src/redeploy/self-reload.ts) both exits
170
192
  * RESTART_EXIT_CODE for a fresh generation on a redeploy and exits on its own if this supervisor
171
193
  * dies outright (SIGKILL, a crash), freeing the dashboard port. Deliberately not SUPERVISED_ENV:
172
- * the child must run `gui`, not supervise a fleet. Resolves like spawnRunChild — a failed spawn
194
+ * the child must run `gui`, not supervise a team. Resolves like spawnRunChild — a failed spawn
173
195
  * is `{ code: 1, signal: null }` — so an EMFILE/ENOMEM here cannot throw an unhandled 'error'. */
174
- export function spawnGuiChild(signal, env = {}) {
175
- return spawnSupervised(["gui"], signal, env);
196
+ export function spawnGuiChild(signal, env = {}, stdio = "inherit") {
197
+ return spawnSupervised(["gui"], signal, env, stdio);
176
198
  }
177
199
  /** Spawn one supervised child (`commandArgs` after the cli.js script path) and resolve on its
178
200
  * exit, with the abort signal wiring and spawn-failure handling shared by spawnRunChild and
179
201
  * spawnGuiChild: the signal's abort sends SIGTERM, and a spawn that never starts resolves as a
180
202
  * failed exit instead of emitting an unhandled 'error'. */
181
- function spawnSupervised(commandArgs, signal, env) {
203
+ function spawnSupervised(commandArgs, signal, env, stdio = "inherit") {
182
204
  return new Promise((resolve) => {
183
205
  const script = process.argv[1];
184
206
  if (!script) {
@@ -186,7 +208,7 @@ function spawnSupervised(commandArgs, signal, env) {
186
208
  return;
187
209
  }
188
210
  const child = spawn(process.execPath, [script, ...commandArgs], {
189
- stdio: "inherit",
211
+ stdio,
190
212
  env: childEnv(env),
191
213
  });
192
214
  // runOnAbort closes the register/abort race: an already-fired signal kills the child
@@ -1,3 +1,4 @@
1
+ // vocabulary: plain
1
2
  /**
2
3
  * The only backend-specific prompt text (plans/agent-backends.md "What the pi extensions did,
3
4
  * per backend"). Everything else in the prompts already speaks in shell commands and "tool
@@ -10,26 +11,45 @@
10
11
  * where its own tool surface does. Adding a backend means adding one dialect here, not editing
11
12
  * every prompt builder.
12
13
  */
13
- /** pi's dialect: the identity of the prompts before agent backends — its `role_notes` tool,
14
- * its `read` tool's `offset`/`limit`, and its bundled head+tail marker. */
14
+ /** pi's dialect: the identity of the prompts before agent backends — its `read` tool's
15
+ * `offset`/`limit`, and its bundled head+tail marker. */
15
16
  export const PI_DIALECT = {
16
- notesTool: "role_notes",
17
17
  readRange: "the read tool's offset/limit (or `sed -n 'A,Bp'`)",
18
18
  oversizedOutput: `Oversized tool results come back as head+tail around a marker that names the omitted amount
19
19
  and where the full output lives — follow the pointer (re-read with \`offset\`/\`limit\`, or open
20
20
  the full-output file path) instead of retrying the same read.`,
21
21
  };
22
- /** claude's dialect: the `role_notes` MCP server registers as `mcp__tumwater__role_notes`, the
23
- * Read tool takes `offset`/`limit`, and Claude Code truncates oversized Bash output and spills
24
- * large results to a file it names (so it needs no head+tail marker). */
22
+ /** claude's dialect: the Read tool takes `offset`/`limit`, and Claude Code truncates
23
+ * oversized Bash output and spills large results to a file it names (so it needs no head+tail
24
+ * marker). */
25
25
  export const CLAUDE_DIALECT = {
26
- notesTool: "mcp__tumwater__role_notes",
27
26
  readRange: "the Read tool's offset/limit (or `sed -n 'A,Bp'`)",
28
27
  oversizedOutput: `Oversized tool results are truncated and saved to a file the tool names — read that file
29
28
  in ranges (the Read tool's offset/limit) instead of retrying the same read.`,
30
29
  };
31
- /** The dialect for an agent id; every backend but claude speaks pi's dialect (and an unknown
32
- * id falls back to pi because run-agent.ts routes an unregistered id to the pi backend). */
30
+ /** opencode's dialect (plans/opencode-backend.md §5): its read tool takes `offset`/`limit`,
31
+ * its oversized shell output spills to a named file (finding 17), and two backend rules tell
32
+ * the model how OpenCode's shell tool works: a 2-minute default timeout that `timeout`
33
+ * overrides, and no `background` (a backgrounded command dies when the run ends, finding 18). */
34
+ export const OPENCODE_DIALECT = {
35
+ readRange: "the read tool's offset/limit (or `sed -n 'A,Bp'`)",
36
+ oversizedOutput: `Oversized shell output keeps only its last lines, followed by a note naming the file with
37
+ the full output — read that file in ranges (the read tool's offset/limit) instead of
38
+ re-running the command.`,
39
+ backendRules: [
40
+ "Shell commands time out after 2 minutes unless you pass `timeout` in milliseconds; give the project's check a timeout that covers it (for example 900000).",
41
+ "Run every shell command in the foreground: never set `background`, because a background command is killed when your run ends.",
42
+ ],
43
+ };
44
+ /** The dialect table keyed by backend id: every backend but claude speaks pi's dialect (and
45
+ * an unknown id falls back to pi because run-agent.ts routes an unregistered id to the pi
46
+ * backend). Adding a backend means one row here, not another branch. */
47
+ const DIALECTS = {
48
+ pi: PI_DIALECT,
49
+ claude: CLAUDE_DIALECT,
50
+ opencode: OPENCODE_DIALECT,
51
+ };
52
+ /** The dialect for an agent id, read from the per-backend table. */
33
53
  export function dialectFor(agent) {
34
- return agent === "claude" ? CLAUDE_DIALECT : PI_DIALECT;
54
+ return DIALECTS[agent ?? "pi"] ?? PI_DIALECT;
35
55
  }