tumwater 0.2.0 → 0.3.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 +42 -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 +4 -3
- 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 +402 -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 +246 -55
- package/dist/src/backlog/backlog-cli-view.js +280 -0
- package/dist/src/backlog/backlog-cli.js +85 -274
- package/dist/src/backlog/backlog-commit.js +4 -5
- package/dist/src/backlog/backlog-eligibility.js +175 -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 +254 -0
- package/dist/src/backlog/backlog-release.js +117 -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-culprit.js +94 -0
- package/dist/src/baseline/main-guardrails.js +209 -0
- package/dist/src/baseline/main-red.js +139 -32
- package/dist/src/baseline/main-revert.js +133 -0
- package/dist/src/baseline/main-watch.js +184 -0
- package/dist/src/brief/brief-edit.js +9 -11
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget.js +30 -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 +1 -2
- 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 +118 -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 +150 -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 +308 -590
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-role-command.js +420 -0
- package/dist/src/cli/cli-start-summary.js +160 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
- package/dist/src/cli/completion.js +149 -22
- package/dist/src/cli/config-commands.js +41 -18
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +189 -73
- package/dist/src/cli/log-commands.js +148 -82
- package/dist/src/cli/question-commands.js +205 -10
- package/dist/src/cli.js +106 -43
- package/dist/src/collections.js +26 -10
- 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 +13 -1
- package/dist/src/config/config-fallbacks.js +93 -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 +141 -199
- package/dist/src/config/config-views.js +127 -53
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +131 -264
- package/dist/src/config/config.js +48 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
- package/dist/src/doctor/doctor-backlog-plans.js +263 -0
- package/dist/src/doctor/doctor-backlog.js +100 -496
- package/dist/src/doctor/doctor-check-names.js +81 -0
- package/dist/src/doctor/doctor-checks.js +52 -579
- package/dist/src/doctor/doctor-claude-checks.js +145 -0
- package/dist/src/doctor/doctor-codex-checks.js +279 -0
- package/dist/src/doctor/doctor-contention-checks.js +380 -0
- package/dist/src/doctor/doctor-holds.js +82 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +236 -402
- package/dist/src/doctor/doctor-notify.js +3 -4
- package/dist/src/doctor/doctor-opencode-checks.js +162 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-project-checks.js +303 -0
- package/dist/src/doctor/doctor.js +121 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +7 -11
- package/dist/src/events/event-format.js +181 -86
- package/dist/src/events/event-labels.js +12 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +39 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +60 -24
- 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 +56 -56
- package/dist/src/failure/failure-render.js +31 -23
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +99 -35
- 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 +177 -84
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +108 -58
- package/dist/src/gates/maintenance-quota.js +10 -13
- 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 +77 -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 +36 -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 +42 -18
- package/dist/src/gui/gui-backlog-endpoints.js +155 -0
- package/dist/src/gui/gui-command.js +8 -13
- package/dist/src/gui/gui-config-commands.js +94 -72
- package/dist/src/gui/gui-endpoint-commands.js +4 -3
- 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 +108 -13
- package/dist/src/gui/gui-prompt-commands.js +11 -14
- package/dist/src/gui/gui-report-endpoints.js +90 -0
- package/dist/src/gui/gui-server.js +11 -4
- 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 +147 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +193 -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 +25 -9
- 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 +81 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +150 -11
- 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 +90 -0
- package/dist/src/merge/merge-queue-render.js +49 -11
- package/dist/src/merge/merge-queue.js +31 -15
- package/dist/src/merge/merge-requeue.js +102 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +33 -11
- package/dist/src/merge/merge-to-main.js +86 -27
- package/dist/src/merge/merge-top.js +69 -0
- package/dist/src/merge/merge-verify.js +12 -10
- package/dist/src/notes-cli.js +30 -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 +320 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
- package/dist/src/orchestrator/orchestrator.js +128 -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 +201 -0
- package/dist/src/orchestrator/scheduling-skip.js +185 -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 +116 -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 +18 -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 +121 -211
- package/dist/src/prompt/notes-backlog.js +181 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +129 -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 +161 -77
- package/dist/src/report/report-fold.js +129 -52
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +133 -64
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +26 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/known-flakes.js +100 -1
- package/dist/src/review/post-merge-review.js +106 -0
- package/dist/src/review/protected-edits.js +4 -5
- 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 +155 -360
- 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 +69 -12
- package/dist/src/roles/role-guidance.js +55 -20
- package/dist/src/roles/role-labels.js +1 -2
- package/dist/src/roles/role-render.js +67 -50
- package/dist/src/roles/role-view.js +59 -47
- package/dist/src/roles/roles.js +31 -31
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/{tick → run}/qa-coverage.js +9 -27
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +179 -0
- package/dist/src/run/run-detail-render.js +98 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -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} +108 -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} +108 -50
- 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} +91 -56
- 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 +172 -0
- package/dist/src/run/stage-path-checks.js +730 -0
- package/dist/src/{loop → runner}/leftover.js +80 -25
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +202 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +107 -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} +21 -15
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +102 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- 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 +43 -16
- 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 +28 -28
- package/dist/src/status/status-roles.js +39 -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 +5 -6
- 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 +63 -17
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +57 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +67 -13
- package/dist/src/ui/badges.js +65 -37
- package/dist/src/ui/gui/gui-client-backlog.js +292 -0
- package/dist/src/ui/gui/gui-client-boot.js +32 -26
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
- package/dist/src/ui/gui/gui-client-drawer.js +126 -285
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +434 -67
- package/dist/src/ui/gui/gui-client-labels.js +1 -2
- 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 +55 -51
- package/dist/src/ui/gui/gui-client-pending.js +227 -23
- package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
- package/dist/src/ui/gui/gui-client-report.js +87 -427
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +56 -4
- package/dist/src/ui/gui/gui-client-team.js +25 -465
- package/dist/src/ui/gui/gui-client.js +27 -25
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +9 -7
- package/dist/src/ui/gui/gui-styles.js +34 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +136 -49
- package/dist/src/ui/status-render.js +101 -82
- package/dist/src/ui/team-alerts.js +248 -57
- package/dist/src/ui/tone.js +5 -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 +51 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +3 -5
- package/dist/src/ui/tui/tui-editor-backends.js +132 -0
- package/dist/src/ui/tui/tui-editor-brief.js +10 -12
- package/dist/src/ui/tui/tui-editor-budget.js +35 -31
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
- package/dist/src/ui/tui/tui-editor-config.js +86 -0
- package/dist/src/ui/tui/tui-editor-entry.js +36 -47
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +37 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
- package/dist/src/ui/tui/tui-editor-interval.js +11 -9
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +3 -5
- 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 +99 -35
- package/dist/src/ui/tui/tui-editor-retire.js +4 -6
- package/dist/src/ui/tui/tui-editor-role-key.js +76 -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 +60 -34
- package/dist/src/ui/tui/tui-editor-slots.js +23 -0
- package/dist/src/ui/tui/tui-editors.js +35 -2
- package/dist/src/ui/tui/tui-frame.js +56 -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 +24 -9
- package/dist/src/ui/tui/tui-pane-activity.js +14 -11
- package/dist/src/ui/tui/tui-pane-backlog.js +171 -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 +58 -8
- package/dist/src/ui/tui/tui-pane-history.js +402 -82
- package/dist/src/ui/tui/tui-pane-pending.js +308 -13
- package/dist/src/ui/tui/tui-pane-queued.js +71 -55
- package/dist/src/ui/tui/tui-pane-report.js +46 -14
- package/dist/src/ui/tui/tui-pane-session.js +25 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +80 -23
- package/dist/src/ui/tui/tui-panes.js +100 -30
- package/dist/src/ui/tui/tui.js +14 -14
- package/dist/src/verdict/fix-claim.js +82 -32
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +42 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- 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,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { contextBudgetRule } from "./prompt.js";
|
|
3
2
|
import { dialectFor } from "./dialect.js";
|
|
4
3
|
import { NOTHING_TO_DO, REPLY_ENDINGS, SUMMARY_BLOCK } from "../verdict/reply-contract.js";
|
|
@@ -8,7 +7,7 @@ import { NOTHING_TO_DO, REPLY_ENDINGS, SUMMARY_BLOCK } from "../verdict/reply-co
|
|
|
8
7
|
* the cut-off and timeout bridges deliberately phrase their own finish instructions instead. */
|
|
9
8
|
const CONTINUE_TASK_BRIDGE = `Continue the SAME task you were working on and finish it. If the work so far turns out to be
|
|
10
9
|
unusable, redo it — but stay on this task rather than picking a new one.`;
|
|
11
|
-
/** The follow-up prompt for resuming an interrupted
|
|
10
|
+
/** The follow-up prompt for resuming an interrupted run. It is sent into the SAME pi session as
|
|
12
11
|
* the interrupted run — which already carries the full original prompt, all rules, and the work
|
|
13
12
|
* so far — so it only needs to bridge the gap. The bridge names the real cause: a run cut off at
|
|
14
13
|
* the context ceiling needs to finish with the smallest change and read almost nothing more, not
|
|
@@ -63,11 +62,13 @@ ${contextBudgetRule(dialectFor(agent))}
|
|
|
63
62
|
${REPLY_ENDINGS}`;
|
|
64
63
|
}
|
|
65
64
|
/** The bridge for a `handoff` resume (plans/agent-backends.md "Sessions"): the newest session
|
|
66
|
-
* in the worktree's session dir belongs to another agent, so this
|
|
67
|
-
* the full assembled
|
|
65
|
+
* in the worktree's session dir belongs to another agent, so this run starts a FRESH session —
|
|
66
|
+
* the full assembled run prompt, plus the one fact a fresh session cannot know: an interrupted
|
|
68
67
|
* run's uncommitted edits are sitting in the worktree. The worktree is NOT reset for a handoff,
|
|
69
|
-
* so the bridge must send the new run to `git diff` before it starts its own work.
|
|
70
|
-
|
|
68
|
+
* so the bridge must send the new run to `git diff` before it starts its own work. A `salvaged`
|
|
69
|
+
* handoff's edits were restored from a patch of a run the harness lost track of
|
|
70
|
+
* (src/git/slot-salvage.ts) rather than kept in place. */
|
|
71
|
+
export function buildHandoffPrompt(roleId, runPrompt, cause = "handoff",
|
|
71
72
|
/** Named facts an image-reroute handoff note needs that the cause alone cannot carry: the
|
|
72
73
|
* model the blind run was on and the image file it read. */
|
|
73
74
|
imageReroute) {
|
|
@@ -80,12 +81,16 @@ discard them. This run starts on the model job the daily budget left you.`
|
|
|
80
81
|
when it read ${imageReroute?.path ?? "an image"}, because that model cannot read images; its
|
|
81
82
|
uncommitted edits are in your worktree — review \`git diff\`, then finish or discard them. This
|
|
82
83
|
run is on a model that CAN read images, so read the image again.`
|
|
83
|
-
:
|
|
84
|
+
: cause === "salvaged"
|
|
85
|
+
? `An earlier run of the "${roleId}" role was cut short before tumwater could save its work;
|
|
86
|
+
its uncommitted edits were recovered and are in your worktree — review \`git status\` and
|
|
87
|
+
\`git diff\` (new files show as untracked), then finish or discard them.`
|
|
88
|
+
: `An earlier run of the "${roleId}" role on another model was interrupted; its
|
|
84
89
|
uncommitted edits are in your worktree — review \`git diff\`, then finish or discard them.`;
|
|
85
|
-
return `${
|
|
90
|
+
return `${runPrompt}\n\n${note}`;
|
|
86
91
|
}
|
|
87
|
-
/** The one-turn follow-up sent into a
|
|
88
|
-
* but its reply carried no SUMMARY line — 73 of the first 670 commits merged as "<role>
|
|
92
|
+
/** The one-turn follow-up sent into a run's OWN session (--continue) when the run changed files
|
|
93
|
+
* but its reply carried no SUMMARY line — 73 of the first 670 commits merged as "<role> run N"
|
|
89
94
|
* because of that, most of them the largest diffs in the repo. The session still holds everything
|
|
90
95
|
* the run did, so one short reply recovers the subject and body the commit deserves; the caller
|
|
91
96
|
* bounds the run tightly and falls back to a diff-derived subject if this too yields nothing. */
|
|
@@ -101,10 +106,10 @@ did not include the required closing block, so tumwater cannot describe the comm
|
|
|
101
106
|
to make. Reply now with ONLY that block — no tool calls, no other text, one line each:
|
|
102
107
|
${SUMMARY_BLOCK}`;
|
|
103
108
|
}
|
|
104
|
-
/** The note injected into a role's next FRESH
|
|
105
|
-
* off at the context ceiling without merging anything (the
|
|
106
|
-
*
|
|
107
|
-
* cross-
|
|
109
|
+
/** The note injected into a role's next FRESH run prompt after its previous run(s) were cut
|
|
110
|
+
* off at the context ceiling without merging anything (the role gave up resuming — see
|
|
111
|
+
* run-apply.ts's CUT_OFF_RESUME_LIMIT — or a cut-off director prompt is re-running). The only
|
|
112
|
+
* cross-run memory that the last attempt was too big for the window. */
|
|
108
113
|
export function buildCutOffNote(streak) {
|
|
109
114
|
const runs = streak === 1 ? "run" : `${streak} runs`;
|
|
110
115
|
return `Your previous ${runs} as this role ran out of context before merging anything. Pick a
|
|
@@ -1,47 +1,53 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { describeCheck } from "../build/build-check-report.js";
|
|
4
|
-
import { DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_SIZING } from "../roles/role-guidance.js";
|
|
5
|
-
import { CLAIMS_RULE,
|
|
3
|
+
import { DECOMPOSITION_GUIDANCE, NEEDS_REPLAN_NOTE, NEEDS_REVIEW_NOTE, PLAN_QUEUE_GUIDANCE, PLAN_SIZING } from "../roles/role-guidance.js";
|
|
4
|
+
import { CLAIMS_RULE, REPLY_ENDINGS } from "../verdict/reply-contract.js";
|
|
6
5
|
import { todayStamp } from "../budget/budget.js";
|
|
7
6
|
import { daysBetween } from "../text/datetime.js";
|
|
8
7
|
import { plural } from "../text/phrases.js";
|
|
9
8
|
import { worktreePath } from "../paths.js";
|
|
10
9
|
import { PI_DIALECT, dialectFor } from "./dialect.js";
|
|
11
|
-
/**
|
|
10
|
+
/** Prompt construction for the roles' pi runs (run and director). The reply contract those
|
|
11
|
+
* runs must follow — the TUMWATER_NOTHING_TO_DO sentinel, the TUMWATER_REFUSED line, the
|
|
12
|
+
* SUMMARY/WHY/RISK/VERIFIED block format, the three endings, and the claims rules — lives in
|
|
13
|
+
* reply-contract.ts; this module weaves it into each prompt. The follow-up prompts that pick a
|
|
14
|
+
* session back up — the resume bridge, the missing-summary recovery, and the fresh-run cut-off
|
|
15
|
+
* note — live in prompt-followup.ts. The merge gate's pi runs (conflict resolution, build fix,
|
|
16
|
+
* review) build their prompts in gate-prompts.ts; assembling a reply into the run's commit message
|
|
17
|
+
* lives in git/commit-message.ts.
|
|
18
|
+
*
|
|
19
|
+
* The prose is tuned for the team's models (2026-10-01): the primary GLM-5.3-Flash (an 18B-active
|
|
20
|
+
* MoE behind a ~1M window) and the budget fallback's local Qwen3.8-27B (~127k window). Both follow
|
|
21
|
+
* short grouped rules with concrete numbers and literal commands far better than long dense
|
|
22
|
+
* paragraphs, over-read when told merely to "work economically", make unchecked claims the reviewer
|
|
23
|
+
* then rejects (the primary's leading rejection cause), and need to be told how a reply must end
|
|
24
|
+
* — so the rules are grouped with one rule per bullet, budgets are numeric, role tasks are
|
|
25
|
+
* numbered steps, claims carry the check that proves them, the three possible endings are a
|
|
26
|
+
* mutually exclusive list, and that closing contract comes last, where a model attends to it most.
|
|
27
|
+
* The prompt is compact: its first request is re-sent on every turn, so the rules keep their
|
|
28
|
+
* directives without the reasons, the principles block keeps only its bullets, the brief file is
|
|
29
|
+
* read rather than inlined, and an assigned run goes without the material its assignment makes
|
|
30
|
+
* redundant. It was written for models with a window of at most 128k (2026-10-17) and became
|
|
31
|
+
* every model's prompt on 2026-10-18 to cut the tokens each turn re-sends; the longer full
|
|
32
|
+
* variant was deleted after a day of the team's runs on it (2026-10-19). The PRINCIPLES.md reader
|
|
33
|
+
* the principles block is fed from lives in principles.ts (readPrinciples, with its injection
|
|
34
|
+
* cap). */
|
|
35
|
+
/** The context-budget rule every run carries. Under the old 87k window half of all runs ended
|
|
12
36
|
* at the ceiling merging nothing (308 of 733 in the autonomous fortnight; 216 of 245 no-change
|
|
13
|
-
*
|
|
37
|
+
* runs in the first week of September), almost all of it whole-file reads: the model, told only
|
|
14
38
|
* to "work economically", read the codebase file by file (277 whole-file reads against 6 ranged
|
|
15
39
|
* ones in the bugfix/improve/clean logs). Every token read is prefill and dilutes the model's
|
|
16
40
|
* attention, so the rule states the cost in numbers and the one habit that prevents it: check
|
|
17
|
-
* size, then read in ranges.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* the
|
|
24
|
-
*
|
|
41
|
+
* size, then read in ranges. The range-read threshold is ~150 lines, what a 64k window's read cap
|
|
42
|
+
* holds (bounded-output.ts outputLimits), and the first bullet names the cost rather than the
|
|
43
|
+
* window's size, since every model gets it. One rule per bullet (2026-10-01), so a small model can
|
|
44
|
+
* follow each on its own. (Reasoning length is not addressed here: a "think briefly" bullet
|
|
45
|
+
* measured no drop in the fallback model's thinking — the oMLX thinking-budget cap is the lever.)
|
|
46
|
+
* The bundled context-budget extension (src/pi-extension/context-budget.ts) complements this rule
|
|
47
|
+
* with the live fill level. Stated once so the run rules and prompt-followup.ts's resume bridge
|
|
48
|
+
* cannot drift. Must not contain the phrase "ran out of context" — the loop tests use it to tell
|
|
49
|
+
* a fresh run from a cut-off resume. */
|
|
25
50
|
export function contextBudgetRule(dialect = PI_DIALECT) {
|
|
26
|
-
return `- Your context window is finite: everything you read stays in it until the run ends, and a
|
|
27
|
-
run that fills the window lands nothing. A whole-file read of a 500-line module costs ~5k tokens.
|
|
28
|
-
- Check size before reading (\`wc -l\`) and read files over ~300 lines in ranges: find the lines
|
|
29
|
-
with \`grep -n\`, then read them with ${dialect.readRange}.
|
|
30
|
-
- Cap command output with \`head\`/\`tail\`. Never dump a file, a log, or a test run wholesale.
|
|
31
|
-
- Do not re-read what you already saw — re-read only a region you edited.
|
|
32
|
-
- Each turn re-sends everything read so far, so issue lookups that do not depend on each other
|
|
33
|
-
(a \`wc -l\` over several files, the ranges a \`grep -n\` found, a typecheck and a targeted
|
|
34
|
-
test) as separate tool calls in the same turn. Keep anything that depends on a prior result
|
|
35
|
-
sequential — do not batch an edit with the test that checks it.
|
|
36
|
-
- ${dialect.oversizedOutput}`;
|
|
37
|
-
}
|
|
38
|
-
/** The pi-dialect reading-budget rule, byte-identical to the rule before the dialect split, for
|
|
39
|
-
* the callers and tests that want the default text. */
|
|
40
|
-
export const CONTEXT_BUDGET_RULE = contextBudgetRule(PI_DIALECT);
|
|
41
|
-
/** contextBudgetRule for the compact prompt: the same habits, with the range-read threshold at
|
|
42
|
-
* ~150 lines, which is what a 64k window's read cap holds (bounded-output.ts outputLimits). Its
|
|
43
|
-
* first bullet names the cost rather than the window's size, since every model gets it. */
|
|
44
|
-
export function compactContextBudgetRule(dialect = PI_DIALECT) {
|
|
45
51
|
return `- Everything you read stays in your context until the run ends and is re-sent on every turn;
|
|
46
52
|
a run that fills the window merges nothing. A whole read of a 500-line file costs ~5k tokens.
|
|
47
53
|
- Check size first (\`wc -l\`) and read files over ~150 lines in ranges: find the lines with
|
|
@@ -52,7 +58,7 @@ export function compactContextBudgetRule(dialect = PI_DIALECT) {
|
|
|
52
58
|
dependent steps sequential.
|
|
53
59
|
- ${dialect.oversizedOutput}`;
|
|
54
60
|
}
|
|
55
|
-
/** The process-kill rule every run that may run commands carries, word for word: the
|
|
61
|
+
/** The process-kill rule every run that may run commands carries, word for word: the run and
|
|
56
62
|
* director rules (full and compact, each adding its own reason), the conflict resolver, and the
|
|
57
63
|
* reviewer. The team's runs and tumwater's own checks share one host, so a kill by pattern
|
|
58
64
|
* reaches them all. On 2026-10-18 a feature run's `pkill -f "dist/test/test-runner.js"; pkill -f
|
|
@@ -62,7 +68,7 @@ export function compactContextBudgetRule(dialect = PI_DIALECT) {
|
|
|
62
68
|
export const KILL_BY_PID_RULE = `Never kill processes by name or pattern (\`pkill\`, \`killall\`,
|
|
63
69
|
\`pgrep … | xargs kill\`): stop only a process you started, by its PID (\`kill $!\` right after
|
|
64
70
|
backgrounding it).`;
|
|
65
|
-
/** The test-runner rule every run that may run tests carries: the
|
|
71
|
+
/** The test-runner rule every run that may run tests carries: the run and director rules, the
|
|
66
72
|
* conflict resolver, and the reviewer. Project-neutral on purpose — a team works on any codebase
|
|
67
73
|
* (npm, cargo, pytest, a configured check.command), so the rule names no ecosystem's runner as THE
|
|
68
74
|
* right one: it points at the declared check or the framework already in use, and its one example
|
|
@@ -78,14 +84,13 @@ export const TEST_RUNNER_RULE = `- Run tests only through the project's declared
|
|
|
78
84
|
runner finds no tests at best, and can kill them mid-run, leaking processes and temp files.`;
|
|
79
85
|
/** Render a dialect's `backendRules` as one bullet each, or nothing when the dialect has none
|
|
80
86
|
* (pi and claude) — so a backend's extra shell/reasoning guidance rides the reading-budget
|
|
81
|
-
* section right after the oversized-output rule
|
|
82
|
-
* prompts. */
|
|
87
|
+
* section right after the oversized-output rule. */
|
|
83
88
|
function backendRuleLines(rules) {
|
|
84
89
|
if (!rules || rules.length === 0)
|
|
85
90
|
return "";
|
|
86
91
|
return "\n" + rules.map((rule) => `- ${rule}`).join("\n");
|
|
87
92
|
}
|
|
88
|
-
/** The date line every pi prompt carries —
|
|
93
|
+
/** The date line every pi prompt carries — run and director (via sharedPreamble) and the gate's
|
|
89
94
|
* conflict and review runs — naming the local calendar day as YYYY-MM-DD. No prompt
|
|
90
95
|
* used to say what day it is, so a run that had to write one (a BUGS.md heading's "(found by …
|
|
91
96
|
* YYYY-MM-DD)", a Fixed or Refused date, NEEDS_REVIEW_NOTE's and NEEDS_REPLAN_NOTE's
|
|
@@ -98,7 +103,7 @@ function backendRuleLines(rules) {
|
|
|
98
103
|
export function dateLine(today = todayStamp()) {
|
|
99
104
|
return `Today's date is ${today} (local time).`;
|
|
100
105
|
}
|
|
101
|
-
/** The repo root as a
|
|
106
|
+
/** The repo root as a role's worktree reaches it (`../../..`, out of .tumwater/worktrees/<role>),
|
|
102
107
|
* derived from worktreePath so the prompt cannot drift from the layout: the hand-written "two
|
|
103
108
|
* levels up (`../../node_modules`)" it replaced pointed at .tumwater/ itself, and on 2026-09-29
|
|
104
109
|
* a bugfix run that followed it (`cd ../..`, git output empty there) fell back to the primary
|
|
@@ -111,118 +116,25 @@ export const DEFAULT_SCOPE = `- Do exactly ONE focused task, then stop. Small, c
|
|
|
111
116
|
- Choose the task within your first ~15 tool calls, in a handful of turns. A task that would
|
|
112
117
|
need more than roughly 60 tool calls, or most of the codebase in view, is too big for one
|
|
113
118
|
run — take a smaller one.`;
|
|
114
|
-
/** The rules every
|
|
119
|
+
/** The rules every role prompt carries — run and director alike, so the two cannot drift.
|
|
115
120
|
* `check` — the project's resolved check (plans/portability.md §6/7) — names the actual
|
|
116
121
|
* verification command in the Leave-the-project-working rule instead of asserting npm, and
|
|
117
122
|
* only an npm check keeps the node_modules borrowing sentence: false and actively misleading
|
|
118
123
|
* in a repo with no node_modules anywhere (a Python, Rust, or Go repo, or one with no check
|
|
119
124
|
* at all). Undefined keeps the generic wording, exactly as prompts read before a check could
|
|
120
|
-
* be configured. `scope` is the Scope section's rules: DEFAULT_SCOPE unless the
|
|
121
|
-
* states its own (Role.scope).
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
* be configured. `scope` is the Scope section's rules: DEFAULT_SCOPE unless the run's role
|
|
126
|
+
* states its own (Role.scope). Orientation differs for an `assigned` run, which reads its entry
|
|
127
|
+
* first and the brief only when the entry needs it — reading the brief in full cost a median
|
|
128
|
+
* ~2.5k tokens of every run before its first edit (2026-10-17 audit). */
|
|
129
|
+
function commonRules(check, briefFile = "README.md", scope = DEFAULT_SCOPE, dialect = PI_DIALECT, assigned = false, gateCommand) {
|
|
130
|
+
const verify = check && gateCommand
|
|
131
|
+
? `verify with \`${gateCommand}\` (lint, compile and the tests your change affects) — run it
|
|
132
|
+
after your change and fix what you broke. Tumwater runs the full check (${describeCheck(check)})
|
|
133
|
+
itself; do not run it.`
|
|
134
|
+
: check
|
|
135
|
+
? `verify with ${describeCheck(check)} (the project's declared check) — run it after your
|
|
128
136
|
change and fix what you broke.`
|
|
129
|
-
|
|
130
|
-
const modules = check?.kind === "npm"
|
|
131
|
-
? `
|
|
132
|
-
- Your worktree has no node_modules of its own; it borrows the install at the repo root
|
|
133
|
-
(\`${ROOT_FROM_WORKTREE}/node_modules\`). To inspect a dependency's types or source, read that
|
|
134
|
-
directory directly instead of widening the search outward.`
|
|
135
|
-
: "";
|
|
136
|
-
return `
|
|
137
|
-
Rules for this run:
|
|
138
|
-
|
|
139
|
-
Orientation — read this much before choosing your task, and no more:
|
|
140
|
-
- First read the project brief (${briefFile}) in full, plus QUESTIONS.md when present.
|
|
141
|
-
- PLANS.md and BUGS.md hold open work: the prompt's <backlog-index> block lists their actionable
|
|
142
|
-
entries (PLANS.md ## Planned, BUGS.md ## Open, QUESTIONS.md ## Open), each with its 1-based line
|
|
143
|
-
range, so read only the entries you need by those ranges. Finished entries live in
|
|
144
|
-
PLANS-DONE.md and BUGS-FIXED.md, newest first; the index lists the newest few with their
|
|
145
|
-
ranges. Those archive files only grow — never read them whole: search them with grep, or read
|
|
146
|
-
one entry by its range, and only when a specific finished entry matters to your task.
|
|
147
|
-
- Your worktree starts clean at main, and tumwater checks main's build before code roles
|
|
148
|
-
start: do not run the build or test suite just to establish a baseline. Run it after your
|
|
149
|
-
change, or when the task itself needs its output (reproducing a failure, counting the suite).
|
|
150
|
-
|
|
151
|
-
Scope:
|
|
152
|
-
${scope}
|
|
153
|
-
|
|
154
|
-
Reading budget:
|
|
155
|
-
${contextBudgetRule(dialect)}${backendRuleLines(dialect.backendRules)}
|
|
156
|
-
|
|
157
|
-
Where you work:
|
|
158
|
-
- Stay inside your worktree: run commands from it — the directory you start in, where
|
|
159
|
-
\`git log\` and \`git show\` work just the same — or from a scratch directory under the system
|
|
160
|
-
temp.
|
|
161
|
-
- Other agents run concurrently on this machine: put scratch files under \`$TMPDIR\` (made with
|
|
162
|
-
\`mktemp\`), never at a fixed \`/tmp\` path such as \`/tmp/check.log\`, so no other run overwrites
|
|
163
|
-
or reads yours.
|
|
164
|
-
- Never cd to the repo root (\`${ROOT_FROM_WORKTREE}\`): it is the primary checkout, which tumwater
|
|
165
|
-
merges main into while you work, and when this project is tumwater itself its dist/ is the
|
|
166
|
-
code the running team executes — never build, test, or edit files in that checkout.${modules}
|
|
167
|
-
- Never run an unbounded scan (\`find /\`, \`grep -r /\`, any recursive search rooted outside the
|
|
168
|
-
repo): it runs for tens of minutes with no output until tumwater kills your run as hung.
|
|
169
|
-
- Never run a command that can wait forever — interactive programs (TUIs, REPLs, editors,
|
|
170
|
-
anything reading stdin), servers, or watch modes. To test such a program, background it with
|
|
171
|
-
a hard time limit (kill it after at most 30 minutes) and never give it a real TTY.
|
|
172
|
-
- ${KILL_BY_PID_RULE} A pattern naming your check or test runner also matches other
|
|
173
|
-
agents' runs and tumwater's own checks on this machine, and kills them too.
|
|
174
|
-
- Leave the project working: ${verify} One run answers every question about the check: write
|
|
175
|
-
its full output to a file in a scratch dir once (\`<check> > <scratch-dir>/check.log 2>&1\`),
|
|
176
|
-
then pipe that file through \`tail\` — only the failures matter. To see any other part of the
|
|
177
|
-
output, grep or read the same file; re-run the check only after an edit changes the tree.
|
|
178
|
-
${TEST_RUNNER_RULE}
|
|
179
|
-
|
|
180
|
-
Boundaries:
|
|
181
|
-
- Never create, amend, or revert git commits, branches, or merges — tumwater handles all git
|
|
182
|
-
operations. Reading git history is fine.
|
|
183
|
-
- Never touch the .tumwater directory or tumwater.json.
|
|
184
|
-
- Never edit the brief block in ${briefFile} (between the tumwater:prompt markers).
|
|
185
|
-
- PRINCIPLES.md holds this project's design principles; only the director and steward roles may
|
|
186
|
-
edit it. Treat it as read-only — to object to a principle, record the objection in PLANS.md.
|
|
187
|
-
- docs/invariants.md states each subsystem's guarantees, pinned to the test that enforces them.
|
|
188
|
-
Read the matching section before you reconstruct what the code you are changing is supposed
|
|
189
|
-
to guarantee; when a merge adds or changes a guarantee, update the register in the same
|
|
190
|
-
commit.
|
|
191
|
-
|
|
192
|
-
When to ask, when to refuse:
|
|
193
|
-
- When a fork in the road is genuinely the user's call (product direction, an irreversible
|
|
194
|
-
choice, taste), do not guess: append a question to QUESTIONS.md under ## Open with context,
|
|
195
|
-
the options, and your own recommendation. Then continue with the parts that don't depend on
|
|
196
|
-
it, or end the run. Never block on an unanswered question; check QUESTIONS.md for answers at
|
|
197
|
-
the start of each run and act on one that unblocks your work. Do not re-ask an open question.
|
|
198
|
-
- If partway in you conclude the task would harm the project — it violates PRINCIPLES.md, grows
|
|
199
|
-
complexity without justification, or keeps fighting back — refuse it. Revert nothing; append
|
|
200
|
-
this note directly under the entry's heading in PLANS.md (a planned feature) or BUGS.md:
|
|
201
|
-
**Refused <YYYY-MM-DD> by <role>: <one-line reason>**
|
|
202
|
-
That note is the only change a refusing run leaves.
|
|
203
|
-
- When choosing work, skip entries carrying a Refused note — do not pick them and do not
|
|
204
|
-
re-refuse them. The objection stands until a human or the director edits the entry, so a
|
|
205
|
-
fully blocked backlog is a legitimate nothing-to-do state.
|
|
206
|
-
|
|
207
|
-
${CLAIMS_RULE}
|
|
208
|
-
|
|
209
|
-
How to end your reply — tumwater parses it, so the form matters:
|
|
210
|
-
- Your last message is plain text: never a tool call, and never an announcement of what you would
|
|
211
|
-
do next ("Let me check…") — either make the call or finish. If a tool result only repeats what
|
|
212
|
-
you already have, do not call it again.
|
|
213
|
-
${REPLY_ENDINGS}`;
|
|
214
|
-
}
|
|
215
|
-
/** commonRules for the compact prompt (CompactPrompt): every directive of the full rules, in
|
|
216
|
-
* fewer words. Orientation differs for an assigned run, which reads its entry first and the
|
|
217
|
-
* brief only when the entry needs it — reading the brief in full cost a median ~2.5k tokens of
|
|
218
|
-
* every run before its first edit (2026-10-17 audit). Scope, Boundaries' first three bullets,
|
|
219
|
-
* TEST_RUNNER_RULE and the reply contract are the full prompt's own text. Keep it in step with
|
|
220
|
-
* commonRules: test/compact-prompt.test.ts checks every directive both must state. */
|
|
221
|
-
function compactRules(check, briefFile, scope, dialect, assigned) {
|
|
222
|
-
const verify = check
|
|
223
|
-
? `verify with ${describeCheck(check)} (the project's declared check) — run it after your
|
|
224
|
-
change and fix what you broke.`
|
|
225
|
-
: `if it has a build or test command, run it after your change and fix what you broke.`;
|
|
137
|
+
: `if it has a build or test command, run it after your change and fix what you broke.`;
|
|
226
138
|
const modules = check?.kind === "npm"
|
|
227
139
|
? `
|
|
228
140
|
- Your worktree has no node_modules; it borrows \`${ROOT_FROM_WORKTREE}/node_modules\`. Read a
|
|
@@ -233,14 +145,15 @@ function compactRules(check, briefFile, scope, dialect, assigned) {
|
|
|
233
145
|
- Read your assigned entry (at the end of this prompt) by its line range first. It replaces your
|
|
234
146
|
task's choosing steps, so this prompt carries no backlog index. Read the project brief
|
|
235
147
|
(${briefFile}) or QUESTIONS.md only when the entry needs them.
|
|
236
|
-
- PLANS.md
|
|
237
|
-
by a range this prompt gives, or find it with \`grep -n\` first.`
|
|
148
|
+
- Never read PLANS.md, BUGS.md or their archives (PLANS-DONE.md, BUGS-FIXED.md) whole. Read
|
|
149
|
+
another entry only by a range this prompt gives, or find it with \`grep -n\` first.`
|
|
238
150
|
: `Orientation — read this much before choosing your task, and no more:
|
|
239
151
|
- First read the project brief (${briefFile}) in full, plus QUESTIONS.md when present.
|
|
240
|
-
- PLANS.md and BUGS.md
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
152
|
+
- PLANS.md and BUGS.md hold open work: the <backlog-index> block gives each actionable entry
|
|
153
|
+
with its 1-based line range, so read only the entries you need, by range. Finished entries live
|
|
154
|
+
in PLANS-DONE.md and BUGS-FIXED.md, newest first (the index lists the newest few). Never read
|
|
155
|
+
those archives whole: grep them, or read one entry by its range, only when a finished entry
|
|
156
|
+
matters to your task.`;
|
|
244
157
|
return `
|
|
245
158
|
Rules for this run:
|
|
246
159
|
|
|
@@ -252,7 +165,7 @@ Scope:
|
|
|
252
165
|
${scope}
|
|
253
166
|
|
|
254
167
|
Reading budget:
|
|
255
|
-
${
|
|
168
|
+
${contextBudgetRule(dialect)}${backendRuleLines(dialect.backendRules)}
|
|
256
169
|
|
|
257
170
|
Where you work:
|
|
258
171
|
- Run commands from your worktree (where you start; \`git log\` and \`git show\` work there) or a
|
|
@@ -266,7 +179,7 @@ Where you work:
|
|
|
266
179
|
30 minutes) and never give it a real TTY.
|
|
267
180
|
- ${KILL_BY_PID_RULE} A pattern also kills other agents' runs and checks.
|
|
268
181
|
- Leave the project working: ${verify} Write the check's full output to a scratch file once
|
|
269
|
-
(
|
|
182
|
+
(\`${gateCommand ? "<gate>" : "<check>"} > <scratch-dir>/check.log 2>&1\`) and \`tail\` it; grep that file for anything else, and
|
|
270
183
|
re-run the check only after an edit changes the tree.
|
|
271
184
|
${TEST_RUNNER_RULE}
|
|
272
185
|
|
|
@@ -289,11 +202,13 @@ When to ask, when to refuse:
|
|
|
289
202
|
justification, or keeps fighting back): refuse it. Revert nothing; append this note directly
|
|
290
203
|
under the entry's heading in PLANS.md (a planned feature) or BUGS.md:
|
|
291
204
|
**Refused <YYYY-MM-DD> by <role>: <one-line reason>**
|
|
292
|
-
|
|
205
|
+
The one-line reason must name what in this entry makes it harmful; another entry's hold, or
|
|
206
|
+
your own notes, is never a reason — skip that entry instead. That note is the only change a
|
|
207
|
+
refusing run leaves.
|
|
293
208
|
- Skip entries carrying a Refused note: never pick or re-refuse them. A fully blocked backlog is
|
|
294
209
|
a legitimate nothing-to-do state.
|
|
295
210
|
|
|
296
|
-
${
|
|
211
|
+
${CLAIMS_RULE}
|
|
297
212
|
|
|
298
213
|
How to end your reply — tumwater parses it, so the form matters:
|
|
299
214
|
- Your last message is plain text: never a tool call, and never an announcement of what you would
|
|
@@ -301,21 +216,21 @@ How to end your reply — tumwater parses it, so the form matters:
|
|
|
301
216
|
you already have, do not call it again.
|
|
302
217
|
${REPLY_ENDINGS}`;
|
|
303
218
|
}
|
|
304
|
-
/**
|
|
305
|
-
*
|
|
306
|
-
* kept whole. */
|
|
219
|
+
/** What the principles block carries of PRINCIPLES.md: the file from its first list item on,
|
|
220
|
+
* dropping its own introduction (which restates the block's heading). A file with no list item
|
|
221
|
+
* is kept whole. */
|
|
307
222
|
export function principleBullets(principles) {
|
|
308
223
|
const lines = principles.split("\n");
|
|
309
224
|
const first = lines.findIndex((line) => /^[-*] /.test(line));
|
|
310
225
|
return first <= 0 ? principles : lines.slice(first).join("\n");
|
|
311
226
|
}
|
|
312
|
-
/** The <principles> block injected into every
|
|
313
|
-
* taste, phrased positively so
|
|
314
|
-
* itself is read by principles.ts's readPrinciples. */
|
|
227
|
+
/** The <principles> block injected into every run and director prompt: the project's codified
|
|
228
|
+
* taste, phrased positively so roles follow it rather than merely avoid violations — its bullets
|
|
229
|
+
* only (principleBullets). The file itself is read by principles.ts's readPrinciples. */
|
|
315
230
|
function principlesBlock(principles) {
|
|
316
|
-
return `Design principles this project holds — uphold them in everything you produce:\n<principles>\n${principles}\n</principles>`;
|
|
231
|
+
return `Design principles this project holds — uphold them in everything you produce:\n<principles>\n${principleBullets(principles)}\n</principles>`;
|
|
317
232
|
}
|
|
318
|
-
/** The <failure-digest> block injected into the
|
|
233
|
+
/** The <failure-digest> block injected into the selfcheck role's prompt (plans/telemetry-role.md):
|
|
319
234
|
* the harness renders the digest from its own event log at the project root and hands it over, so
|
|
320
235
|
* the role spends no tool calls acquiring evidence and cannot read a stale or foreign log. */
|
|
321
236
|
function digestBlock(digest) {
|
|
@@ -333,19 +248,29 @@ function savedClause(savedDay, today) {
|
|
|
333
248
|
return "last saved today; ";
|
|
334
249
|
return `last saved ${savedDay}, ${plural(age, "day")} ago; `;
|
|
335
250
|
}
|
|
336
|
-
/** The role's
|
|
251
|
+
/** The role's notes as shown to it: its own earlier runs' note, labeled as unverified.
|
|
337
252
|
* Rides only when there is a non-empty note; the standing instruction to write one is always
|
|
338
|
-
* present (roleNotesInstruction), so a role's FIRST
|
|
339
|
-
* command exists and can seed the
|
|
340
|
-
function roleNotesBlock(notes, savedDay, today) {
|
|
253
|
+
* present (roleNotesInstruction), so a role's FIRST run — with no note yet — still learns the
|
|
254
|
+
* command exists and can seed the notes. */
|
|
255
|
+
function roleNotesBlock(notes, hasBacklogIndex, savedDay, today) {
|
|
256
|
+
const liveSource = hasBacklogIndex
|
|
257
|
+
? `the <backlog-index> block above is the live
|
|
258
|
+
source of what is currently true of each entry and series, so check it (and the entry itself) before acting on a
|
|
259
|
+
note's say-so.`
|
|
260
|
+
: `the backlog is the live
|
|
261
|
+
source of what is currently true of each entry and series, so check the entry itself (and, when this run carries
|
|
262
|
+
one, its line in the backlog) before acting on a note's say-so.`;
|
|
341
263
|
return `Notes your role wrote in earlier runs (${savedClause(savedDay, today)}yours, unverified — check against the code before
|
|
342
|
-
relying on them)
|
|
264
|
+
relying on them). A claim they make about an entry's backlog state — refused, blocked, abandoned, needs-replan,
|
|
265
|
+
done, behind another entry — is a snapshot of the past, not the present: ${liveSource}
|
|
266
|
+
A note that tells you to skip or never re-author an entry is always overridden by the backlog.
|
|
267
|
+
<role-notes>\n${notes.trim()}\n</role-notes>`;
|
|
343
268
|
}
|
|
344
|
-
/** The standing instruction that makes the
|
|
345
|
-
* write one, so the first
|
|
269
|
+
/** The standing instruction that makes the notes seedable: every role run is told it may
|
|
270
|
+
* write one, so the first run (when no note exists yet) can create it. The note content block
|
|
346
271
|
* (roleNotesBlock) is what is omitted when there is nothing to show. Every backend speaks the
|
|
347
272
|
* same shell command (plans/notes-command.md §3), and the director never reaches
|
|
348
|
-
*
|
|
273
|
+
* buildRunPrompt, so it never carries one. */
|
|
349
274
|
export function roleNotesInstruction() {
|
|
350
275
|
return `Before you end, if you learned something the next run of your role should know (where
|
|
351
276
|
things live, what you ruled out and why, what you would look at next), save the full replacement
|
|
@@ -363,42 +288,43 @@ const OLDER_NAMES_MAP = "loop = role, tick = run, fleet = team, landing/landed =
|
|
|
363
288
|
/** The sentence every assembled prompt carries once: the older names and where all of them are
|
|
364
289
|
* listed. Interpolated into the shared preamble and the reviewer and resolver openers. */
|
|
365
290
|
export const OLDER_NAMES_SENTENCE = `Older tumwater names still appear in code, git history and logs: ${OLDER_NAMES_MAP}; docs/glossary.md in tumwater's repository lists them all.`;
|
|
366
|
-
/** Shared opening of every
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
|
|
371
|
-
|
|
291
|
+
/** Shared opening of every role prompt: where the run happens and what day it is. The brief is
|
|
292
|
+
* not inlined: the rules send each run to the brief file, which holds the same text. Defined
|
|
293
|
+
* once so the run and director prompts cannot drift — and so the one sentence telling every
|
|
294
|
+
* role to date its records from dateLine, not from the repo, reaches each of them without
|
|
295
|
+
* editing any role text. */
|
|
296
|
+
function sharedPreamble(today) {
|
|
297
|
+
return [
|
|
372
298
|
`You work in a dedicated git worktree of this project; your changes will be committed and merged to main by tumwater after you finish.`,
|
|
373
299
|
`${dateLine(today)} Stamp it on anything you record now — a new BUGS.md heading ends
|
|
374
|
-
"(found by the <role> role YYYY-MM-DD)", a
|
|
375
|
-
a
|
|
300
|
+
"(found by the <role> role YYYY-MM-DD)", a BUGS.md record closes with "— fixed YYYY-MM-DD by the <role> role",
|
|
301
|
+
a finished plan's Done stamp reads "— done YYYY-MM-DD by the <role> role" appended after its
|
|
302
|
+
"(planned YYYY-MM-DD by the <role> role …)" parenthetical, and a Refused or
|
|
376
303
|
Needs-review note carries the date too — and count plan deadlines from it; never infer the date
|
|
377
304
|
from the repo.`,
|
|
378
305
|
OLDER_NAMES_SENTENCE,
|
|
379
306
|
];
|
|
380
|
-
if (initialPrompt) {
|
|
381
|
-
parts.push(`The project's brief — its reason to exist — is:\n<project-prompt>\n${initialPrompt}\n</project-prompt>`);
|
|
382
|
-
}
|
|
383
|
-
return parts;
|
|
384
307
|
}
|
|
385
|
-
/** The
|
|
386
|
-
export function
|
|
387
|
-
const { role,
|
|
308
|
+
/** The prompt for one role run. */
|
|
309
|
+
export function buildRunPrompt(input) {
|
|
310
|
+
const { role, rejectedReview, principles, digest, coverage, filings, backlogStructure, backlogIndex, notes, notesSavedDay, notesBacklog, extraInstructions, planTargetNote, flakyChecks, check, gateCommand, briefFile, today, userRequest, agent, assigned } = input;
|
|
388
311
|
const dialect = dialectFor(agent);
|
|
389
312
|
const day = today ?? todayStamp();
|
|
390
313
|
const parts = [
|
|
314
|
+
...(rejectedReview ? [rejectedReview.trim()] : []),
|
|
391
315
|
`You are the "${role.id}" role (${role.title}) on this project's tumwater team — tumwater runs a team of AI roles that develop the project.`,
|
|
392
|
-
...sharedPreamble(
|
|
316
|
+
...sharedPreamble(day),
|
|
393
317
|
];
|
|
394
318
|
if (principles)
|
|
395
|
-
parts.push(principlesBlock(
|
|
319
|
+
parts.push(principlesBlock(principles));
|
|
396
320
|
if (userRequest)
|
|
397
321
|
parts.push(`An explicit request from the user, aimed at this role. Treat it as this run's steering;
|
|
398
322
|
your role's rules and the merge gate still apply unchanged. If the request is out of this
|
|
399
323
|
role's scope, say so in your reply instead of doing it anyway.\n<user-request>\n${userRequest.trim()}\n</user-request>`);
|
|
400
324
|
if (coverage)
|
|
401
325
|
parts.push(coverage);
|
|
326
|
+
if (filings)
|
|
327
|
+
parts.push(filings);
|
|
402
328
|
if (digest)
|
|
403
329
|
parts.push(digestBlock(digest));
|
|
404
330
|
if (backlogStructure)
|
|
@@ -406,7 +332,9 @@ role's scope, say so in your reply instead of doing it anyway.\n<user-request>\n
|
|
|
406
332
|
if (backlogIndex)
|
|
407
333
|
parts.push(backlogIndex);
|
|
408
334
|
if (notes && notes.trim() !== "")
|
|
409
|
-
parts.push(roleNotesBlock(notes, notesSavedDay, day));
|
|
335
|
+
parts.push(roleNotesBlock(notes, Boolean(backlogIndex), notesSavedDay, day));
|
|
336
|
+
if (notesBacklog)
|
|
337
|
+
parts.push(notesBacklog);
|
|
410
338
|
parts.push(`Your task this run:\n${role.find.trim()}`);
|
|
411
339
|
if (planTargetNote)
|
|
412
340
|
parts.push(planTargetNote.trim());
|
|
@@ -415,39 +343,35 @@ role's scope, say so in your reply instead of doing it anyway.\n<user-request>\n
|
|
|
415
343
|
if (extraInstructions)
|
|
416
344
|
parts.push(`Additional standing instructions from the user:\n${extraInstructions.trim()}`);
|
|
417
345
|
parts.push(roleNotesInstruction());
|
|
418
|
-
parts.push(commonRules(check, briefFile, role.scope, dialect,
|
|
346
|
+
parts.push(commonRules(check, briefFile, role.scope, dialect, assigned, gateCommand).trim());
|
|
419
347
|
return parts.join("\n\n");
|
|
420
348
|
}
|
|
421
|
-
/** The prompt for a director
|
|
422
|
-
export function buildDirectorPrompt(userPrompt,
|
|
423
|
-
/** The project's resolved check (plans/portability.md §6/7) — same threading as the
|
|
349
|
+
/** The prompt for a director run, which routes a user request into the project. */
|
|
350
|
+
export function buildDirectorPrompt(userPrompt, principles,
|
|
351
|
+
/** The project's resolved check (plans/portability.md §6/7) — same threading as the run
|
|
424
352
|
* prompt, since commonRules is shared by both builders. */
|
|
425
353
|
check,
|
|
426
354
|
/** The resolved brief file's name (plans/portability.md §7a/7) — same threading again. */
|
|
427
355
|
briefFile,
|
|
428
356
|
/** Today's local date (see dateLine). Omitted: todayStamp() — tests pin it. */
|
|
429
357
|
today,
|
|
430
|
-
/** Rendered actionable backlog index (see backlog-
|
|
358
|
+
/** Rendered actionable backlog index (see backlog-index.ts); the run prompt carries it
|
|
431
359
|
* too, so the director can route against the same bounded view of the backlog. */
|
|
432
360
|
backlogIndex,
|
|
433
|
-
/** The
|
|
361
|
+
/** The backend the director resolves to, selecting the prompt dialect (./dialect.ts).
|
|
434
362
|
* Omitted: pi's dialect. */
|
|
435
|
-
|
|
436
|
-
/** The compact variant every run gets; a director run is never assigned an entry. Omitted:
|
|
437
|
-
* the full prompt. */
|
|
438
|
-
compact,
|
|
363
|
+
backend,
|
|
439
364
|
/** The director's `roles.director.instructions` override — its run prompt is otherwise the
|
|
440
365
|
* user's request. Omitted: no `Additional standing instructions` block, exactly as today. */
|
|
441
366
|
extraInstructions) {
|
|
442
|
-
const variant = compact ? { assigned: false } : undefined;
|
|
443
367
|
const parts = [
|
|
444
368
|
`You are the "director" role on this project's tumwater team — tumwater runs a team of AI roles that develop the project. The user steers
|
|
445
369
|
the project by sending it requests; one has just arrived. Other specialist roles continuously
|
|
446
370
|
implement planned features from PLANS.md and fix bugs from BUGS.md.`,
|
|
447
|
-
...sharedPreamble(
|
|
371
|
+
...sharedPreamble(today),
|
|
448
372
|
];
|
|
449
373
|
if (principles)
|
|
450
|
-
parts.push(principlesBlock(
|
|
374
|
+
parts.push(principlesBlock(principles));
|
|
451
375
|
if (backlogIndex)
|
|
452
376
|
parts.push(backlogIndex);
|
|
453
377
|
parts.push(`The user's request:\n<user-request>\n${userPrompt.trim()}\n</user-request>`);
|
|
@@ -455,7 +379,7 @@ implement planned features from PLANS.md and fix bugs from BUGS.md.`,
|
|
|
455
379
|
work yourself:
|
|
456
380
|
- A feature request or substantial change: write a concrete plan for it in PLANS.md (goal,
|
|
457
381
|
approach, files touched, acceptance criteria) so the feature role implements it. Do not build
|
|
458
|
-
it now. ${PLAN_SIZING}
|
|
382
|
+
it now. ${PLAN_SIZING} ${PLAN_QUEUE_GUIDANCE}
|
|
459
383
|
- A bug report: record it in BUGS.md (symptom, how to reproduce, suspected cause — investigate
|
|
460
384
|
briefly to sharpen the report) so the bugfix role fixes it. Do not fix it now.
|
|
461
385
|
- Guidance, a decision, or a constraint (e.g. "prefer X", "drop feature Y"): record it durably
|
|
@@ -494,7 +418,7 @@ work yourself:
|
|
|
494
418
|
if (extraInstructions)
|
|
495
419
|
parts.push(`Additional standing instructions from the user:\n${extraInstructions.trim()}`);
|
|
496
420
|
// Before the shared rules, not after them: the closing reply contract stays the last thing
|
|
497
|
-
// in the prompt, where a model attends to it most (the
|
|
421
|
+
// in the prompt, where a model attends to it most (the run prompt's invariant too).
|
|
498
422
|
parts.push(`Note on one boundary in the rules below, director only: user-defined-role requests are
|
|
499
423
|
executed by writing .tumwater-config-request.json in your worktree (shape and worked example
|
|
500
424
|
above) — never by editing tumwater.json, which stays off-limits to you as to every role. Tumwater
|
|
@@ -502,6 +426,7 @@ validates the request and applies only its customRoles array; a request that als
|
|
|
502
426
|
any other setting (timeouts, budgets, role enablement, review settings) has that key discarded
|
|
503
427
|
with a warning, so such a request is guidance to record per the routing rules, not an edit you
|
|
504
428
|
can make.`);
|
|
505
|
-
|
|
429
|
+
// A director run is never assigned an entry.
|
|
430
|
+
parts.push(commonRules(check, briefFile, undefined, dialectFor(backend)).trim());
|
|
506
431
|
return parts.join("\n\n");
|
|
507
432
|
}
|