tumwater 0.2.0 → 0.4.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.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +55 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +6 -4
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +404 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +281 -55
- package/dist/src/backlog/backlog-cli-view.js +255 -0
- package/dist/src/backlog/backlog-cli.js +91 -335
- package/dist/src/backlog/backlog-commit.js +20 -13
- package/dist/src/backlog/backlog-eligibility.js +193 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +264 -0
- package/dist/src/backlog/backlog-release.js +134 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-guardrails.js +136 -0
- package/dist/src/baseline/main-red.js +153 -36
- package/dist/src/baseline/main-watch.js +232 -0
- package/dist/src/brief/brief-edit.js +12 -12
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget-fallback-view.js +288 -0
- package/dist/src/budget/budget-wiring.js +158 -0
- package/dist/src/budget/budget.js +31 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +65 -3
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +181 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +183 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +291 -598
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-review-commands.js +113 -0
- package/dist/src/cli/cli-role-command.js +525 -0
- package/dist/src/cli/cli-start-summary.js +167 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +193 -237
- package/dist/src/cli/completion.js +169 -22
- package/dist/src/cli/config-commands.js +58 -26
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +258 -82
- package/dist/src/cli/log-commands.js +164 -85
- package/dist/src/cli/question-commands.js +211 -10
- package/dist/src/cli.js +173 -45
- package/dist/src/collections.js +56 -13
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +16 -1
- package/dist/src/config/config-fallbacks.js +94 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +169 -222
- package/dist/src/config/config-views.js +136 -54
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +164 -265
- package/dist/src/config/config.js +53 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +330 -0
- package/dist/src/doctor/doctor-backlog-plans.js +398 -0
- package/dist/src/doctor/doctor-backlog.js +249 -512
- package/dist/src/doctor/doctor-check-names.js +85 -0
- package/dist/src/doctor/doctor-checks.js +61 -593
- package/dist/src/doctor/doctor-claude-checks.js +142 -0
- package/dist/src/doctor/doctor-codex-checks.js +276 -0
- package/dist/src/doctor/doctor-contention-checks.js +506 -0
- package/dist/src/doctor/doctor-fallback-checks.js +130 -0
- package/dist/src/doctor/doctor-holds.js +80 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +216 -537
- package/dist/src/doctor/doctor-notify.js +9 -5
- package/dist/src/doctor/doctor-opencode-checks.js +164 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-pi-checks.js +62 -0
- package/dist/src/doctor/doctor-project-checks.js +397 -0
- package/dist/src/doctor/doctor.js +126 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +21 -12
- package/dist/src/events/event-format.js +185 -89
- package/dist/src/events/event-labels.js +11 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +52 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +80 -26
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +65 -60
- package/dist/src/failure/failure-render.js +29 -21
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +35 -35
- package/dist/src/files/file-queue.js +17 -0
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +88 -225
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +101 -143
- package/dist/src/gates/maintenance-quota.js +37 -30
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +89 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +54 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +43 -19
- package/dist/src/gui/gui-backlog-endpoints.js +156 -0
- package/dist/src/gui/gui-command.js +26 -13
- package/dist/src/gui/gui-config-commands.js +168 -80
- package/dist/src/gui/gui-endpoint-commands.js +5 -4
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +235 -13
- package/dist/src/gui/gui-prompt-commands.js +26 -20
- package/dist/src/gui/gui-report-endpoints.js +97 -0
- package/dist/src/gui/gui-server.js +26 -5
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +155 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +190 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +28 -17
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +58 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +45 -19
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +214 -0
- package/dist/src/merge/merge-queue-render.js +48 -11
- package/dist/src/merge/merge-queue.js +52 -15
- package/dist/src/merge/merge-requeue.js +103 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +27 -11
- package/dist/src/merge/merge-to-main.js +77 -26
- package/dist/src/merge/merge-top.js +83 -0
- package/dist/src/merge/merge-verify.js +75 -18
- package/dist/src/notes-cli.js +35 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +352 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +71 -370
- package/dist/src/orchestrator/orchestrator.js +129 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +245 -0
- package/dist/src/orchestrator/scheduling-skip.js +195 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +126 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +26 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +150 -217
- package/dist/src/prompt/notes-backlog.js +184 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +131 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +188 -124
- package/dist/src/report/report-fold.js +130 -54
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +136 -65
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +23 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/diff-rules.js +53 -0
- package/dist/src/review/known-flakes.js +112 -1
- package/dist/src/review/post-merge-review-accept.js +51 -0
- package/dist/src/review/post-merge-review-render.js +112 -0
- package/dist/src/review/post-merge-review.js +239 -0
- package/dist/src/review/protected-edits.js +24 -10
- package/dist/src/review/quarantine-render.js +65 -0
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +180 -401
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +127 -12
- package/dist/src/roles/role-guidance.js +65 -20
- package/dist/src/roles/role-labels.js +7 -5
- package/dist/src/roles/role-render.js +108 -56
- package/dist/src/roles/role-view.js +95 -56
- package/dist/src/roles/roles.js +33 -33
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/ci-parity.js +121 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/run/qa-coverage.js +125 -0
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +175 -0
- package/dist/src/run/run-detail-render.js +91 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +73 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +122 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +170 -83
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +105 -57
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +178 -0
- package/dist/src/run/stage-checks-shared.js +65 -0
- package/dist/src/run/stage-name-checks.js +204 -0
- package/dist/src/run/stage-path-checks.js +231 -0
- package/dist/src/run/stage-prose-checks.js +261 -0
- package/dist/src/runner/leftover.js +216 -0
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +191 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +109 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +39 -18
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +236 -245
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +103 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claim-entries.js +49 -0
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +49 -17
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +43 -28
- package/dist/src/status/status-roles.js +50 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +7 -8
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +65 -18
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +60 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +78 -13
- package/dist/src/ui/badges.js +99 -38
- package/dist/src/ui/gui/gui-client-backlog.js +314 -0
- package/dist/src/ui/gui/gui-client-boot.js +89 -61
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +254 -0
- package/dist/src/ui/gui/gui-client-drawer.js +155 -289
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +437 -68
- package/dist/src/ui/gui/gui-client-labels.js +6 -3
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +60 -52
- package/dist/src/ui/gui/gui-client-pending.js +405 -24
- package/dist/src/ui/gui/gui-client-report-chart.js +492 -0
- package/dist/src/ui/gui/gui-client-report.js +105 -430
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +163 -5
- package/dist/src/ui/gui/gui-client-team.js +36 -465
- package/dist/src/ui/gui/gui-client.js +38 -26
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +10 -7
- package/dist/src/ui/gui/gui-styles.js +38 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +33 -32
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +364 -49
- package/dist/src/ui/status-render.js +109 -82
- package/dist/src/ui/team-alerts.js +728 -62
- package/dist/src/ui/tone.js +12 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +53 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +4 -12
- package/dist/src/ui/tui/tui-editor-backends.js +127 -0
- package/dist/src/ui/tui/tui-editor-brief.js +14 -36
- package/dist/src/ui/tui/tui-editor-budget.js +36 -39
- package/dist/src/ui/tui/tui-editor-check.js +29 -0
- package/dist/src/ui/tui/tui-editor-checks.js +28 -0
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +25 -0
- package/dist/src/ui/tui/tui-editor-config.js +99 -0
- package/dist/src/ui/tui/tui-editor-entry.js +39 -64
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +46 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +117 -0
- package/dist/src/ui/tui/tui-editor-interval.js +29 -16
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +9 -29
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +95 -41
- package/dist/src/ui/tui/tui-editor-retire.js +5 -13
- package/dist/src/ui/tui/tui-editor-role-enabled.js +126 -0
- package/dist/src/ui/tui/tui-editor-role-key.js +71 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +101 -34
- package/dist/src/ui/tui/tui-editor-slots.js +24 -0
- package/dist/src/ui/tui/tui-editors.js +44 -2
- package/dist/src/ui/tui/tui-frame.js +68 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +33 -9
- package/dist/src/ui/tui/tui-pane-activity.js +35 -19
- package/dist/src/ui/tui/tui-pane-backlog.js +198 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +168 -8
- package/dist/src/ui/tui/tui-pane-history.js +446 -82
- package/dist/src/ui/tui/tui-pane-pending.js +539 -15
- package/dist/src/ui/tui/tui-pane-queued.js +78 -57
- package/dist/src/ui/tui/tui-pane-report.js +54 -16
- package/dist/src/ui/tui/tui-pane-session.js +34 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +91 -28
- package/dist/src/ui/tui/tui-panes.js +153 -34
- package/dist/src/ui/tui/tui.js +18 -15
- package/dist/src/verdict/fix-claim.js +129 -33
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +77 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/leftover.js +0 -130
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/qa-coverage.js +0 -108
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
import { knownRoleIds, loadConfig } from "../config/config.js";
|
|
1
|
+
import { knownRoleIds, knownRoleIdsCached, loadConfig } from "../config/config.js";
|
|
3
2
|
import { fail, say, sayJson } from "../cli/cli-output.js";
|
|
4
|
-
import { failOverDurationCap, flagValue, parseDurationFlag, parseRoleFlag } from "../cli/cli-args.js";
|
|
5
|
-
import { errorMessage } from "../text/text.js";
|
|
3
|
+
import { failOverDurationCap, flagValue, parseCountFlag, parseDurationFlag, parseRoleFlag } from "../cli/cli-args.js";
|
|
4
|
+
import { errorMessage, splitCommaList } from "../text/text.js";
|
|
6
5
|
import { PAUSE_FOR_OVERFLOW_HINT, REASON_VALUE_ERROR, ROLE_VALUE_ERROR } from "../cli/cli-flag-specs.js";
|
|
7
6
|
import { artifactPhrase, hasRetirableLeftovers, previewRetire, retireRole } from "./retire.js";
|
|
8
|
-
import { revertMergedCommit } from "./revert.js";
|
|
7
|
+
import { previewRevert, revertFollowUp, revertMergedCommit, runRevertSha } from "./revert.js";
|
|
8
|
+
import { runNotFoundMessage } from "../run/run-detail.js";
|
|
9
|
+
import { readRunDetail } from "../run/run-detail-data.js";
|
|
10
|
+
import { readRunRows } from "../history/history-data.js";
|
|
11
|
+
import { canonicalRoleId } from "../roles/legacy-role-ids.js";
|
|
9
12
|
import { agree, plural, teamResumePhrase, pauseReasonSuffix } from "../text/phrases.js";
|
|
10
13
|
import { errCode } from "../errno.js";
|
|
11
14
|
import { shortSha } from "../text/format.js";
|
|
12
|
-
import { INSTANCE_ROLES } from "../roles/
|
|
15
|
+
import { INSTANCE_ROLES } from "../roles/runner-ids.js";
|
|
13
16
|
import { allRoleIds, unknownRoleMessage } from "../roles/roles.js";
|
|
14
17
|
import { normalizePauseReason, pauseTeam, pauseRole, pausedRoles, resumeTeam, resumeRole, } from "../team/team-state.js";
|
|
15
18
|
import { readOrchestratorInfo } from "../team/orchestrator-info.js";
|
|
@@ -21,15 +24,15 @@ import { markerApplyNote, NO_HARNESS_ERROR, PAUSE_FOR_MAX_MS, cancelScheduledSto
|
|
|
21
24
|
* live beside their shared `--role` resolution. The marker-writing cores and shared
|
|
22
25
|
* confirmations they print live in src/operator/operator-intent.ts (shared with the
|
|
23
26
|
* dashboard and TUI); the team-side consumer half is src/operator/operator-requests.ts;
|
|
24
|
-
* the `prompt` command, which drives the durable per-
|
|
27
|
+
* the `prompt` command, which drives the durable per-role queues rather than the marker
|
|
25
28
|
* protocol, lives beside them in src/inbox/prompt-commands.ts, and the `config` command,
|
|
26
29
|
* which reads and writes tumwater.json directly rather than touching team state, in
|
|
27
30
|
* src/cli/config-commands.ts. Every command here is deliberately usable without a live
|
|
28
31
|
* harness except `abort` and `stop`, which have nothing to reach when no team is up. */
|
|
29
32
|
/** The `--role <id>` value when given, resolved WITHOUT tumwater.json when it names a
|
|
30
33
|
* built-in catalog role: the team itself tolerates a broken config (the live reload keeps
|
|
31
|
-
* the last-known-good one), so an operator marker aimed at a built-in
|
|
32
|
-
* on the file parsing — the same resilience `logs --
|
|
34
|
+
* the last-known-good one), so an operator marker aimed at a built-in role must not depend
|
|
35
|
+
* on the file parsing — the same resilience `logs --transcript` already has. A custom-role id or
|
|
33
36
|
* an unknown id falls through to the config-backed check, which fails with the honest error
|
|
34
37
|
* (the config problem, or "unknown role" naming every valid id). Returns null when no
|
|
35
38
|
* --role is given. */
|
|
@@ -46,17 +49,41 @@ function namedRole(root, args) {
|
|
|
46
49
|
fail(errorMessage(err)); // same message main().catch would print, but via the standard fail()
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
|
-
/**
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
/** The trimmed, non-empty pieces of a comma-separated `--role` value; null when `--role` is
|
|
53
|
+
* absent, and a failure with ROLE_VALUE_ERROR when no piece remains (bare `--role`, `,`). */
|
|
54
|
+
function rolePieces(args) {
|
|
55
|
+
const value = flagValue(args, "--role");
|
|
56
|
+
if (value === null)
|
|
57
|
+
return null;
|
|
58
|
+
const pieces = splitCommaList(value ?? "");
|
|
59
|
+
if (pieces.length === 0)
|
|
60
|
+
fail(ROLE_VALUE_ERROR);
|
|
61
|
+
return pieces;
|
|
62
|
+
}
|
|
63
|
+
/** namedRole over a comma list (`--role clean,dedupe`): every piece resolves through namedRole
|
|
64
|
+
* before the caller writes anything, so a bad id writes no marker. Deduplicated in first-seen
|
|
65
|
+
* order; null when `--role` is absent. */
|
|
66
|
+
function namedRoleList(root, args) {
|
|
67
|
+
const pieces = rolePieces(args);
|
|
68
|
+
if (pieces === null)
|
|
69
|
+
return null;
|
|
70
|
+
return [...new Set(pieces.map((piece) => namedRole(root, ["--role", piece])))];
|
|
71
|
+
}
|
|
72
|
+
/** namedRole for the commands that write or lift the per-role pause marker, over a comma list
|
|
73
|
+
* (`--role clean,dedupe`, like `history --role`): `feature-1` (`bugfix-1`) is the pause key of
|
|
74
|
+
* instance 1 of a multi-instance role (src/roles/runner-ids.ts's instancePauseKey), kept
|
|
75
|
+
* verbatim; every other piece resolves through namedRole. Every piece resolves before the
|
|
76
|
+
* caller writes anything, so a bad id writes no marker. Deduplicated in first-seen order;
|
|
77
|
+
* null when `--role` is absent. */
|
|
78
|
+
function pauseTargetRoles(root, args) {
|
|
79
|
+
const pieces = rolePieces(args);
|
|
80
|
+
if (pieces === null)
|
|
81
|
+
return null;
|
|
82
|
+
const roles = pieces.map((piece) => [...INSTANCE_ROLES].some((base) => piece === `${base}-1`) ? piece : namedRole(root, ["--role", piece]));
|
|
83
|
+
return [...new Set(roles)];
|
|
57
84
|
}
|
|
58
85
|
/** The `--role <id>` value a marker command requires: namedRole's resolution plus the
|
|
59
|
-
* command-specific "requires --role" failure.
|
|
86
|
+
* command-specific "requires --role" failure. retire needs a target (unlike
|
|
60
87
|
* reset-counters/resume/wake, which default to every role), so the guard lives here once and
|
|
61
88
|
* names the calling command in the error. */
|
|
62
89
|
function requiredNamedRole(root, args, command) {
|
|
@@ -65,27 +92,26 @@ function requiredNamedRole(root, args, command) {
|
|
|
65
92
|
fail(`${command} requires --role <id> (e.g. \`--role feature\`)`);
|
|
66
93
|
return role;
|
|
67
94
|
}
|
|
68
|
-
/** The role(s) a marker command targets: the `--role <id
|
|
69
|
-
* role in the config. reset-counters and wake share the same all-roles
|
|
70
|
-
* here once instead of drifting between their bodies. */
|
|
95
|
+
/** The role(s) a marker command targets: the `--role <id>[,<id>...]` value when given,
|
|
96
|
+
* otherwise every role in the config. reset-counters and wake share the same all-roles
|
|
97
|
+
* default, so it lives here once instead of drifting between their bodies. */
|
|
71
98
|
function targetRoles(root, args) {
|
|
72
|
-
|
|
73
|
-
return role ? [role] : Object.keys(loadConfig(root).roles);
|
|
99
|
+
return namedRoleList(root, args) ?? Object.keys(loadConfig(root).roles);
|
|
74
100
|
}
|
|
75
|
-
/** `tumwater reset-counters [--role <id>]`: zero the per-
|
|
101
|
+
/** `tumwater reset-counters [--role <id>[,<id>...]]`: zero the per-role counters shown in the
|
|
76
102
|
* dashboards so a fresh observation window can begin. Scheduling fields and pi session
|
|
77
|
-
* continuity are untouched:
|
|
103
|
+
* continuity are untouched: roles keep sleeping/waking exactly as before. */
|
|
78
104
|
export async function cmdResetCounters(root, args) {
|
|
79
105
|
say(requestResetCounters(root, targetRoles(root, args)));
|
|
80
106
|
}
|
|
81
|
-
/** `tumwater wake [--role <id>] [--in <duration> | --cancel | --list [--json]]`: tell the
|
|
82
|
-
* team "whatever the
|
|
107
|
+
/** `tumwater wake [--role <id>[,<id>...]] [--in <duration> | --cancel | --list [--json]]`: tell the
|
|
108
|
+
* team "whatever the roles were failing on is fixed — try again", so the named roles run
|
|
83
109
|
* within one poll instead of
|
|
84
110
|
* sleeping until their backoff expires. With `--in`, the wake is scheduled: the marker is
|
|
85
111
|
* written now but consumed no earlier than now + duration, the same shape `pause --for`'s
|
|
86
112
|
* auto-resume takes — the wake applies at the deadline, not at submit. With `--cancel`, the
|
|
87
|
-
* pending scheduled wakes (or the named
|
|
88
|
-
* written. With `--list`, every pending scheduled wake (or the named
|
|
113
|
+
* pending scheduled wakes (or the named roles' share) are dropped instead; no wake is
|
|
114
|
+
* written. With `--list`, every pending scheduled wake (or the named roles')
|
|
89
115
|
* is printed, earliest first — `--json` as an array of {roles, atMs}; read-only. */
|
|
90
116
|
export async function cmdWake(root, args) {
|
|
91
117
|
// `--in <duration>` (the scheduled wake): the command's own gate (runMarkerCommand's
|
|
@@ -99,9 +125,9 @@ export async function cmdWake(root, args) {
|
|
|
99
125
|
if (inRaw !== null || args.includes("--cancel"))
|
|
100
126
|
fail("wake --list cannot be combined with --in or --cancel");
|
|
101
127
|
const now = Date.now();
|
|
102
|
-
const
|
|
103
|
-
const wakes = listWakes(root,
|
|
104
|
-
say(args.includes("--json") ? JSON.stringify(wakes) : renderWakeList(wakes, now,
|
|
128
|
+
const roles = namedRoleList(root, args) ?? undefined;
|
|
129
|
+
const wakes = listWakes(root, roles, now);
|
|
130
|
+
say(args.includes("--json") ? JSON.stringify(wakes) : renderWakeList(wakes, now, roles));
|
|
105
131
|
return;
|
|
106
132
|
}
|
|
107
133
|
if (args.includes("--json"))
|
|
@@ -109,29 +135,36 @@ export async function cmdWake(root, args) {
|
|
|
109
135
|
if (args.includes("--cancel")) {
|
|
110
136
|
if (inRaw !== null)
|
|
111
137
|
fail("wake --cancel and --in cannot be combined");
|
|
112
|
-
|
|
113
|
-
say(cancelWakes(root, role ?? undefined));
|
|
138
|
+
say(cancelWakes(root, namedRoleList(root, args) ?? undefined));
|
|
114
139
|
return;
|
|
115
140
|
}
|
|
116
141
|
const inMs = inRaw !== null ? parseDurationFlag("wake --in", inRaw) : undefined;
|
|
117
142
|
if (inMs !== undefined)
|
|
118
143
|
failOverDurationCap("wake --in", inMs, PAUSE_FOR_MAX_MS);
|
|
119
144
|
// requestWake takes the duration, not a deadline: it reads the clock once for both the
|
|
120
|
-
// marker's deadline and its "wakes in" phrase, so no
|
|
145
|
+
// marker's deadline and its "wakes in" phrase, so no clock advance between two reads can reword
|
|
121
146
|
// "45m" as "2699999ms".
|
|
122
147
|
say(requestWake(root, targetRoles(root, args), inMs));
|
|
123
148
|
}
|
|
124
|
-
/** `tumwater reclaim [--dry-run]`: run one manual reclaim pass over every harness
|
|
125
|
-
* (plans/disk-floor.md, part 3/4). `--dry-run` lists each candidate with its idle
|
|
126
|
-
* many ignored paths `git clean -ndX` would remove, and changes nothing — it
|
|
127
|
-
* worktree nor writes the worktree-use registry
|
|
128
|
-
* pass is requested through the marker the orchestrator
|
|
129
|
-
* respected; with none running it runs in-process, since
|
|
149
|
+
/** `tumwater reclaim [--dry-run [--json]]`: run one manual reclaim pass over every harness
|
|
150
|
+
* worktree (plans/disk-floor.md, part 3/4). `--dry-run` lists each candidate with its idle
|
|
151
|
+
* age and how many ignored paths `git clean -ndX` would remove, and changes nothing — it
|
|
152
|
+
* neither cleans a worktree nor writes the worktree-use registry; `--json` prints those rows
|
|
153
|
+
* as data. With a live team the pass is requested through the marker the orchestrator
|
|
154
|
+
* consumes, so in-use worktrees are respected; with none running it runs in-process, since
|
|
155
|
+
* nothing is in use. */
|
|
130
156
|
export async function cmdReclaim(root, args) {
|
|
131
157
|
const dryRun = args.includes("--dry-run");
|
|
158
|
+
const json = args.includes("--json");
|
|
159
|
+
if (json && !dryRun)
|
|
160
|
+
fail("reclaim --json requires --dry-run");
|
|
132
161
|
const idleHours = loadConfig(root).worktreeIdleReclaimHours;
|
|
133
162
|
if (dryRun) {
|
|
134
163
|
const candidates = await inspectReclaimCandidates(root, idleHours);
|
|
164
|
+
if (json) {
|
|
165
|
+
sayJson({ dryRun: true, idleReclaimHours: idleHours, candidates });
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
135
168
|
if (candidates.length === 0) {
|
|
136
169
|
say("nothing to reclaim — no reclaimable worktrees");
|
|
137
170
|
return;
|
|
@@ -149,20 +182,23 @@ export async function cmdReclaim(root, args) {
|
|
|
149
182
|
}
|
|
150
183
|
say(await runManualReclaim(root));
|
|
151
184
|
}
|
|
152
|
-
/** `tumwater abort --role <id
|
|
185
|
+
/** `tumwater abort --role <id>[,<id>...]`: kill the named roles' in-flight runs right now (a
|
|
186
|
+
* comma list writes one marker per role). The CLI cannot
|
|
153
187
|
* reach into the orchestrator process, so the request rides on disk like reset-counters':
|
|
154
188
|
* a per-role marker file a running team consumes within one poll cycle (the runner's
|
|
155
|
-
*
|
|
156
|
-
* with no team there is nothing to consume the marker. The
|
|
157
|
-
* off normally and later
|
|
189
|
+
* abortRun kills the pi child and resets the worktree to main). Requires a live harness —
|
|
190
|
+
* with no team there is nothing to consume the marker. The role stays enabled: it backs
|
|
191
|
+
* off normally and later runs proceed as usual. */
|
|
158
192
|
export async function cmdAbort(root, args) {
|
|
159
193
|
// As in cmdLogs: the config exists only to validate the id against built-ins plus
|
|
160
|
-
// user-defined
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
194
|
+
// user-defined roles; a missing --role fails before it is ever needed.
|
|
195
|
+
const roles = namedRoleList(root, args) ?? fail("abort requires --role <id> (e.g. `--role feature`)");
|
|
196
|
+
for (const role of roles) {
|
|
197
|
+
const result = requestAbort(root, role);
|
|
198
|
+
if (!result.ok)
|
|
199
|
+
fail(result.error);
|
|
200
|
+
say(result.message);
|
|
201
|
+
}
|
|
166
202
|
}
|
|
167
203
|
/** `tumwater restart`: apply a pending self-redeploy now, waiving the restart cooldown —
|
|
168
204
|
* the terminal twin of the dashboard update alert's refresh button (POST /api/restart,
|
|
@@ -175,9 +211,10 @@ export async function cmdRestart(root, _args) {
|
|
|
175
211
|
fail(result.error);
|
|
176
212
|
say(result.message);
|
|
177
213
|
}
|
|
178
|
-
/** `tumwater pause [--role <id>] [--for <duration>]`: with a
|
|
179
|
-
*
|
|
180
|
-
*
|
|
214
|
+
/** `tumwater pause [--role <id>[,<id>...]] [--for <duration>]`: with roles (a comma list pauses
|
|
215
|
+
* each), stop THAT role from
|
|
216
|
+
* starting new runs — in-flight ones finish, every other role (the director included)
|
|
217
|
+
* keeps running; without one, stop every role from starting NEW runs while in-flight
|
|
181
218
|
* ones finish and the director keeps running (its prompts outrank operator gates, like
|
|
182
219
|
* under the budget cap). The markers
|
|
183
220
|
* are persistent state, not one-shot requests: presence means paused until `resume` removes
|
|
@@ -212,8 +249,8 @@ export async function cmdPause(root, args = [], now = Date.now()) {
|
|
|
212
249
|
// discipline timedPauseBits's own `now` parameter follows.
|
|
213
250
|
const timed = forMs === undefined ? undefined : { ms: forMs, untilMs: now + forMs };
|
|
214
251
|
const untilMs = timed?.untilMs;
|
|
215
|
-
const
|
|
216
|
-
if (
|
|
252
|
+
const roles = pauseTargetRoles(root, args);
|
|
253
|
+
if (roles) {
|
|
217
254
|
// The plan keeps per-role pauses anonymous (a per-role reason would need a per-role map
|
|
218
255
|
// for no observed need), so a reason aimed at a role pause fails fast here — accepting
|
|
219
256
|
// the flag and silently dropping the note would tell the operator the reason stands
|
|
@@ -225,7 +262,8 @@ export async function cmdPause(root, args = [], now = Date.now()) {
|
|
|
225
262
|
// the CLI, TUI, and GUI cannot drift on format or idempotence; a false return means the
|
|
226
263
|
// role was already in the set, which rolePauseMessage words — unless a `--for` stands,
|
|
227
264
|
// which overwrites the deadline and reports the fresh confirmation.
|
|
228
|
-
|
|
265
|
+
for (const role of roles)
|
|
266
|
+
say(rolePauseMessage(root, role, pauseRole(root, role, untilMs), timed, now));
|
|
229
267
|
return;
|
|
230
268
|
}
|
|
231
269
|
// pauseTeam in src/team/team-state.ts is the single writer of the pause marker — the GUI's
|
|
@@ -263,7 +301,7 @@ export function signalOrchestrator(pid) {
|
|
|
263
301
|
throw err;
|
|
264
302
|
}
|
|
265
303
|
}
|
|
266
|
-
/** `tumwater stop`: SIGTERM the running orchestrator, which drains its in-flight
|
|
304
|
+
/** `tumwater stop`: SIGTERM the running orchestrator, which drains its in-flight runs and
|
|
267
305
|
* exits — exactly the shutdown the supervised child's own SIGINT/SIGTERM handler performs, so
|
|
268
306
|
* Ctrl+C and `stop` from another terminal are the same code path (the supervisor needs no
|
|
269
307
|
* signal of its own: a clean child exit already ends its loop). Unlike the marker commands
|
|
@@ -303,17 +341,19 @@ export async function cmdStop(root, args = []) {
|
|
|
303
341
|
else
|
|
304
342
|
say("the orchestrator exited before the stop signal arrived — nothing is running");
|
|
305
343
|
}
|
|
306
|
-
/** `tumwater resume [--role <id>]`: with a
|
|
307
|
-
* per-role marker set); without one,
|
|
308
|
-
*
|
|
309
|
-
*
|
|
344
|
+
/** `tumwater resume [--role <id>[,<id>...]]`: with roles (a comma list lifts
|
|
345
|
+
* each), lift that role's pause (removed from the per-role marker set); without one,
|
|
346
|
+
* lift a team pause by removing its marker. Idempotent like pause: with no marker there
|
|
347
|
+
* is nothing to do. No live harness required — resuming before startup just means the
|
|
348
|
+
* next `tumwater run` starts unpaused. */
|
|
310
349
|
export async function cmdResume(root, args = []) {
|
|
311
|
-
const
|
|
312
|
-
if (
|
|
350
|
+
const roles = pauseTargetRoles(root, args);
|
|
351
|
+
if (roles) {
|
|
313
352
|
// resumeRole (src/team/team-state.ts) is the single remover of the per-role marker; a false
|
|
314
353
|
// return means the role was never paused — the changed-state contract roleResumeMessage
|
|
315
354
|
// words ("is already paused" vs "was not paused").
|
|
316
|
-
|
|
355
|
+
for (const role of roles)
|
|
356
|
+
say(roleResumeMessage(root, role, resumeRole(root, role)));
|
|
317
357
|
return;
|
|
318
358
|
}
|
|
319
359
|
// resumeTeam (src/team/team-state.ts) is the single remover, shared with the GUI toggle;
|
|
@@ -325,7 +365,7 @@ export async function cmdResume(root, args = []) {
|
|
|
325
365
|
const { when, tail } = markerApplyNote(root);
|
|
326
366
|
// The per-role pause outlives a team resume (the markers are independent), so the resumed
|
|
327
367
|
// team's confirmation must name the roles still individually paused instead of claiming
|
|
328
|
-
// "
|
|
368
|
+
// "roles run again" for roles the scheduler keeps gated.
|
|
329
369
|
const still = pausedRoles(root);
|
|
330
370
|
const roleNote = still.length > 0
|
|
331
371
|
? ` (${still.join(", ")} ${agree(still.length, "is", "are")} still individually paused — \`tumwater resume --role <id>\` lifts each)`
|
|
@@ -333,7 +373,7 @@ export async function cmdResume(root, args = []) {
|
|
|
333
373
|
say(`${teamResumePhrase()}${when}${roleNote}${tail}`);
|
|
334
374
|
}
|
|
335
375
|
/** The role id retire targets: a built-in or configured id as for the other marker commands, or
|
|
336
|
-
* else any well-formed id that still has a branch or merge ref (a
|
|
376
|
+
* else any well-formed id that still has a branch or merge ref (a role no config names). */
|
|
337
377
|
async function retireTargetRole(root, args) {
|
|
338
378
|
const role = flagValue(args, "--role");
|
|
339
379
|
if (role === null)
|
|
@@ -353,12 +393,12 @@ async function retireTargetRole(root, args) {
|
|
|
353
393
|
return role;
|
|
354
394
|
fail(unknownRoleMessage(role, ids));
|
|
355
395
|
}
|
|
356
|
-
/** `tumwater retire --role <id> [--force] [--json]`: remove a disabled
|
|
396
|
+
/** `tumwater retire --role <id> [--force] [--json]`: remove a disabled role's leftover worktree,
|
|
357
397
|
* branch, merge ref, and paused-state marker. The collection, safety rails, and removal live in
|
|
358
398
|
* src/operator/retire.ts; this is the render layer — one line per removed artifact, the skip lines
|
|
359
399
|
* that make a second run idempotent, or the `--json` payload. */
|
|
360
400
|
export async function cmdRetire(root, args) {
|
|
361
|
-
// The config exists only to validate the id against built-ins plus user-defined
|
|
401
|
+
// The config exists only to validate the id against built-ins plus user-defined roles, with
|
|
362
402
|
// the leftover-branch gate for ids no config names; a missing --role fails before it is needed.
|
|
363
403
|
const role = await retireTargetRole(root, args);
|
|
364
404
|
const force = args.includes("--force");
|
|
@@ -395,24 +435,95 @@ export async function cmdRetire(root, args) {
|
|
|
395
435
|
if (result.removed.length === 0 && result.skipped.length === 0)
|
|
396
436
|
say(`nothing to remove for role ${role}`);
|
|
397
437
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
*
|
|
401
|
-
*
|
|
438
|
+
const REVERT_USAGE = "usage: tumwater revert <sha>|<role> <n>|<role> --last [--dry-run] [--json]";
|
|
439
|
+
/** The sha the run `<role> <n>` (or the newest completed run of `<role>` under `last`) merged
|
|
440
|
+
* under, resolved the way `tumwater history <role> <n>` and the dashboard's revert resolve it
|
|
441
|
+
* (`runMergedSha`). Fails, exit 1, when the run is unknown or did not merge: revert is an
|
|
442
|
+
* action, so a miss is an error rather than history's exit-0 "not found". */
|
|
443
|
+
function revertRunSha(root, positionals, last) {
|
|
444
|
+
const role = canonicalRoleId(positionals[0]);
|
|
445
|
+
const ids = knownRoleIdsCached(root);
|
|
446
|
+
if (!ids.includes(role))
|
|
447
|
+
fail(`${unknownRoleMessage(role, ids)} (${REVERT_USAGE})`);
|
|
448
|
+
const run = last
|
|
449
|
+
? (readRunRows(root, 1, role)[0]?.run ?? null)
|
|
450
|
+
: parseCountFlag("revert <n>", positionals[1]);
|
|
451
|
+
if (run === null)
|
|
452
|
+
fail(`no completed run of ${role} in the event log`);
|
|
453
|
+
const detail = readRunDetail(root, role, run);
|
|
454
|
+
if (detail === null)
|
|
455
|
+
fail(runNotFoundMessage(role, run));
|
|
456
|
+
const found = runRevertSha(role, run, detail);
|
|
457
|
+
if (!found.ok)
|
|
458
|
+
fail(found.error);
|
|
459
|
+
const sha = found.sha;
|
|
460
|
+
return { sha, line: `run ${role} #${run} merged as ${shortSha(sha)}`, role, run };
|
|
461
|
+
}
|
|
462
|
+
/** `tumwater revert <sha>|<role> <n>|<role> --last`: undo one merged change on main,
|
|
463
|
+
* committing the inverse as `tumwater(operator): Revert <short sha>` under the primary-worktree
|
|
464
|
+
* lock. The lock, branch guard, and fail-closed ref/conflict handling live in
|
|
465
|
+
* src/operator/revert.ts; this renderer names the new main head and names the role
|
|
466
|
+
* that made the reverted commit, when one did, as the one that may redo the work.
|
|
467
|
+
* `--json` prints the preview or the revert as one JSON object instead (refusals still fail on
|
|
468
|
+
* stderr). */
|
|
402
469
|
export async function cmdRevert(root, args) {
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
|
|
470
|
+
// `--dry-run` and `--last` are the only flags; the positionals select a sha (one), a run
|
|
471
|
+
// (`<role> <n>`) or the newest run of a role (`<role>` with --last). A flag or any other
|
|
472
|
+
// shape fails before anything is looked up or written.
|
|
473
|
+
const dryRun = args.includes("--dry-run");
|
|
474
|
+
const last = args.includes("--last");
|
|
475
|
+
const json = args.includes("--json");
|
|
476
|
+
const rest = args.filter((a) => a !== "--dry-run" && a !== "--last" && a !== "--json");
|
|
407
477
|
// A flag-shaped token is a dropped flag, not a commit: refuse it before rev-parse turns a
|
|
408
478
|
// lone `--json` into the misleading "no such commit". Mirrors `config set`'s
|
|
409
479
|
// flag-looking-value gate and gui-command.ts's --token gate, and a real sha never starts
|
|
410
480
|
// with `-`.
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
481
|
+
const flagged = rest.find((a) => a.startsWith("-"));
|
|
482
|
+
if (flagged !== undefined)
|
|
483
|
+
fail(`revert takes only --dry-run, --last and --json (got ${flagged}); pass the commit or run to undo as the argument`);
|
|
484
|
+
if (last ? rest.length !== 1 : rest.length < 1 || rest.length > 2)
|
|
485
|
+
fail(`revert needs a commit or a run (${REVERT_USAGE})`);
|
|
486
|
+
const run = last || rest.length === 2 ? revertRunSha(root, rest, last) : null;
|
|
487
|
+
const sha = run?.sha ?? rest[0];
|
|
488
|
+
const runLine = run?.line ?? null;
|
|
489
|
+
const runRef = run === null ? null : { role: run.role, run: run.run };
|
|
490
|
+
if (dryRun) {
|
|
491
|
+
const p = await previewRevert(root, sha);
|
|
492
|
+
if (!p.ok)
|
|
493
|
+
fail(p.error);
|
|
494
|
+
if (json) {
|
|
495
|
+
sayJson({ dryRun: true, run: runRef, sha: p.sha, subject: p.subject, paths: p.paths, head: p.head, primary: p.primary, applies: p.applies, dirty: p.dirty });
|
|
496
|
+
if (!p.applies || p.dirty)
|
|
497
|
+
process.exitCode = 1;
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if (runLine !== null)
|
|
501
|
+
say(runLine);
|
|
502
|
+
say(`would revert ${shortSha(p.sha)} ${p.subject}`);
|
|
503
|
+
for (const path of p.paths)
|
|
504
|
+
say(` ${path}`);
|
|
505
|
+
const on = `on ${p.primary} (HEAD ${shortSha(p.head)}); nothing was written`;
|
|
506
|
+
if (p.applies && !p.dirty)
|
|
507
|
+
say(`applies cleanly ${on}`);
|
|
508
|
+
if (!p.applies)
|
|
509
|
+
say(`would conflict ${on}`);
|
|
510
|
+
if (p.dirty)
|
|
511
|
+
say("the checkout has staged or unstaged changes, so tumwater revert would refuse until they are committed or stashed; nothing was written");
|
|
512
|
+
if (!p.applies || p.dirty)
|
|
513
|
+
process.exitCode = 1;
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const result = await revertMergedCommit(root, sha);
|
|
414
517
|
if (!result.ok)
|
|
415
518
|
fail(result.error);
|
|
519
|
+
if (json) {
|
|
520
|
+
sayJson({ dryRun: false, run: runRef, subject: result.subject, headSha: result.headSha, beforeSha: result.beforeSha, followUp: revertFollowUp(result.subject) });
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
if (runLine !== null)
|
|
524
|
+
say(runLine);
|
|
416
525
|
say(`main is now ${shortSha(result.headSha)}`);
|
|
417
|
-
|
|
526
|
+
const followUp = revertFollowUp(result.subject);
|
|
527
|
+
if (followUp !== null)
|
|
528
|
+
say(followUp);
|
|
418
529
|
}
|