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
|
@@ -8,22 +8,26 @@ export function registerStartupMigration(step) {
|
|
|
8
8
|
throw new Error(`startup migration "${step.name}" is already registered`);
|
|
9
9
|
registry.push(step);
|
|
10
10
|
}
|
|
11
|
-
/** Run every registered step in registration order. A step that
|
|
12
|
-
* `state_migrated` event
|
|
13
|
-
*
|
|
11
|
+
/** Run every registered step in registration order. A step that changed something logs one
|
|
12
|
+
* `state_migrated` event, whose detail also lists any collisions it kept; a step that only kept
|
|
13
|
+
* collisions logs nothing. A step that reports failed artifacts or throws logs one warning, the
|
|
14
|
+
* rest still run, and the step retries at the next start. A second call logs nothing once the
|
|
15
|
+
* first moved everything it could. */
|
|
14
16
|
export async function runStartupMigrations(root) {
|
|
15
17
|
for (const step of registry) {
|
|
16
18
|
try {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
+
const { moved, kept, failed } = await step.run(root);
|
|
20
|
+
if (moved.length > 0) {
|
|
19
21
|
logEvent(root, {
|
|
20
22
|
source: TUMWATER_SOURCE,
|
|
21
23
|
type: "state_migrated",
|
|
22
24
|
step: step.name,
|
|
23
|
-
moved:
|
|
24
|
-
detail:
|
|
25
|
+
moved: moved.length,
|
|
26
|
+
detail: [...moved, ...kept].join("; "),
|
|
25
27
|
});
|
|
26
28
|
}
|
|
29
|
+
if (failed.length > 0)
|
|
30
|
+
warnEventBestEffort(root, TUMWATER_SOURCE, `startup migration ${step.name}: ${failed.join("; ")}`);
|
|
27
31
|
}
|
|
28
32
|
catch (err) {
|
|
29
33
|
warnEventBestEffort(root, TUMWATER_SOURCE, `startup migration ${step.name} failed: ${errorMessage(err)}`);
|
package/dist/src/paths.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { DIRECTOR_ROLE } from "./roles/roles.js";
|
|
3
|
+
import { isDirectory } from "./files/files.js";
|
|
4
4
|
/** All harness runtime state lives under <repo>/.tumwater (gitignored). */
|
|
5
5
|
export const STATE_DIR = ".tumwater";
|
|
6
6
|
/** The config file's basename — the name .gitignore's entry and the init output share. */
|
|
@@ -8,7 +8,7 @@ export const CONFIG_BASENAME = "tumwater.json";
|
|
|
8
8
|
/** The tracked settings template's basename: the shareable baseline an untracked
|
|
9
9
|
* tumwater.json is seeded from (plans/portability.md §4a/7). */
|
|
10
10
|
export const EXAMPLE_CONFIG_BASENAME = "tumwater.example.json";
|
|
11
|
-
/** The files the project brief (the managed
|
|
11
|
+
/** The files the project brief (the managed brief text + status sections) may live in,
|
|
12
12
|
* candidates in resolution order: TUMWATER.md first, so an adopted repo's own README.md stays
|
|
13
13
|
* untouched (plans/portability.md §7a/7); README.md is the compatibility path every repo
|
|
14
14
|
* tumwater has created so far. */
|
|
@@ -23,7 +23,8 @@ export function configPath(root) {
|
|
|
23
23
|
return path.join(root, CONFIG_BASENAME);
|
|
24
24
|
}
|
|
25
25
|
/** The cross-process lock serializing read-modify-write updates of tumwater.json
|
|
26
|
-
* (writeConfigMutation
|
|
26
|
+
* (writeConfigMutation in config/config-write-core.ts and applyConfigRequest in
|
|
27
|
+
* config/config-request.ts): the CLI's
|
|
27
28
|
* `tumwater config set`, a standalone `tumwater gui` server, and the running team are separate
|
|
28
29
|
* processes that can rewrite one config in the same instant, and without serialization each
|
|
29
30
|
* one's whole-file write silently drops the others' change. A lock directory owned by the
|
|
@@ -51,7 +52,7 @@ export function exampleConfigPath(root) {
|
|
|
51
52
|
}
|
|
52
53
|
/** The director's config-write request file, at its worktree root (plans/portability.md §3/7):
|
|
53
54
|
* the director writes it, the harness consumes and deletes it before any commit path — so it
|
|
54
|
-
* never enters a diff, a review prompt, or the project's history, and custom-
|
|
55
|
+
* never enters a diff, a review prompt, or the project's history, and custom-role management
|
|
55
56
|
* works whether or not tumwater.json is tracked. */
|
|
56
57
|
export function configRequestPath(wt) {
|
|
57
58
|
return path.join(wt, ".tumwater-config-request.json");
|
|
@@ -62,22 +63,46 @@ export function configRequestPath(wt) {
|
|
|
62
63
|
export function worktreesDir(root) {
|
|
63
64
|
return path.join(tumwaterDir(root), "worktrees");
|
|
64
65
|
}
|
|
65
|
-
/**
|
|
66
|
+
/** Where a pooled slot's uncommitted leftovers are saved as patches before the slot is reset for
|
|
67
|
+
* another lease (slot-salvage.ts). A patch directly here is kept for the operator until session
|
|
68
|
+
* retention prunes it; one waiting for its role's next run lives under salvagePendingDir. */
|
|
69
|
+
export function salvageDir(root) {
|
|
70
|
+
return path.join(tumwaterDir(root), "salvage");
|
|
71
|
+
}
|
|
72
|
+
/** The patches of `role`'s unfinished work waiting for its next run to restore them
|
|
73
|
+
* (slot-salvage.ts, restoreSalvagedWork). */
|
|
74
|
+
export function salvagePendingDir(root, role) {
|
|
75
|
+
return path.join(salvageDir(root), "pending", role);
|
|
76
|
+
}
|
|
77
|
+
/** A role's persistent git worktree under .tumwater/worktrees/. */
|
|
66
78
|
export function worktreePath(root, role) {
|
|
67
79
|
return path.join(worktreesDir(root), role);
|
|
68
80
|
}
|
|
69
|
-
/** A
|
|
81
|
+
/** A role's persistent branch name. */
|
|
70
82
|
export function branchName(role) {
|
|
71
83
|
return `tumwater/${role}`;
|
|
72
84
|
}
|
|
73
|
-
/** A role's
|
|
85
|
+
/** A role's state file (.tumwater/state/<role>.json; runner-state.ts). */
|
|
74
86
|
export function statePath(root, role) {
|
|
75
87
|
return path.join(tumwaterDir(root), "state", `${role}.json`);
|
|
76
88
|
}
|
|
89
|
+
/** A backend's subscription account state (.tumwater/state/<backend>-account.json;
|
|
90
|
+
* subscription-account.ts): the billing answer and newest subscription window readings,
|
|
91
|
+
* written by the orchestrator only. */
|
|
92
|
+
export function accountPath(root, backend) {
|
|
93
|
+
return path.join(tumwaterDir(root), "state", `${backend}-account.json`);
|
|
94
|
+
}
|
|
77
95
|
/** The claude account state (.tumwater/state/claude-account.json; claude-account.ts): the
|
|
78
|
-
*
|
|
96
|
+
* claude backend's subscription account — accountPath for the "claude" backend. */
|
|
79
97
|
export function claudeAccountPath(root) {
|
|
80
|
-
return
|
|
98
|
+
return accountPath(root, "claude");
|
|
99
|
+
}
|
|
100
|
+
/** The codex write guard's trust cache (.tumwater/state/codex-hook-trust.json;
|
|
101
|
+
* codex-hook-trust.ts): the `{key, hash}` codex itself reports through `hooks/list`, keyed by
|
|
102
|
+
* codex version and hook definition so the lookup runs once per build and Codex version, not
|
|
103
|
+
* once per run. Runtime state under .tumwater/state/, never committed. */
|
|
104
|
+
export function codexHookTrustPath(root) {
|
|
105
|
+
return path.join(tumwaterDir(root), "state", "codex-hook-trust.json");
|
|
81
106
|
}
|
|
82
107
|
/** The worktree-use registry (plans/disk-floor.md, part 2/4; git/worktree-use.ts): which
|
|
83
108
|
* worktrees are in use and when each was last used, so pressure reclaim can order candidates
|
|
@@ -103,15 +128,28 @@ export function orchestratorStatePath(root) {
|
|
|
103
128
|
export function imageProbesPath(root) {
|
|
104
129
|
return path.join(tumwaterDir(root), "state", "image-probes.json");
|
|
105
130
|
}
|
|
106
|
-
/** The `
|
|
131
|
+
/** The images column `tumwater doctor` last read from `pi --list-models`, keyed provider/model.
|
|
132
|
+
* Runtime state under .tumwater/state/, never committed. */
|
|
133
|
+
export function piListedModelsPath(root) {
|
|
134
|
+
return path.join(tumwaterDir(root), "state", "pi-listed-models.json");
|
|
135
|
+
}
|
|
136
|
+
/** The `qa` flow-coverage ledger (run/qa-coverage.ts): which flow each observer run exercised
|
|
107
137
|
* and how it went. Runtime state under .tumwater/state/, never committed — a passing check
|
|
108
138
|
* must leave the repo untouched, or every cheap pass would move main and wake the team. */
|
|
109
139
|
export function qaCoveragePath(root) {
|
|
110
140
|
return path.join(tumwaterDir(root), "state", "qa-coverage.json");
|
|
111
141
|
}
|
|
112
|
-
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
142
|
+
/** The `feedback` observer's per-install filing ledger (run/feedback-filings.ts): which GitHub
|
|
143
|
+
* issues this install already filed on znation/tumwater, so the next fresh session's prompt can
|
|
144
|
+
* render a "previously filed" block without re-deriving its dedupe from the network alone.
|
|
145
|
+
* Runtime state under .tumwater/state/, never committed — a filing must leave the repo untouched
|
|
146
|
+
* (the role's only write is `gh`), and the worktree resets to main each run. */
|
|
147
|
+
export function feedbackFilingsPath(root) {
|
|
148
|
+
return path.join(tumwaterDir(root), "state", "feedback-filings.json");
|
|
149
|
+
}
|
|
150
|
+
/** A role's notes (.tumwater/state/notes/<role>.md): the bounded note the role's own earlier
|
|
151
|
+
* runs wrote, carried into the next fresh session. Runtime state under .tumwater/state/, never
|
|
152
|
+
* committed — the worktree resets to main each run, so a committed note would move main. The
|
|
115
153
|
* director has none: its work is the operator's prompt, not a recurring search. */
|
|
116
154
|
export function roleNotesPath(root, role) {
|
|
117
155
|
return path.join(tumwaterDir(root), "state", "notes", `${role}.md`);
|
|
@@ -123,6 +161,22 @@ export function roleNotesPath(root, role) {
|
|
|
123
161
|
export function mergeStatePath(root) {
|
|
124
162
|
return path.join(tumwaterDir(root), "state", "merging.json");
|
|
125
163
|
}
|
|
164
|
+
/** The reverted changes still waiting for a free runner (.tumwater/state/reverted.json;
|
|
165
|
+
* src/merge/merge-drain.ts): `{ reverted: [{ commit, role, reasons }] }`, each entry dropped once
|
|
166
|
+
* assigned. */
|
|
167
|
+
export function revertedPendingPath(root) {
|
|
168
|
+
return path.join(tumwaterDir(root), "state", "reverted.json");
|
|
169
|
+
}
|
|
170
|
+
/** Merged commits awaiting their review after merging (src/review/post-merge-review.ts), for roles
|
|
171
|
+
* listed in `review.afterMerge`: `{ pending: PostReview[] }`. Runtime state, never committed. */
|
|
172
|
+
export function postReviewPath(root) {
|
|
173
|
+
return path.join(tumwaterDir(root), "state", "post-review.json");
|
|
174
|
+
}
|
|
175
|
+
/** The detached checkout a post-merge review reads the merged commit in; the leading underscore
|
|
176
|
+
* keeps it from colliding with a role worktree. */
|
|
177
|
+
export function postReviewWorktreePath(root) {
|
|
178
|
+
return path.join(worktreesDir(root), "_post-review");
|
|
179
|
+
}
|
|
126
180
|
/** The merge marker's old file, deleted by the startup migration (the marker is display-only,
|
|
127
181
|
* so a previous generation's is stale and is not read). */
|
|
128
182
|
export function legacyLandingStatePath(root) {
|
|
@@ -140,13 +194,18 @@ export function autoRestartStampPath(root) {
|
|
|
140
194
|
export function baselineVerdictsPath(root) {
|
|
141
195
|
return path.join(tumwaterDir(root), "state", "baseline-verdicts.json");
|
|
142
196
|
}
|
|
197
|
+
/** The quarantined flaky tests (review/known-flakes.ts): tests that failed and then passed on the
|
|
198
|
+
* same tree, newest 100, each with the BUGS.md entry filed for it. */
|
|
199
|
+
export function quarantinePath(root) {
|
|
200
|
+
return path.join(tumwaterDir(root), "state", "quarantine.json");
|
|
201
|
+
}
|
|
143
202
|
/** Marker file `tumwater reset-counters` drops for a running team to consume (it must also
|
|
144
203
|
* zero the runners' in-memory counters, or their next save resurrects the old values). */
|
|
145
204
|
export function resetRequestPath(root) {
|
|
146
205
|
return path.join(tumwaterDir(root), "reset-counters.json");
|
|
147
206
|
}
|
|
148
207
|
/** Marker file `tumwater wake [--role <id>]` drops for a running team to consume: like the
|
|
149
|
-
* reset-counters marker it must name its targets because it can affect many
|
|
208
|
+
* reset-counters marker it must name its targets because it can affect many roles, and like it
|
|
150
209
|
* it must reach the runners' IN-MEMORY schedule — the poll loop reads eligibility from the
|
|
151
210
|
* in-memory state, so clearing only the on-disk file would not wake anything. */
|
|
152
211
|
export function wakeRequestPath(root) {
|
|
@@ -172,9 +231,9 @@ export function reclaimRequestPath(root) {
|
|
|
172
231
|
return path.join(tumwaterDir(root), "reclaim.json");
|
|
173
232
|
}
|
|
174
233
|
/** Per-role marker file `tumwater abort --role <id>` drops for a running team to consume:
|
|
175
|
-
* kill that
|
|
234
|
+
* kill that role's in-flight run. One file per role (presence = pending request; content is
|
|
176
235
|
* just `{ at }`) keeps consumption race-free and needs no parsing — unlike the single shared
|
|
177
|
-
* reset-counters marker, which must name its targets because it affects many
|
|
236
|
+
* reset-counters marker, which must name its targets because it affects many roles. */
|
|
178
237
|
export function abortRequestPath(root, role) {
|
|
179
238
|
return path.join(tumwaterDir(root), `abort-${role}.json`);
|
|
180
239
|
}
|
|
@@ -186,7 +245,7 @@ export function pausedPath(root) {
|
|
|
186
245
|
return path.join(tumwaterDir(root), "paused.json");
|
|
187
246
|
}
|
|
188
247
|
/** Operator-intent marker for `tumwater stop --in <duration>`: `{ at, until }` in epoch ms. The
|
|
189
|
-
* running team's watch consumes it when `until` passes; a fresh `tumwater
|
|
248
|
+
* running team's watch consumes it when `until` passes; a fresh `tumwater start` clears a
|
|
190
249
|
* stale one. */
|
|
191
250
|
export function scheduledStopPath(root) {
|
|
192
251
|
return path.join(tumwaterDir(root), "stop-at.json");
|
|
@@ -216,29 +275,29 @@ export const EVENTS_LOG_BASENAME = "events.jsonl";
|
|
|
216
275
|
export function eventsLogPath(root) {
|
|
217
276
|
return path.join(tumwaterDir(root), "log", EVENTS_LOG_BASENAME);
|
|
218
277
|
}
|
|
219
|
-
/**
|
|
220
|
-
* to events.jsonl.1
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* drift apart. */
|
|
224
|
-
export function eventsArchivePath(root) {
|
|
225
|
-
return eventsLogPath(root) + ".
|
|
278
|
+
/** An archived generation of the event log (src/files/files.ts rotateIfLarge renames the grown
|
|
279
|
+
* log to events.jsonl.1 and shifts older generations down, up to EVENTS_KEEP of them); the
|
|
280
|
+
* windowed readers continue into them when the live log ends inside the window (event-window.ts).
|
|
281
|
+
* `generation` defaults to 1, the newest archive. The path lives beside eventsLogPath so the
|
|
282
|
+
* pair cannot drift apart. */
|
|
283
|
+
export function eventsArchivePath(root, generation = 1) {
|
|
284
|
+
return eventsLogPath(root) + "." + generation;
|
|
226
285
|
}
|
|
227
286
|
/** A role's raw pi transcript log (.tumwater/log/<role>.pi.jsonl); tailed by the GUI/TUI. */
|
|
228
287
|
export function piLogPath(root, role) {
|
|
229
288
|
return path.join(tumwaterDir(root), "log", `${role}.pi.jsonl`);
|
|
230
289
|
}
|
|
231
|
-
/** A role's backend-native stdout log (.tumwater/log/<role>.<
|
|
232
|
-
* beside the canonical raw log and kept for debugging only: no reader folds it, and the
|
|
290
|
+
/** A role's backend-native stdout log (.tumwater/log/<role>.<backend>.native.jsonl), written
|
|
291
|
+
* beside the canonical raw log and kept for debugging only: no reader folds it, and the backend
|
|
233
292
|
* is in the name because one role's runs may switch backends and the two dialects must not
|
|
234
293
|
* mix. Written and rotated like the raw log (src/agent/run-agent.ts). */
|
|
235
|
-
export function nativeLogPath(root, role,
|
|
236
|
-
return path.join(tumwaterDir(root), "log", `${role}.${
|
|
294
|
+
export function nativeLogPath(root, role, backend) {
|
|
295
|
+
return path.join(tumwaterDir(root), "log", `${role}.${backend}.native.jsonl`);
|
|
237
296
|
}
|
|
238
297
|
/** Root of the full-output files the bundled pi extension writes for oversized tool
|
|
239
298
|
* results (.tumwater/log/tool-output/<toolCallId>.log). Pruned by the same sessionRetentionDays
|
|
240
299
|
* window as sessions (orchestrator.ts's two retention passes): a pointer to a tool result is
|
|
241
|
-
* only useful while its
|
|
300
|
+
* only useful while its run is recent, and the files otherwise accumulate without bound. */
|
|
242
301
|
export function toolOutputDir(root) {
|
|
243
302
|
return path.join(tumwaterDir(root), "log", "tool-output");
|
|
244
303
|
}
|
|
@@ -246,7 +305,7 @@ export function toolOutputDir(root) {
|
|
|
246
305
|
export function sessionsRootDir(root) {
|
|
247
306
|
return path.join(tumwaterDir(root), "sessions");
|
|
248
307
|
}
|
|
249
|
-
/** A role's own pi session dir; hasResumableSession looks here for an interrupted
|
|
308
|
+
/** A role's own pi session dir; hasResumableSession looks here for an interrupted run to
|
|
250
309
|
* resume. */
|
|
251
310
|
export function sessionDir(root, role) {
|
|
252
311
|
return path.join(sessionsRootDir(root), role);
|
|
@@ -259,14 +318,7 @@ export function sessionDir(root, role) {
|
|
|
259
318
|
export function nearestTumwaterRoot(sessionDir) {
|
|
260
319
|
let dir = sessionDir;
|
|
261
320
|
for (let i = 0; i < 64; i += 1) {
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
tumwater = fs.statSync(path.join(dir, ".tumwater"));
|
|
265
|
-
}
|
|
266
|
-
catch {
|
|
267
|
-
tumwater = undefined;
|
|
268
|
-
}
|
|
269
|
-
if (tumwater?.isDirectory())
|
|
321
|
+
if (isDirectory(path.join(dir, ".tumwater")))
|
|
270
322
|
return dir;
|
|
271
323
|
const parent = path.dirname(dir);
|
|
272
324
|
if (parent === dir)
|
|
@@ -275,6 +327,17 @@ export function nearestTumwaterRoot(sessionDir) {
|
|
|
275
327
|
}
|
|
276
328
|
return undefined;
|
|
277
329
|
}
|
|
330
|
+
/** The team root of the workspace `dir` sits in — `dir` lies under `worktreesDir(root)` for the
|
|
331
|
+
* nearest `.tumwater` root — or undefined for a team root itself, a directory elsewhere under
|
|
332
|
+
* it, or a directory with no root above. A read-only lookup for messages, never used to decide
|
|
333
|
+
* where to write (same caution as teamRootOf). */
|
|
334
|
+
export function owningTeamRoot(dir) {
|
|
335
|
+
const root = nearestTumwaterRoot(dir);
|
|
336
|
+
if (root === undefined)
|
|
337
|
+
return undefined;
|
|
338
|
+
const rel = path.relative(worktreesDir(root), dir);
|
|
339
|
+
return rel !== "" && !path.isAbsolute(rel) && !rel.startsWith("..") ? root : undefined;
|
|
340
|
+
}
|
|
278
341
|
/** The team root that owns `sessionDir`: the `.tumwater` directory that contains it. A run's
|
|
279
342
|
* session dir is always `<root>/.tumwater/sessions/…`, so the first ancestor holding a
|
|
280
343
|
* `.tumwater` directory is the root; opencodeDbPath reads back to that same `.tumwater` for
|
|
@@ -291,7 +354,7 @@ export function teamRootOf(sessionDir) {
|
|
|
291
354
|
}
|
|
292
355
|
/** The directory the notes shim lands in, under a team root: `<root>/.tumwater/bin`.
|
|
293
356
|
* run-agent installs the `tumwater-notes` command there (src/agent/notes-shim.ts) and
|
|
294
|
-
* run-marker's
|
|
357
|
+
* run-marker's backendBaseEnv prepends it to every run's PATH, so a run on any backend finds
|
|
295
358
|
* the command (plans/notes-command.md "Reaching it from a run"). */
|
|
296
359
|
export function notesShimDir(root) {
|
|
297
360
|
return path.join(tumwaterDir(root), "bin");
|
|
@@ -313,30 +376,30 @@ export function opencodeModelsPath(root) {
|
|
|
313
376
|
}
|
|
314
377
|
/** Session dir for a role's review-gate runs. Kept OUTSIDE the role's own session dir on
|
|
315
378
|
* purpose: hasResumableSession (the resume-after-shutdown guard) must only ever see the
|
|
316
|
-
* AUTHOR's sessions — a leftover reviewer session would make an interrupted
|
|
379
|
+
* AUTHOR's sessions — a leftover reviewer session would make an interrupted run "resume"
|
|
317
380
|
* into a review context it never had. Old files are cleaned by the same age-based prune.
|
|
318
381
|
*/
|
|
319
382
|
export function reviewSessionDir(root, role) {
|
|
320
383
|
return path.join(sessionsRootDir(root), "_review", role);
|
|
321
384
|
}
|
|
322
385
|
/** The per-run child of a role's review session dir: one directory per review of one change,
|
|
323
|
-
* keyed by the run's
|
|
386
|
+
* keyed by the review run's number and pinned sha, so a follow-up turn — or a later attempt that
|
|
324
387
|
* resumes this review — continues exactly that run's session rather than whichever review
|
|
325
388
|
* wrote last into the shared parent. */
|
|
326
389
|
export function reviewRunSessionDir(root, role, runKey) {
|
|
327
390
|
return path.join(reviewSessionDir(root, role), runKey);
|
|
328
391
|
}
|
|
329
|
-
/** Queued human prompts awaiting pickup by a
|
|
392
|
+
/** Queued human prompts awaiting pickup by a role (inbox.ts). */
|
|
330
393
|
export function inboxDir(root) {
|
|
331
394
|
return path.join(tumwaterDir(root), "inbox");
|
|
332
395
|
}
|
|
333
|
-
/** The queue directory one
|
|
334
|
-
* queue at the inbox root so existing inboxes stay readable, and every other
|
|
335
|
-
* per-role subdirectory — `tumwater prompt --role <id>` writes where only that
|
|
396
|
+
/** The queue directory one role's prompts wait in (inbox.ts): the director keeps its historical
|
|
397
|
+
* queue at the inbox root so existing inboxes stay readable, and every other role gets a
|
|
398
|
+
* per-role subdirectory — `tumwater prompt --role <id>` writes where only that role reads. */
|
|
336
399
|
export function roleInboxDir(root, role) {
|
|
337
400
|
return role === DIRECTOR_ROLE ? inboxDir(root) : path.join(inboxDir(root), role);
|
|
338
401
|
}
|
|
339
|
-
/** The durable merge queue (src/merge/merge-queue.ts): a changed
|
|
402
|
+
/** The durable merge queue (src/merge/merge-queue.ts): a changed run's pinned commit waits here
|
|
340
403
|
* as one JSON file for the orchestrator's merge pipeline (plans/merge-queue.md 3/5, land-queue
|
|
341
404
|
* speed 2c). Like the inbox it is a directory of timestamped files —
|
|
342
405
|
* a crash between enqueue and drop loses nothing, and `tumwater status` can read it without the
|
|
@@ -349,6 +412,10 @@ export function mergeQueueDir(root) {
|
|
|
349
412
|
export function legacyLandQueueDir(root) {
|
|
350
413
|
return path.join(tumwaterDir(root), "land-queue"); // vocabulary-ok: legacy path read from old layouts
|
|
351
414
|
}
|
|
415
|
+
/** How long a merge-lock taker outside the merge queue waits for the lock: a merge holds it through
|
|
416
|
+
* its in-lock check, which can run several minutes. A dead holder is still broken early by
|
|
417
|
+
* `tryBreakStale`. */
|
|
418
|
+
export const MERGE_LOCK_WAIT_MS = 15 * 60_000;
|
|
352
419
|
/** The lock dir serializing merges to main (merge-to-main.ts; doctor checks it). */
|
|
353
420
|
export function mergeLockDir(root) {
|
|
354
421
|
return path.join(tumwaterDir(root), "merge.lock");
|
|
@@ -376,7 +443,7 @@ export function witnessWorktreePath(root) {
|
|
|
376
443
|
return path.join(worktreesDir(root), "_build");
|
|
377
444
|
}
|
|
378
445
|
/** One slot of the worktree pool (plans/worktree-pool.md): a fixed `.tumwater/worktrees/_slot-<n>`
|
|
379
|
-
* checkout that
|
|
446
|
+
* checkout that runs and verifies lease and switch commits in place, instead of one `_land-<role>`
|
|
380
447
|
* per role. The leading underscore keeps it from colliding with a role worktree. */
|
|
381
448
|
export function slotWorktreePath(root, n) {
|
|
382
449
|
return path.join(worktreesDir(root), `_slot-${n}`);
|
|
@@ -402,7 +469,7 @@ export function slotsLockPath(root) {
|
|
|
402
469
|
return path.join(tumwaterDir(root), "state", "slots.lock");
|
|
403
470
|
}
|
|
404
471
|
/** The ref pinning a role's committed-but-not yet merged sha (plans/merge-queue.md invariant 4):
|
|
405
|
-
* written right after the
|
|
472
|
+
* written right after the run's commit, before its branch resets to main, so the reset cannot
|
|
406
473
|
* orphan the work. Deleted on every terminal merge outcome; kept until re-merged otherwise. */
|
|
407
474
|
export function mergeRefName(role) {
|
|
408
475
|
return `refs/tumwater/merge/${role}`;
|
|
@@ -414,7 +481,7 @@ export function legacyLandingRefName(role) {
|
|
|
414
481
|
return `refs/tumwater/landing/${role}`; // vocabulary-ok: legacy name read from old refs or commits
|
|
415
482
|
}
|
|
416
483
|
/** The ref naming a role's rejected change while a revision is due (plans/revise-rejected.md):
|
|
417
|
-
* written at the gate's rejection, read by the author's next
|
|
484
|
+
* written at the gate's rejection, read by the author's next run to re-apply the rejected diff,
|
|
418
485
|
* and deleted once the revision merges, is dropped, conflicts, or exhausts its rounds. Keeping
|
|
419
486
|
* the head reachable here stops git gc from collecting the one commit the revision re-applies. */
|
|
420
487
|
export function rejectedRefName(role) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* keeps a legitimately slow suite below it while a hang surfaces within one quiet window of
|
|
8
8
|
* the default. Both stall surfaces (runPi's warning, the dashboard's flag) must apply the
|
|
9
9
|
* same threshold or one cries wolf while the other stays silent. */
|
|
10
|
+
import { streamsToolOutput } from "../agent/backend-traits.js";
|
|
10
11
|
export function bufferedCommandStallMs(stallMs) {
|
|
11
12
|
return Math.max(stallMs * 2, 10 * 60_000);
|
|
12
13
|
}
|
|
@@ -14,7 +15,7 @@ export function bufferedCommandStallMs(stallMs) {
|
|
|
14
15
|
* silence carries no hang signal and the stall warning would be a false alarm. Two shapes do
|
|
15
16
|
* this: a pipe (`npm test 2>&1 | tail -8`) holds every byte in the pipeline until the upstream
|
|
16
17
|
* command exits, and a stdout redirect (`npm test > /tmp/out`) sends the bytes to a file
|
|
17
|
-
* instead of pi's pipe. Both are shapes the
|
|
18
|
+
* instead of pi's pipe. Both are shapes the run prompt itself prescribes for verification
|
|
18
19
|
* runs, so the stall detector must not read their silence as a stall. A bare `2>&1` is NOT
|
|
19
20
|
* such a shape: it points stderr at stdout's destination — pi's live pipe — so output still
|
|
20
21
|
* streams and a hang stays detectable. `2>` and `2>>` likewise leave or append only stderr.
|
|
@@ -50,3 +51,13 @@ export function commandBuffersOutput(command) {
|
|
|
50
51
|
}
|
|
51
52
|
return false;
|
|
52
53
|
}
|
|
54
|
+
/** True when a tool call gives no silence signal, so it must be judged by the buffered
|
|
55
|
+
* wall-clock threshold instead: either the agent never streams tool output (claude and
|
|
56
|
+
* opencode, which send no content updates) or the command itself buffers its stdout
|
|
57
|
+
* (commandBuffersOutput). The two stall surfaces — pi-watchdogs.ts's runPi stall warning and
|
|
58
|
+
* progress-data.ts's in-flight stall flag — must agree on this or one surface cries wolf
|
|
59
|
+
* while the other stays silent (BUGS.md 2026-09-28); this composes streamsToolOutput with the
|
|
60
|
+
* command classifier so they cannot drift. */
|
|
61
|
+
export function callBuffersOutput(agent, command) {
|
|
62
|
+
return !streamsToolOutput(agent) || commandBuffersOutput(command);
|
|
63
|
+
}
|
package/dist/src/pi/pi-args.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Building the pi command line for one
|
|
1
|
+
/** Building the pi command line for one run — pure argv construction with no subprocess or
|
|
2
2
|
* file I/O. Split out of pi.ts; the child-process integration (runPi) now lives in
|
|
3
3
|
* src/agent/run-agent.ts and the run's result types in src/pi/pi-run-result.ts, while
|
|
4
4
|
* test/pi-args.test.ts pins how config and session choices shape the command line. */
|
|
@@ -9,8 +9,9 @@ import { fileURLToPath } from "node:url";
|
|
|
9
9
|
* oversized tool results, context-shake then reclaims old bulky results at 70% of the window,
|
|
10
10
|
* context-budget appends its context-usage note to the (already bounded) result that crosses a
|
|
11
11
|
* threshold, strip-thinking drops the model's replayed thinking from each request on a
|
|
12
|
-
* small-window chat-completions model,
|
|
13
|
-
* system prompt
|
|
12
|
+
* small-window chat-completions model, trim-system-prompt drops pi's docs section from the
|
|
13
|
+
* system prompt, and write-guard refuses an edit or write outside the run's worktree. Notes ride
|
|
14
|
+
* the `tumwater-notes` command on
|
|
14
15
|
* every backend from part 2/4 on, so the role-notes extension is no longer bundled. */
|
|
15
16
|
export function bundledExtensionPaths() {
|
|
16
17
|
return [
|
|
@@ -19,6 +20,7 @@ export function bundledExtensionPaths() {
|
|
|
19
20
|
"context-budget.js",
|
|
20
21
|
"strip-thinking.js",
|
|
21
22
|
"trim-system-prompt.js",
|
|
23
|
+
"write-guard.js",
|
|
22
24
|
].map((file) => fileURLToPath(new URL(`../pi-extension/${file}`, import.meta.url)));
|
|
23
25
|
}
|
|
24
26
|
/** pi 1.2.0's built-in extensions other than `mcp`, read from pi's own `dist/extensions/index.js`.
|
|
@@ -29,7 +31,7 @@ export function bundledExtensionPaths() {
|
|
|
29
31
|
* otherwise unchanged. A pi bump that renames or adds a built-in is a visible diff here; doctor
|
|
30
32
|
* prints the same names so a package meant for the team does not vanish silently. */
|
|
31
33
|
export const PI_KEPT_BUILTINS = ["llama.cpp", "codemode", "tool-search"];
|
|
32
|
-
/** Build the pi argv for one
|
|
34
|
+
/** Build the pi argv for one run: the harness's own flags, the bundled extensions, then the
|
|
33
35
|
* user's config.piArgs (so a user flag still wins). */
|
|
34
36
|
export function piArgs(opts) {
|
|
35
37
|
const { config } = opts;
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* stderr exit rules, and the model-fallback-clone warning — so src/agent/run-agent.ts stays
|
|
5
5
|
* backend-neutral. The claude adapter registers alongside it in src/agent/run-agent.ts. */
|
|
6
6
|
import { piArgs } from "./pi-args.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { resolveBinForBackend } from "./pi-bin.js";
|
|
8
|
+
import { backendBaseEnv, withNotesPath } from "../process/run-marker.js";
|
|
9
9
|
import { isPermanentConfigError, matchBackendFailure } from "./pi-failure.js";
|
|
10
10
|
import { hasResumableSession, sessionResumable } from "../agent/session-ledger.js";
|
|
11
|
-
/** pi crashing on malformed JSON, as Node's JSON.parse phrases it on pi's stderr — five
|
|
11
|
+
/** pi crashing on malformed JSON, as Node's JSON.parse phrases it on pi's stderr — five runs in
|
|
12
12
|
* the first 18 days died this way (one of them 2 h 39 m of director work on a fresh steering
|
|
13
13
|
* prompt), each traced to a torn chunk from the model server rather than to the session. Matched
|
|
14
14
|
* against the child's stderr at exit; exported for tests. */
|
|
@@ -29,7 +29,7 @@ export const piBackend = {
|
|
|
29
29
|
defaultBin: "pi",
|
|
30
30
|
binEnv: "TUMWATER_PI_BIN",
|
|
31
31
|
resolveBin(config) {
|
|
32
|
-
return
|
|
32
|
+
return resolveBinForBackend(config, this);
|
|
33
33
|
},
|
|
34
34
|
invocation(run) {
|
|
35
35
|
// The prompt rides on stdin, never argv: pi --print reads a piped stdin to EOF as the first
|
|
@@ -43,7 +43,7 @@ export const piBackend = {
|
|
|
43
43
|
continueSession: run.continueSession,
|
|
44
44
|
agentBin: run.agentBin,
|
|
45
45
|
});
|
|
46
|
-
const env = withNotesPath(
|
|
46
|
+
const env = withNotesPath(backendBaseEnv(run.runMarker, undefined, run.binDir), run.notesPath);
|
|
47
47
|
return { args, stdin: run.prompt, env };
|
|
48
48
|
},
|
|
49
49
|
translator() {
|
|
@@ -63,7 +63,7 @@ export const piBackend = {
|
|
|
63
63
|
if (info.killed)
|
|
64
64
|
return {};
|
|
65
65
|
// A nonzero exit whose stderr ends in a JSON.parse failure is pi dying on a torn server
|
|
66
|
-
// chunk: transient, retryable with --continue (the
|
|
66
|
+
// chunk: transient, retryable with --continue (the runner decides).
|
|
67
67
|
if (info.code !== 0 && TRANSIENT_PI_CRASH.test(info.stderr))
|
|
68
68
|
return { transientPiCrash: true };
|
|
69
69
|
// A provider-wide backend failure printed on pi's stderr (a severed stream, the provider's
|