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,21 +1,37 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { shortSha } from "../text/format.js";
|
|
3
2
|
import { KILL_BY_PID_RULE, OLDER_NAMES_SENTENCE, TEST_RUNNER_RULE, dateLine } from "./prompt.js";
|
|
4
|
-
import { NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE } from "../roles/role-guidance.js";
|
|
5
3
|
import { describeCheck } from "../build/build-check-report.js";
|
|
6
|
-
import { formatTimestamp } from "../text/datetime.js";
|
|
7
4
|
import { numberedList } from "../text/markdown.js";
|
|
8
|
-
import {
|
|
5
|
+
import { VERDICT_ENDING } from "../verdict/reply-contract.js";
|
|
6
|
+
import { joinParts } from "../text/text.js";
|
|
7
|
+
import { FINISHED_ARCHIVES } from "../backlog/backlog-md.js";
|
|
9
8
|
/** Prompts for the merge gate's pi runs — the runs the merge/review pipeline starts, not the
|
|
10
|
-
*
|
|
11
|
-
* (merge-to-main.ts), the adversarial pre-merge review (review.ts), and the
|
|
12
|
-
* gate's verdicts back to the
|
|
13
|
-
*
|
|
14
|
-
* and detection for parsing a reviewer's VERDICT line — lives in
|
|
9
|
+
* roles' authoring runs (those live in prompt.ts): conflict resolution after a rebase
|
|
10
|
+
* (merge-to-main.ts), the adversarial pre-merge review (review.ts), and the conflict hand-back
|
|
11
|
+
* note. The other notes that carry the gate's verdicts back to the role that authored the
|
|
12
|
+
* change live in gate-notes.ts. The machine-detectable half of the gate's reply contract —
|
|
13
|
+
* verdict constants and detection for parsing a reviewer's VERDICT line — lives in
|
|
14
|
+
* reply-contract.ts. */
|
|
15
15
|
/** The listed-reasons placeholder the review and revision notes share when a rejection recorded
|
|
16
16
|
* none: one home so a revision round's note and the next rejection's note cannot disagree on
|
|
17
17
|
* how an empty objection list reads. */
|
|
18
|
-
const NO_REASONS = "(no reasons recorded)";
|
|
18
|
+
export const NO_REASONS = "(no reasons recorded)";
|
|
19
|
+
/** Check 4's note on how a finished entry reads in the diff. The author pastes it under the live
|
|
20
|
+
* file's finished section, and the commit-time sweep (src/backlog/backlog-archive.ts) moves it
|
|
21
|
+
* to the top of the archive before the gate builds the diff. So a correct change shows the
|
|
22
|
+
* entry leaving PLANS.md or BUGS.md for PLANS-DONE.md or BUGS-FIXED.md. A reviewer that did
|
|
23
|
+
* not know this rejected such changes as misfiled. One change spent all four rounds asking for
|
|
24
|
+
* the entry under PLANS.md's `## Done`, a move the author cannot make stick (2026-10-21).
|
|
25
|
+
* Built from FINISHED_ARCHIVES so the names cannot drift from the sweep's. */
|
|
26
|
+
const ARCHIVE_SWEEP_SENTENCE = (() => {
|
|
27
|
+
const sections = FINISHED_ARCHIVES.map((a) => `${a.file}'s \`## ${a.section}\``).join(" or ");
|
|
28
|
+
const archives = FINISHED_ARCHIVES.map((a) => a.archive).join(" or ");
|
|
29
|
+
return `A finished entry reaches this diff already archived: the author pastes it under
|
|
30
|
+
${sections}, and tumwater's commit-time sweep moves it
|
|
31
|
+
from there to the top of ${archives}, leaving that heading empty. An
|
|
32
|
+
entry that leaves the live file for its archive, closing stamp added, is the expected update,
|
|
33
|
+
not a filing error.`;
|
|
34
|
+
})();
|
|
19
35
|
/** The two labeled blocks that show the resolver what each side meant, framed as data, not
|
|
20
36
|
* instructions, so pi cannot mistake a commit body for a rule. */
|
|
21
37
|
function conflictIntentBlocks(intent) {
|
|
@@ -54,8 +70,8 @@ function conflictedFileLine(file) {
|
|
|
54
70
|
function listsHunks(files) {
|
|
55
71
|
return files.some((f) => typeof f !== "string" && f.hunks.length > 0);
|
|
56
72
|
}
|
|
57
|
-
/** The prompt for resolving merge conflicts left in a
|
|
58
|
-
* resolved check, as the
|
|
73
|
+
/** The prompt for resolving merge conflicts left in a role's worktree. `check` — the project's
|
|
74
|
+
* resolved check, as the run prompt threads it — is named so the resolver knows which command
|
|
59
75
|
* the harness will run (told only to keep the tests passing, the 2026-10-04 resolver guessed
|
|
60
76
|
* `npx vitest run` in a node:test repo, BUGS.md 2026-10-05), and the rules tell it not to run
|
|
61
77
|
* that check itself: merge-to-main.ts's verifyMerge runs it on the resolved tree before
|
|
@@ -125,24 +141,26 @@ ${TEST_RUNNER_RULE}${noCheckRunRule}
|
|
|
125
141
|
/** The prompt for the adversarial pre-merge review gate: a fresh-session pi run that sees only the
|
|
126
142
|
* diff and project context — never the author's session — and replies with exactly one VERDICT
|
|
127
143
|
* line plus numbered reasons (see parseVerdict in src/review/review-verdict.ts).
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* pre-check no green run stands behind the tree, and a reviewer running the suite itself is doing
|
|
135
|
-
* its job. `baseRev` is the frozen revision the diff is measured against (changeBaseRev's
|
|
144
|
+
* The prompt always says tumwater is running the project's own check on this tree (alongside
|
|
145
|
+
* the review, or already done), so the reviewer spends its run on what a green suite cannot show
|
|
146
|
+
* instead of running it. The no-re-run instruction is its own line in the rules list, not a clause
|
|
147
|
+
* in the context paragraph: stated there, reviewers read past it and re-ran the suite in scratch
|
|
148
|
+
* copies under /tmp while holding the merge slot (BUGS.md 2026-09-23). `baseRev` is the frozen
|
|
149
|
+
* revision the diff is measured against (changeBaseRev's
|
|
136
150
|
* merge-base, resolved when the gate builds the diff): the prompt names it and tells the reviewer
|
|
137
|
-
* to compare against it, never `main`, because other
|
|
151
|
+
* to compare against it, never `main`, because other roles merge to main while the review runs
|
|
138
152
|
* (BUGS.md 2026-10-06). Omitted, the prompt keeps the generic "ahead of main" wording. `today` pins
|
|
139
153
|
* the date line (prompt.ts's dateLine) for tests; omitted, it is the local day. The text must
|
|
140
154
|
* contain the literal "VERDICT:" exactly twice — the two advertised forms — because a prompt
|
|
141
155
|
* test derives the accepted forms from it. `priorReview` is present only when this merge is a
|
|
142
156
|
* revision of a previously rejected change (plans/revise-rejected.md part 2/2): it names the round
|
|
143
157
|
* and shows the prior objections plus the interdiff so the re-review checks each one first.
|
|
144
|
-
* Omitted, the prompt is unchanged from a fresh change's.
|
|
145
|
-
|
|
158
|
+
* Omitted, the prompt is unchanged from a fresh change's. `postMerge` marks the post-merge review
|
|
159
|
+
* of a commit already on main (review.afterMerge): a finding the reviewer can repair is the work —
|
|
160
|
+
* it makes the minimal fix in the worktree, leaves the edit, and ends with the verdict line plus a
|
|
161
|
+
* `FIX:` line — so the instruction and the repair rule render only for that caller, and every other
|
|
162
|
+
* (pre-merge) caller's prompt is byte-identical. */
|
|
163
|
+
export function buildReviewPrompt(diff, summary, commitBody, principles, highFriction, baseRev, today, priorReview, knownMainFailures, postMerge) {
|
|
146
164
|
const parts = [
|
|
147
165
|
`You are an adversarial code reviewer for tumwater, which runs a team of AI roles on this project. ${OLDER_NAMES_SENTENCE} A
|
|
148
166
|
role's change is about to be merged to main; you decide whether it may merge. You have no context
|
|
@@ -172,13 +190,23 @@ from a new finding. The prior objections were:\n${list}\nThe interdiff
|
|
|
172
190
|
between the rejected version and this revision (what the revision changed, main's own movement
|
|
173
191
|
excluded):\n<interdiff>\n${priorReview.interdiff}\n</interdiff>`);
|
|
174
192
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
193
|
+
parts.push(`Tumwater is running the project's own check on this tree; do not run the suite. Spend your run
|
|
194
|
+
on what a green check cannot show: wrong behavior the tests never exercise, claims the diff does
|
|
195
|
+
not back, work left half-done.`);
|
|
196
|
+
if (knownMainFailures && knownMainFailures.length > 0)
|
|
197
|
+
parts.push(`Tumwater ran the project's own check on this tree and it failed, but only on tests main already
|
|
198
|
+
fails, or that failed at this change's base and pass on main's tip now — not this change's failures:\n${knownMainFailures.map((t) => `- ${t}`).join("\n")}
|
|
199
|
+
Do not count them against the change unless the diff touches what they test.`);
|
|
179
200
|
if (principles) {
|
|
180
201
|
parts.push(`Design principles this project holds — your review standard; a violation of one is a finding:\n<principles>\n${principles}\n</principles>`);
|
|
181
202
|
}
|
|
203
|
+
if (postMerge) {
|
|
204
|
+
parts.push(`This review judges a change already on main, so a finding you can repair IS the work: make the
|
|
205
|
+
minimal fix right here in the worktree, leave the edit in place, and end with your verdict line plus
|
|
206
|
+
a \`FIX:\` line naming the files you changed — tumwater commits and merges your repair as one fix.
|
|
207
|
+
Fix only what the diff shows is wrong, nothing more. A finding you cannot repair in this worktree is
|
|
208
|
+
recorded as numbered reasons, exactly as a pre-merge rejection is.`);
|
|
209
|
+
}
|
|
182
210
|
// The base the diff is measured from, named in the prompt: main moves while a merge is approved,
|
|
183
211
|
// and a reviewer that double-checks scope with `git diff main` reads a newer merge, reversed, as
|
|
184
212
|
// part of the change (BUGS.md 2026-10-06). Sentence only when a base is given; the callers that
|
|
@@ -191,14 +219,25 @@ never exercise, claims the diff does not back, work left half-done.`);
|
|
|
191
219
|
parts.push(`The full diff this merge will land (${diffBase}):\n<diff>\n${diff}\n</diff>`);
|
|
192
220
|
// Right after the scratch-copy allowance it qualifies: a scratch copy stays fine for measuring
|
|
193
221
|
// something, but a copy made to run the suite is the re-run this line forbids.
|
|
194
|
-
const noRerunRule =
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
is the verified result. Copying the tree elsewhere to run it — rsync or cp into a temp
|
|
222
|
+
const noRerunRule = `
|
|
223
|
+
- Do not run the project's check or its full test suite: tumwater is running it on this tree and
|
|
224
|
+
owns the result. Copying the tree elsewhere to run it — rsync or cp into a temp
|
|
198
225
|
directory, reinstalling dependencies there (for an npm project, \`npm ci\`; otherwise its
|
|
199
|
-
equivalent) — counts as
|
|
200
|
-
specific test file for a concrete reason you can name is fine
|
|
201
|
-
|
|
226
|
+
equivalent) — counts as running it. Running one
|
|
227
|
+
specific test file for a concrete reason you can name is fine.`;
|
|
228
|
+
// The worktree rule differs by mode: a pre-merge reviewer must not touch the tree it is judging,
|
|
229
|
+
// while a post-merge reviewer's whole point is to repair what it finds in this worktree (the
|
|
230
|
+
// harness commits the edit). The pre-merge text is byte-identical to the line it replaces.
|
|
231
|
+
const worktreeRule = postMerge
|
|
232
|
+
? `- Make your repair directly in this worktree and leave it: the files you edit are what
|
|
233
|
+
tumwater commits as one fix commit. Never run a git command that changes state (no git add,
|
|
234
|
+
commit, merge, rebase, reset) — tumwater owns every git operation and commits for you. Reading
|
|
235
|
+
files and git history is fine; a scratch copy under the system temp directory is fine when you
|
|
236
|
+
need to run something.`
|
|
237
|
+
: `- Do not edit any file in the worktree. Never run a command that changes state (no git
|
|
238
|
+
add/commit/merge/rebase/reset, no writes in the worktree) — your only output channel is the
|
|
239
|
+
verdict below. Reading files and git history is fine; a scratch copy under the system temp
|
|
240
|
+
directory is fine when you need to run something.`;
|
|
202
241
|
parts.push(`Review adversarially: hunt for correctness bugs, violations of the project's principles,
|
|
203
242
|
unjustified complexity growth, and incomplete or half-done work. Work in this order:
|
|
204
243
|
1. The diff above is current — read it there; do not fetch it again with \`git diff\`,
|
|
@@ -219,8 +258,8 @@ Check, in this order:
|
|
|
219
258
|
1. Does the diff do exactly what the summary and WHY claim — no more, no less? An unclaimed
|
|
220
259
|
change is a finding.
|
|
221
260
|
2. Are the VERIFIED claims consistent with the diff (commands, files, observations)? A claim you
|
|
222
|
-
can disprove is a rejection. Suite counts are tumwater's own attestation —
|
|
223
|
-
|
|
261
|
+
can disprove is a rejection. Suite counts are tumwater's own attestation — it runs the
|
|
262
|
+
check and records them — so a count missing from VERIFIED is
|
|
224
263
|
not a finding, and neither is an author-stated count that differs from it: judge whether the
|
|
225
264
|
tests exist and exercise the change (check 3), not the author's arithmetic.
|
|
226
265
|
3. Do new or changed tests exercise the new behavior — would they fail without the change?
|
|
@@ -231,24 +270,24 @@ Check, in this order:
|
|
|
231
270
|
direction is not itself a defect. Reject only if the change is incoherent or incomplete for
|
|
232
271
|
its stated purpose, or leaves the existing entry stale and contradictory (updating the entry
|
|
233
272
|
in place is the author's duty).
|
|
273
|
+
${ARCHIVE_SWEEP_SENTENCE}
|
|
234
274
|
5. Does anything violate a principle above, or grow complexity the WHY does not justify?
|
|
235
275
|
Reject only for concrete, verifiable defects you can name; when the change is correct, complete
|
|
236
276
|
for its stated purpose, and within the principles, taste alone is not a rejection.
|
|
237
277
|
|
|
238
278
|
Rules for this run:
|
|
239
|
-
|
|
240
|
-
add/commit/merge/rebase/reset, no writes in the worktree) — your only output channel is the
|
|
241
|
-
verdict below. Reading files and git history is fine; a scratch copy under the system temp
|
|
242
|
-
directory is fine when you need to run something.${noRerunRule}
|
|
279
|
+
${worktreeRule}${noRerunRule}
|
|
243
280
|
${TEST_RUNNER_RULE}
|
|
244
281
|
- ${KILL_BY_PID_RULE}
|
|
245
282
|
- Weigh the change against its stated purpose; do not approve work you did not actually check.
|
|
246
283
|
- End your reply with exactly one line in this form:
|
|
247
|
-
${VERDICT_ENDING.replace(/\n/g, "\n ")}`
|
|
284
|
+
${VERDICT_ENDING.replace(/\n/g, "\n ")}${postMerge ? `
|
|
285
|
+
plus, when you repaired a finding, one \`FIX:\` line naming the comma-separated files you edited:
|
|
286
|
+
FIX: <files you changed>` : ""}`);
|
|
248
287
|
return parts.join("\n\n");
|
|
249
288
|
}
|
|
250
289
|
/** The prompt for the next attempt at a review whose previous run hit its time budget while
|
|
251
|
-
* still making progress (
|
|
290
|
+
* still making progress (RunnerState.reviewResume): that run continues the timed-out reviewer's
|
|
252
291
|
* own session (`--continue`), so the diff and everything the reviewer already read are in
|
|
253
292
|
* context. This prompt carries no diff — re-sending it would defeat the resume — and names the
|
|
254
293
|
* frozen comparison base and the unchanged patch-id so the reviewer knows the change it was
|
|
@@ -290,17 +329,32 @@ this worktree, not in a scratch copy. Finish the review now from what you have a
|
|
|
290
329
|
reply with ONLY the closing block — no tool calls, no other text — one line in this form:
|
|
291
330
|
${VERDICT_ENDING}`;
|
|
292
331
|
}
|
|
293
|
-
/** The one-turn follow-up sent into a
|
|
332
|
+
/** The one-turn follow-up sent into a run's OWN session (--continue) when the harness's
|
|
294
333
|
* pre-queue self-check found problems likely to get the change rejected. Only some findings are
|
|
295
334
|
* the merge gate's own deterministic checks; the rest (path drift, plan dependencies) are
|
|
296
335
|
* heuristics, so the prompt never claims the gate rejects every one — claiming it did made an
|
|
297
336
|
* author sweep a rename through the backlog's history (2026-10-18). The session still holds
|
|
298
337
|
* everything the run did, so the author fixes the faults before the change commits and queues —
|
|
299
338
|
* the gate keeps its final say, and the fix costs one bounded turn instead of a rejection cycle.
|
|
300
|
-
* A finding the author believes is wrong is answered in RISK rather than forced away
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
|
|
339
|
+
* A finding the author believes is wrong is answered in RISK rather than forced away.
|
|
340
|
+
* The prompt shows the change's description as the harness holds it and asks only for this
|
|
341
|
+
* turn's RISK and VERIFIED, which the harness appends to that description. Asked for "the
|
|
342
|
+
* closing block again", authors described the turn itself ("No change — the finding is wrong"),
|
|
343
|
+
* and that became the subject of a whole feature (BUGS.md 2026-10-21). A change whose subject
|
|
344
|
+
* was derived from its paths (`change.summary` null) is also asked for a SUMMARY of the whole
|
|
345
|
+
* change. Carries the run prompt's no-git rule (the harness commits). */
|
|
346
|
+
export function buildStageFixPrompt(findings, change) {
|
|
347
|
+
const current = joinParts([change.summary !== null && `SUMMARY: ${change.summary}`, change.body], "\n");
|
|
348
|
+
const description = current === ""
|
|
349
|
+
? ""
|
|
350
|
+
: `Your change's description stays as your closing block gave it, and review checks it against
|
|
351
|
+
the whole diff:
|
|
352
|
+
${current.replace(/^/gm, " ")}
|
|
353
|
+
Do not rewrite it to describe this turn.
|
|
354
|
+
`;
|
|
355
|
+
const summaryLine = change.summary === null
|
|
356
|
+
? " SUMMARY: <imperative one-line description of the whole change, not of this turn, at most 72 characters>\n"
|
|
357
|
+
: "";
|
|
304
358
|
return `Your change is about to commit, but tumwater's pre-queue self-check found problems the
|
|
305
359
|
merge gate or its review is likely to reject:
|
|
306
360
|
${numberedList(findings)}
|
|
@@ -308,137 +362,59 @@ Fix each one in the worktree now with the smallest edit that resolves it, and ke
|
|
|
308
362
|
as it is. When a finding is wrong, say why in your RISK line instead of forcing a change that
|
|
309
363
|
does not help. Do not run any git command that changes state (no add, commit, reset, checkout) —
|
|
310
364
|
tumwater commits for you.
|
|
311
|
-
When done, reply with ONLY
|
|
312
|
-
|
|
365
|
+
${description}When done, reply with ONLY these lines about this turn — no tool calls, no other text, one line
|
|
366
|
+
each. tumwater adds them to the change's RISK and VERIFIED lines, marked as the self-check's:
|
|
367
|
+
${summaryLine} RISK: <for each finding, what you fixed, or why it is wrong and you left it>
|
|
368
|
+
VERIFIED: <what you ran or read to check this turn's fixes — write none when nothing was run>`;
|
|
313
369
|
}
|
|
314
|
-
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
370
|
+
/** How much of the hunks a salvage restore could not place one note quotes, per file and in all:
|
|
371
|
+
* enough to apply a typical leftover by hand without letting one huge rejected file crowd out
|
|
372
|
+
* the run's own prompt. The full patch is always named for the rest. */
|
|
373
|
+
const UNPLACED_FILE_CHARS = 4_000;
|
|
374
|
+
const UNPLACED_TOTAL_CHARS = 16_000;
|
|
375
|
+
/** The note a run gets when the salvaged work restored into its worktree (src/git/slot-salvage.ts)
|
|
376
|
+
* did not all go back cleanly because its branch moved since the work was saved: the files left
|
|
377
|
+
* with conflict markers, with their hunks' line ranges, and the hunks git could not place at all,
|
|
378
|
+
* quoted for the run to apply by hand (a binary file only named), with the saved patch's path for
|
|
379
|
+
* anything cut. Undefined when everything went back cleanly. */
|
|
380
|
+
export function buildSalvageRestoreNote(conflicted, unplaced, patchPath) {
|
|
381
|
+
if (conflicted.length === 0 && unplaced.length === 0)
|
|
382
|
+
return undefined;
|
|
383
|
+
const parts = ["The saved edits did not all go back cleanly: your branch moved since they were saved."];
|
|
384
|
+
if (conflicted.length > 0) {
|
|
385
|
+
const readHint = listsHunks(conflicted)
|
|
386
|
+
? "\nRead each listed hunk's line range plus a few lines of context, not a conflicted file from the top."
|
|
387
|
+
: "";
|
|
388
|
+
parts.push(`These files carry conflict markers: \`<<<<<<< ours\` holds the branch's current text and
|
|
389
|
+
\`>>>>>>> theirs\` the saved edits. Resolve every marker (<<<<<<<, =======, >>>>>>>), keeping the
|
|
390
|
+
intent of both sides:
|
|
391
|
+
${conflicted.map(conflictedFileLine).join("\n")}${readHint}`);
|
|
327
392
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
393
|
+
if (unplaced.length > 0) {
|
|
394
|
+
let budget = UNPLACED_TOTAL_CHARS;
|
|
395
|
+
let cut = 0;
|
|
396
|
+
const quoted = [];
|
|
397
|
+
for (const { path, diff } of unplaced) {
|
|
398
|
+
const body = diff.includes("GIT binary patch")
|
|
399
|
+
? "(a binary file: its saved version is in the patch below)"
|
|
400
|
+
: diff.length > UNPLACED_FILE_CHARS
|
|
401
|
+
? `${diff.slice(0, UNPLACED_FILE_CHARS)}\n… (cut; the rest is in the patch below)`
|
|
402
|
+
: diff.trimEnd();
|
|
403
|
+
if (body.length > budget) {
|
|
404
|
+
cut += 1;
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
budget -= body.length;
|
|
408
|
+
quoted.push(`<diff path="${path}">\n${body}\n</diff>`);
|
|
409
|
+
}
|
|
410
|
+
parts.push(`These saved hunks could not be placed at all. Apply what still makes sense by hand, and leave
|
|
411
|
+
out what the branch already does:
|
|
412
|
+
${quoted.join("\n")}${cut > 0 ? `\n(${cut} more file(s) not shown: they are in the patch below.)` : ""}`);
|
|
344
413
|
}
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
/** The note injected into a role's tick prompt when its rejected change has been re-applied to
|
|
348
|
-
* current main as uncommitted edits (plans/revise-rejected.md, loop/revision.ts's
|
|
349
|
-
* applyRevision): this tick's one task is to revise the change already in the worktree, not
|
|
350
|
-
* author a new one. The prior objections are numbered so the author can work through them; a
|
|
351
|
-
* revision round past the first also reaches here. The chain keeps revising while each round
|
|
352
|
-
* fixes the prior objection; it ends only on a repeated objection or the backstop (BUGS.md
|
|
353
|
-
* 2026-10-14). A pure function so its shape is pinned in tests. */
|
|
354
|
-
export function buildRevisionNote(review, round) {
|
|
355
|
-
const list = numberedList(review.reasons, NO_REASONS);
|
|
356
|
-
return `Your previously rejected change is already in the worktree as uncommitted edits — this
|
|
357
|
-
is revision ${round}. This run's ONE task is to revise it; do not author anything else.
|
|
358
|
-
The review objections were:\n${list}
|
|
359
|
-
Fix each numbered objection with the smallest edit that resolves it, and keep everything else as it
|
|
360
|
-
is. When an objection is about a build-check failure in a test the change does not touch that you
|
|
361
|
-
cannot reproduce, say so in RISK and keep the change as it is. Rewrite the closing block so it
|
|
362
|
-
describes the WHOLE change as it now stands:
|
|
363
|
-
${SUMMARY_BLOCK}
|
|
364
|
-
When an objection shows the change should not exist (its premise is disproven, it duplicates main,
|
|
365
|
-
or it has no reachable benefit), end your reply with the line ${NOTHING_TO_DO} instead, and
|
|
366
|
-
tumwater drops the change.`;
|
|
414
|
+
parts.push(`The whole saved patch is at ${patchPath}; read it only if you need more than the above.`);
|
|
415
|
+
return `<salvage-restore>\n${parts.join("\n\n")}\n</salvage-restore>`;
|
|
367
416
|
}
|
|
368
|
-
/** The note appended to a
|
|
369
|
-
* work-instances.md "Claims", part 4/7): the harness has already picked its entry, so the
|
|
370
|
-
* charter's choosing step is replaced. A pure function so its shape is pinned in tests; the
|
|
371
|
-
* range is optional because a claim whose entry was already released still gets the note. */
|
|
372
|
-
export function buildAssignmentNote(claim, range, missingPaths = []) {
|
|
373
|
-
const where = range ? ` (${claim.file} lines ${range.start}-${range.end})` : ` (${claim.file})`;
|
|
374
|
-
const intro = claim.source === "staged"
|
|
375
|
-
? `Your change moved ONE backlog entry, so it is now your task, replacing your charter's "pick one" step:`
|
|
376
|
-
: `Tumwater has assigned you ONE backlog entry, replacing your charter's "pick one" step:`;
|
|
377
|
-
const shown = missingPaths.slice(0, 10).map((p) => `\`${p}\``).join(", ");
|
|
378
|
-
const rest = missingPaths.length - 10;
|
|
379
|
-
const missingLine = missingPaths.length === 0
|
|
380
|
-
? ""
|
|
381
|
-
: `\nThe entry names paths that do not exist in your checkout: ${shown}${rest > 0 ? `, and ${rest} more` : ""}. Each was renamed or removed after the entry was written (find its successor with \`git log --follow --name-status -- <path>\` or by grepping for the symbols the entry names), or is a file the entry asks you to create.`;
|
|
382
|
-
return `<assigned-entry>
|
|
383
|
-
${intro}
|
|
384
|
-
"${claim.title}"${where}.
|
|
385
|
-
Implement or fix only that entry. If it is too large for one run, append ${NEEDS_REVIEW_NOTE} under its heading and end your reply with that note alone. If it should not be done, append a Refused note under its heading with your objection and change nothing else. Do not edit any other backlog entry.${missingLine}
|
|
386
|
-
</assigned-entry>`;
|
|
387
|
-
}
|
|
388
|
-
/** The note appended to an unassigned work instance's prompt when siblings hold backlog entries
|
|
389
|
-
* (plans/parallel-work-instances.md "an exclusion list of held titles"): those entries are
|
|
390
|
-
* someone else's task, so choosing among the rest — or ending with nothing to do — is the
|
|
391
|
-
* instance's whole job. A pure function so its shape is pinned in tests. */
|
|
392
|
-
export function buildHeldEntriesNote(titles) {
|
|
393
|
-
return `<held-entries>
|
|
394
|
-
Sibling instances hold these backlog entries; do not pick, edit, or implement them, and do not edit their headings. If every remaining entry is held, treat the backlog as having nothing to do for you:
|
|
395
|
-
${titles.map((t) => `- "${t}"`).join("\n")}
|
|
396
|
-
</held-entries>`;
|
|
397
|
-
}
|
|
398
|
-
/** The capped series-part range list shared by the merged-prerequisites and waiting-parts
|
|
399
|
-
* notes: at most five `- "title"` lines, each naming the entry's heading line range, then one
|
|
400
|
-
* `- …and N more` line for the rest, so the two notes list a part's neighbors identically. A
|
|
401
|
-
* pure function so its shape is pinned in tests (test/gate-prompts.test.ts). */
|
|
402
|
-
/** The longest title a compact prompt quotes in an entry list: a PLANS.md heading's tail names
|
|
403
|
-
* the plan's dates and every file it touches, which its range already leads to. */
|
|
404
|
-
const COMPACT_TITLE_CHARS = 100;
|
|
405
|
-
function entryRangeLines(entries, compact = false) {
|
|
406
|
-
// Cut by code point, so an astral character is never split in half.
|
|
407
|
-
const title = (t) => {
|
|
408
|
-
const cps = Array.from(t);
|
|
409
|
-
return compact && cps.length > COMPACT_TITLE_CHARS ? `${cps.slice(0, COMPACT_TITLE_CHARS).join("").trimEnd()}…` : t;
|
|
410
|
-
};
|
|
411
|
-
const lines = entries.slice(0, 5).map((e) => `- "${title(e.title)}" (${e.file ?? "PLANS.md"} lines ${e.start}-${e.end})`);
|
|
412
|
-
if (entries.length > 5)
|
|
413
|
-
lines.push(`- …and ${entries.length - 5} more`);
|
|
414
|
-
return lines;
|
|
415
|
-
}
|
|
416
|
-
/** The note appended to a series part's assignment when parts it requires already merged: each
|
|
417
|
-
* one's Done heading, file (PLANS-DONE.md once archived) and line range, so the implementer reads
|
|
418
|
-
* exactly what that part changed instead of searching a history that runs to thousands of lines.
|
|
419
|
-
* Lists at most five, then a count of the rest. A pure function so its shape is pinned in tests. */
|
|
420
|
-
export function buildMergedPrerequisitesNote(entries,
|
|
421
|
-
/** The compact prompt every run gets: each title cut to COMPACT_TITLE_CHARS. */
|
|
422
|
-
compact = false) {
|
|
423
|
-
const lines = entryRangeLines(entries, compact);
|
|
424
|
-
return `<merged-prerequisites>
|
|
425
|
-
Your assigned entry builds on parts that are already merged. Each one's Done entry records what it actually changed; read one by its range when your entry depends on its details, rather than searching the backlog files:
|
|
426
|
-
${lines.join("\n")}
|
|
427
|
-
</merged-prerequisites>`;
|
|
428
|
-
}
|
|
429
|
-
/** The note injected into a role's prompt after leftover recovery discarded its pinned change
|
|
430
|
-
* at MERGE_CONFLICT_LIMIT (src/loop/leftover.ts): at the cap recovery ordinarily hands the
|
|
431
|
-
* change back to its author with markers instead, so a discard means that lineage already used
|
|
432
|
-
* its hand-back. The merge failures were harness-level, so without the note the author would
|
|
433
|
-
* never learn its work is gone — or that redoing it from memory of the old diff would conflict
|
|
434
|
-
* again. A pure function so its shape is pinned in tests. */
|
|
435
|
-
export function buildConflictDiscardNote(summary, attempts) {
|
|
436
|
-
return (`Your previous change ("${summary}") was discarded without merging: it conflicted with main ` +
|
|
437
|
-
`${attempts} times and conflict resolution could not reconcile it. Main has moved on since you ` +
|
|
438
|
-
`wrote it. If the change is still needed, redo it against current main, starting from main's ` +
|
|
439
|
-
`current version of the files it touched rather than your earlier diff.`);
|
|
440
|
-
}
|
|
441
|
-
/** The note appended to a role's tick prompt when a change was handed back to it with the
|
|
417
|
+
/** The note appended to a role's run prompt when a change was handed back to it with the
|
|
442
418
|
* conflict markers left in place (PLANS.md "Robust conflict landing, part 2/2"): the merge
|
|
443
419
|
* resolver could not settle it, so the author — who knows what the change was for — resolves it
|
|
444
420
|
* over current main. `reason` says whether it was an approved change whose merge kept
|
|
@@ -467,46 +443,3 @@ ${files}${readHint}
|
|
|
467
443
|
${conflictIntentBlocks(intent)}
|
|
468
444
|
</conflict-handback>`;
|
|
469
445
|
}
|
|
470
|
-
/** The note injected into the `bugfix` healer's prompt when main's own suite is red (PLANS.md
|
|
471
|
-
* "Red-main handoff"): the gate's warning event is harness-level and no role prompt reads it, so
|
|
472
|
-
* the one role allowed to author on a red main is told what failed and that fixing it is this
|
|
473
|
-
* tick's job. The healer's normal charter is a starting point, not a fit — a red main blocks
|
|
474
|
-
* every other code role, and the gate's deterministic pre-check rejects any change that leaves
|
|
475
|
-
* the suite red, so authoring anything else first is waste. A pure function so its shape is
|
|
476
|
-
* pinned in tests; script/headline are optional because a red carries a failing script, but the
|
|
477
|
-
* note must still read sensibly if it is ever absent. */
|
|
478
|
-
export function buildMainRedNote(sha, script, headline, tail) {
|
|
479
|
-
const what = script
|
|
480
|
-
? `${script}${headline ? `: ${headline}` : ""}`
|
|
481
|
-
: (headline ?? "the project's declared check");
|
|
482
|
-
// A red baseline already carries the check's bounded clipped tail (clipBuildTail, ≤12 lines:
|
|
483
|
-
// the failing test's name, the error-message line, then the stack). Hoist it into the note so
|
|
484
|
-
// the healer starts from the actual assertion and stack instead of the one-line headline —
|
|
485
|
-
// often just the test name — and must burn its run reproducing the failure first. The tail is
|
|
486
|
-
// fenced and labeled, and never touches the directive lines above, so the failure's own text
|
|
487
|
-
// cannot read as instructions to the role. An absent, empty, or all-blank tail renders today's
|
|
488
|
-
// exact note. */
|
|
489
|
-
const output = (tail ?? []).map((l) => l.trim()).filter((l) => l !== "");
|
|
490
|
-
const tailBlock = output.length > 0
|
|
491
|
-
? `\nFailing check output (${output.length} lines):\n\`\`\`\n${output.join("\n")}\n\`\`\`\n`
|
|
492
|
-
: "";
|
|
493
|
-
return `<main-red>
|
|
494
|
-
main's own suite is red at ${shortSha(sha)} (${what}). Every code-producing role is skipping authoring and no change merges until main is green.
|
|
495
|
-
This run your job is to make main green: reproduce that failure, fix it (add a regression test where one is feasible), and merge the fix.
|
|
496
|
-
The review gate's deterministic pre-check runs main + your change, so a change that leaves the suite red is rejected — do not author anything else first.
|
|
497
|
-
If the failure is environmental — flaky, load-sensitive, or a broken local toolchain — say so plainly in your reply rather than editing unrelated code.
|
|
498
|
-
${tailBlock}</main-red>`;
|
|
499
|
-
}
|
|
500
|
-
/** The note appended to an assigned series part's prompt naming the later planned parts that
|
|
501
|
-
* wait on it, so the implementer sees where its part ends and leaves their share alone. At most
|
|
502
|
-
* five are listed, then a literal `- …and N more` line (the `moreSuffix` phrase renders inline,
|
|
503
|
-
* not as a list line). A pure function so its shape is pinned in tests. */
|
|
504
|
-
export function buildWaitingPartsNote(entries,
|
|
505
|
-
/** The compact prompt every run gets: each title cut to COMPACT_TITLE_CHARS. */
|
|
506
|
-
compact = false) {
|
|
507
|
-
const shown = entryRangeLines(entries, compact);
|
|
508
|
-
return `<waiting-parts>
|
|
509
|
-
Later parts of your series wait for yours to land, and each one plans its own share of the work: do none of it here, and keep in place the names and files they say your part leaves behind. Read one by its range when you need to know what it expects:
|
|
510
|
-
${shown.join("\n")}
|
|
511
|
-
</waiting-parts>`;
|
|
512
|
-
}
|