tumwater 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +55 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +6 -4
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +404 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +281 -55
- package/dist/src/backlog/backlog-cli-view.js +255 -0
- package/dist/src/backlog/backlog-cli.js +91 -335
- package/dist/src/backlog/backlog-commit.js +20 -13
- package/dist/src/backlog/backlog-eligibility.js +193 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +264 -0
- package/dist/src/backlog/backlog-release.js +134 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-guardrails.js +136 -0
- package/dist/src/baseline/main-red.js +153 -36
- package/dist/src/baseline/main-watch.js +232 -0
- package/dist/src/brief/brief-edit.js +12 -12
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget-fallback-view.js +288 -0
- package/dist/src/budget/budget-wiring.js +158 -0
- package/dist/src/budget/budget.js +31 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +65 -3
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +181 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +183 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +291 -598
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-review-commands.js +113 -0
- package/dist/src/cli/cli-role-command.js +525 -0
- package/dist/src/cli/cli-start-summary.js +167 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +193 -237
- package/dist/src/cli/completion.js +169 -22
- package/dist/src/cli/config-commands.js +58 -26
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +258 -82
- package/dist/src/cli/log-commands.js +164 -85
- package/dist/src/cli/question-commands.js +211 -10
- package/dist/src/cli.js +173 -45
- package/dist/src/collections.js +56 -13
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +16 -1
- package/dist/src/config/config-fallbacks.js +94 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +169 -222
- package/dist/src/config/config-views.js +136 -54
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +164 -265
- package/dist/src/config/config.js +53 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +330 -0
- package/dist/src/doctor/doctor-backlog-plans.js +398 -0
- package/dist/src/doctor/doctor-backlog.js +249 -512
- package/dist/src/doctor/doctor-check-names.js +85 -0
- package/dist/src/doctor/doctor-checks.js +61 -593
- package/dist/src/doctor/doctor-claude-checks.js +142 -0
- package/dist/src/doctor/doctor-codex-checks.js +276 -0
- package/dist/src/doctor/doctor-contention-checks.js +506 -0
- package/dist/src/doctor/doctor-fallback-checks.js +130 -0
- package/dist/src/doctor/doctor-holds.js +80 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +216 -537
- package/dist/src/doctor/doctor-notify.js +9 -5
- package/dist/src/doctor/doctor-opencode-checks.js +164 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-pi-checks.js +62 -0
- package/dist/src/doctor/doctor-project-checks.js +397 -0
- package/dist/src/doctor/doctor.js +126 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +21 -12
- package/dist/src/events/event-format.js +185 -89
- package/dist/src/events/event-labels.js +11 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +52 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +80 -26
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +65 -60
- package/dist/src/failure/failure-render.js +29 -21
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +35 -35
- package/dist/src/files/file-queue.js +17 -0
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +88 -225
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +101 -143
- package/dist/src/gates/maintenance-quota.js +37 -30
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +89 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +54 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +43 -19
- package/dist/src/gui/gui-backlog-endpoints.js +156 -0
- package/dist/src/gui/gui-command.js +26 -13
- package/dist/src/gui/gui-config-commands.js +168 -80
- package/dist/src/gui/gui-endpoint-commands.js +5 -4
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +235 -13
- package/dist/src/gui/gui-prompt-commands.js +26 -20
- package/dist/src/gui/gui-report-endpoints.js +97 -0
- package/dist/src/gui/gui-server.js +26 -5
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +155 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +190 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +28 -17
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +58 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +45 -19
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +214 -0
- package/dist/src/merge/merge-queue-render.js +48 -11
- package/dist/src/merge/merge-queue.js +52 -15
- package/dist/src/merge/merge-requeue.js +103 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +27 -11
- package/dist/src/merge/merge-to-main.js +77 -26
- package/dist/src/merge/merge-top.js +83 -0
- package/dist/src/merge/merge-verify.js +75 -18
- package/dist/src/notes-cli.js +35 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +352 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +71 -370
- package/dist/src/orchestrator/orchestrator.js +129 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +245 -0
- package/dist/src/orchestrator/scheduling-skip.js +195 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +126 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +26 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +150 -217
- package/dist/src/prompt/notes-backlog.js +184 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +131 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +188 -124
- package/dist/src/report/report-fold.js +130 -54
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +136 -65
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +23 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/diff-rules.js +53 -0
- package/dist/src/review/known-flakes.js +112 -1
- package/dist/src/review/post-merge-review-accept.js +51 -0
- package/dist/src/review/post-merge-review-render.js +112 -0
- package/dist/src/review/post-merge-review.js +239 -0
- package/dist/src/review/protected-edits.js +24 -10
- package/dist/src/review/quarantine-render.js +65 -0
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +180 -401
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +127 -12
- package/dist/src/roles/role-guidance.js +65 -20
- package/dist/src/roles/role-labels.js +7 -5
- package/dist/src/roles/role-render.js +108 -56
- package/dist/src/roles/role-view.js +95 -56
- package/dist/src/roles/roles.js +33 -33
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/ci-parity.js +121 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/run/qa-coverage.js +125 -0
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +175 -0
- package/dist/src/run/run-detail-render.js +91 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +73 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +122 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +170 -83
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +105 -57
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +178 -0
- package/dist/src/run/stage-checks-shared.js +65 -0
- package/dist/src/run/stage-name-checks.js +204 -0
- package/dist/src/run/stage-path-checks.js +231 -0
- package/dist/src/run/stage-prose-checks.js +261 -0
- package/dist/src/runner/leftover.js +216 -0
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +191 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +109 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +39 -18
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +236 -245
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +103 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claim-entries.js +49 -0
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +49 -17
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +43 -28
- package/dist/src/status/status-roles.js +50 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +7 -8
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +65 -18
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +60 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +78 -13
- package/dist/src/ui/badges.js +99 -38
- package/dist/src/ui/gui/gui-client-backlog.js +314 -0
- package/dist/src/ui/gui/gui-client-boot.js +89 -61
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +254 -0
- package/dist/src/ui/gui/gui-client-drawer.js +155 -289
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +437 -68
- package/dist/src/ui/gui/gui-client-labels.js +6 -3
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +60 -52
- package/dist/src/ui/gui/gui-client-pending.js +405 -24
- package/dist/src/ui/gui/gui-client-report-chart.js +492 -0
- package/dist/src/ui/gui/gui-client-report.js +105 -430
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +163 -5
- package/dist/src/ui/gui/gui-client-team.js +36 -465
- package/dist/src/ui/gui/gui-client.js +38 -26
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +10 -7
- package/dist/src/ui/gui/gui-styles.js +38 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +33 -32
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +364 -49
- package/dist/src/ui/status-render.js +109 -82
- package/dist/src/ui/team-alerts.js +728 -62
- package/dist/src/ui/tone.js +12 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +53 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +4 -12
- package/dist/src/ui/tui/tui-editor-backends.js +127 -0
- package/dist/src/ui/tui/tui-editor-brief.js +14 -36
- package/dist/src/ui/tui/tui-editor-budget.js +36 -39
- package/dist/src/ui/tui/tui-editor-check.js +29 -0
- package/dist/src/ui/tui/tui-editor-checks.js +28 -0
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +25 -0
- package/dist/src/ui/tui/tui-editor-config.js +99 -0
- package/dist/src/ui/tui/tui-editor-entry.js +39 -64
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +46 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +117 -0
- package/dist/src/ui/tui/tui-editor-interval.js +29 -16
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +9 -29
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +95 -41
- package/dist/src/ui/tui/tui-editor-retire.js +5 -13
- package/dist/src/ui/tui/tui-editor-role-enabled.js +126 -0
- package/dist/src/ui/tui/tui-editor-role-key.js +71 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +101 -34
- package/dist/src/ui/tui/tui-editor-slots.js +24 -0
- package/dist/src/ui/tui/tui-editors.js +44 -2
- package/dist/src/ui/tui/tui-frame.js +68 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +33 -9
- package/dist/src/ui/tui/tui-pane-activity.js +35 -19
- package/dist/src/ui/tui/tui-pane-backlog.js +198 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +168 -8
- package/dist/src/ui/tui/tui-pane-history.js +446 -82
- package/dist/src/ui/tui/tui-pane-pending.js +539 -15
- package/dist/src/ui/tui/tui-pane-queued.js +78 -57
- package/dist/src/ui/tui/tui-pane-report.js +54 -16
- package/dist/src/ui/tui/tui-pane-session.js +34 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +91 -28
- package/dist/src/ui/tui/tui-panes.js +153 -34
- package/dist/src/ui/tui/tui.js +18 -15
- package/dist/src/verdict/fix-claim.js +129 -33
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +77 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/leftover.js +0 -130
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/qa-coverage.js +0 -108
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** How a role's id shows up in words: an instance id as `feature #2`. Pure, no I/O, so core
|
|
3
2
|
* modules and the UI may both import it. */
|
|
4
|
-
import { baseRoleOf, instanceIndex } from "./
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
3
|
+
import { baseRoleOf, instanceIndex } from "./runner-ids.js";
|
|
4
|
+
/** The shared display labels that differ from a role's id (the shared table every surface that
|
|
5
|
+
* shows a role label reads through roleLabel, and the dashboard client's hand-kept copy). ci
|
|
6
|
+
* renders as "CI"; every other id — a bare role, a custom role, an instance — renders as its id. */
|
|
7
|
+
export const ROLE_LABELS = { ci: "CI" };
|
|
7
8
|
export function roleLabel(runnerId) {
|
|
8
9
|
const base = baseRoleOf(runnerId);
|
|
9
|
-
|
|
10
|
+
const label = Object.prototype.hasOwnProperty.call(ROLE_LABELS, base) ? ROLE_LABELS[base] : base;
|
|
11
|
+
return base === runnerId ? label : `${label} #${instanceIndex(runnerId)}`;
|
|
10
12
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { joinParts } from "../text/text.js";
|
|
2
2
|
import { agree, shortSpanPhrase } from "../text/phrases.js";
|
|
3
3
|
import { compactTokens, usd } from "../text/format.js";
|
|
4
|
-
import { clockHm, formatTimestamp,
|
|
4
|
+
import { clockHm, formatAge, formatTimestamp, humanAgo, nextRunPhrase, secondsUntil } from "../text/datetime.js";
|
|
5
5
|
import { claudeWindowLabel } from "../agent/claude/claude-account.js";
|
|
6
|
+
import { windowLabel } from "../agent/subscription-account.js";
|
|
7
|
+
import { backendDefaultLabel, backendDisplayName } from "../agent/backend-traits.js";
|
|
6
8
|
import { yieldMultiplierSuffix } from "../scheduling/backoff.js";
|
|
7
9
|
import { quietWindowEnd } from "../scheduling/quiet-hours.js";
|
|
8
|
-
|
|
9
|
-
/** The terminal's view of one loop — what `tumwater role <id>` prints, rendered as Markdown
|
|
10
|
+
/** The terminal's view of one role — what `tumwater role <id>` prints, rendered as Markdown
|
|
10
11
|
* from the payload role-view.ts's rolePayload collects (the same document `--json` prints).
|
|
11
12
|
* Like backlog-render.ts, the renderer owns no collection of its own: the CLI's --json and
|
|
12
13
|
* human branches share one collection through sayJsonOrRender's thunk, so the two surfaces
|
|
@@ -15,7 +16,7 @@ import { isAgentId } from "../config/model-selector.js";
|
|
|
15
16
|
* prose-and-shell markdown the operator may copy verbatim — with the fence grown past any
|
|
16
17
|
* backtick run the text itself contains, so a prompt that quotes a fence still round-trips.
|
|
17
18
|
* Unset things render as explicit `_(none)_` lines rather than disappearing, so an
|
|
18
|
-
* un-overridden
|
|
19
|
+
* un-overridden role reads as fully defaulted, not as a truncated report. */
|
|
19
20
|
/** A code fence one longer than any backtick run in the fenced text, so the block always
|
|
20
21
|
* closes where the text itself would have ended it. */
|
|
21
22
|
function fenceFor(text) {
|
|
@@ -31,22 +32,50 @@ function fencedOrNone(label, text, noneNote = "none") {
|
|
|
31
32
|
const fence = fenceFor(text);
|
|
32
33
|
return [`## ${label}`, "", fence, text.replace(/\n+$/, ""), fence, ""];
|
|
33
34
|
}
|
|
34
|
-
/** The
|
|
35
|
-
* lines — the read-only inspection the TUI's
|
|
36
|
-
* so the terminal and the CLI show one
|
|
35
|
+
/** The Notes and Next run prompt blocks and the "more waits" disclosure, as Markdown
|
|
36
|
+
* lines — the read-only inspection the TUI's notes view and `tumwater role <id>` share,
|
|
37
|
+
* so the terminal and the CLI show one role's notes and assembled prompt identically.
|
|
37
38
|
* `renderRoleMarkdown` splices these at the same position, so the extracted function and the
|
|
38
39
|
* full document cannot drift. */
|
|
39
|
-
export function inspectMarkdownLines(p) {
|
|
40
|
+
export function inspectMarkdownLines(p, now = Date.now()) {
|
|
40
41
|
const running = chainStepLine(p);
|
|
41
|
-
return [...(running ? [running, ""] : []), ...inspectBodyLines(p)];
|
|
42
|
+
return [...(running ? [running, ""] : []), ...inspectBodyLines(p, now)];
|
|
42
43
|
}
|
|
43
|
-
/** The
|
|
44
|
+
/** The notes, prompt and disclosure blocks alone — what renderRoleMarkdown splices after
|
|
44
45
|
* its own Team lines, which already carry the fallback-step bullet. */
|
|
45
|
-
function inspectBodyLines(p) {
|
|
46
|
+
function inspectBodyLines(p, now) {
|
|
46
47
|
const lines = [];
|
|
47
48
|
lines.push(...fencedOrNone("Notes", p.notes, "none yet — the role's own earlier runs write them, and the director has none"));
|
|
49
|
+
// The operator twin of the `<role-notes>` prompt block's save age: name when the note was
|
|
50
|
+
// last saved, so a note from five minutes ago and one from five days ago read differently.
|
|
51
|
+
// Present only when there is a note (noteSavedAt is null with none), so a note-less role's
|
|
52
|
+
// render is byte-identical to today's.
|
|
53
|
+
if (p.noteSavedAt !== null) {
|
|
54
|
+
lines.push(`_Last saved ${formatTimestamp(p.noteSavedAt)} (${humanAgo(p.noteSavedAt, now)}) — a snapshot of the past; verify its claims against the code._`);
|
|
55
|
+
}
|
|
56
|
+
// The qa observer's flow-coverage ledger (role-view.ts's flowCoverage, qa-coverage.ts's
|
|
57
|
+
// coverageRows): each flow's last exercise and result, in the same order and wording family
|
|
58
|
+
// as the prompt block (never-exercised first, then stalest-first), without the prompt's
|
|
59
|
+
// intro sentence — the operator twin of the ledger that is otherwise the observer's only
|
|
60
|
+
// memory. Present only for qa, so every other role's render stays byte-identical.
|
|
61
|
+
if (p.flowCoverage) {
|
|
62
|
+
lines.push("## Flow coverage", "");
|
|
63
|
+
for (const row of p.flowCoverage) {
|
|
64
|
+
if (row.lastRunAt === null) {
|
|
65
|
+
lines.push(`- ${row.flow}: never exercised`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const age = formatAge(now - row.lastRunAt);
|
|
69
|
+
const status = row.result === "bug"
|
|
70
|
+
? `bug filed (BUGS.md: "${row.summary ?? "see BUGS.md"}")`
|
|
71
|
+
: "passed";
|
|
72
|
+
lines.push(`- ${row.flow}: ${age} ago, ${status}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
lines.push("");
|
|
76
|
+
}
|
|
48
77
|
lines.push(...fencedOrNone("Next run's prompt", p.nextPrompt, "nothing to do this run"));
|
|
49
|
-
//
|
|
78
|
+
// run-prompt.ts dequeues exactly one queued prompt per run, so with more than one
|
|
50
79
|
// waiting the block above shows only the oldest — say so, so the count line and the
|
|
51
80
|
// block never read as a contradiction (the 2026-10-04 BUGS.md entry under ## Fixed).
|
|
52
81
|
if (p.inboxCount > 1 && p.nextPrompt !== null && p.nextPrompt.trim() !== "") {
|
|
@@ -59,12 +88,13 @@ function inspectBodyLines(p) {
|
|
|
59
88
|
* `model` alone when only the model is (the join simply drops unset halves) — shared by the
|
|
60
89
|
* main line and the budget-fallback line, so the two render the same wiring the same way. */
|
|
61
90
|
function modelPair(provider, model) {
|
|
62
|
-
return [provider, model]
|
|
91
|
+
return joinParts([provider, model], "/");
|
|
63
92
|
}
|
|
64
93
|
/** The backend's own-default label when no model resolves: `<agent> default` — pi's
|
|
65
|
-
* historical `pi default` for the pi backend, `claude default` for claude (part 4f/7)
|
|
66
|
-
|
|
67
|
-
|
|
94
|
+
* historical `pi default` for the pi backend, `claude default` for claude (part 4f/7),
|
|
95
|
+
* shared with the status rows through `backendDefaultLabel`. */
|
|
96
|
+
function backendDefault(p) {
|
|
97
|
+
return backendDefaultLabel(p.backend);
|
|
68
98
|
}
|
|
69
99
|
/** The provider/model wiring as one readable token: `provider/model` when both resolve,
|
|
70
100
|
* `model` alone when only the model is named, and the backend-default note when neither is.
|
|
@@ -75,11 +105,11 @@ function modelLine(p) {
|
|
|
75
105
|
// level (piDefault is formatted with the effective thinking winning), so the separate
|
|
76
106
|
// ` (thinking: …)` suffix is dropped for this case only.
|
|
77
107
|
if (p.piDefault)
|
|
78
|
-
return `${
|
|
108
|
+
return `${backendDefault(p)} (${p.piDefault})`;
|
|
79
109
|
const pair = modelPair(p.provider, p.model);
|
|
80
110
|
const thinking = p.thinking ? ` (thinking: ${p.thinking})` : "";
|
|
81
111
|
if (!pair)
|
|
82
|
-
return `${
|
|
112
|
+
return `${backendDefault(p)}${thinking}`;
|
|
83
113
|
const agent = p.backend !== "pi" ? `${p.backend}/` : "";
|
|
84
114
|
return `${agent}${pair}${thinking}`;
|
|
85
115
|
}
|
|
@@ -89,9 +119,8 @@ function modelLine(p) {
|
|
|
89
119
|
* backend-default label. One home for the Model fallback and Budget fallback lines, so a
|
|
90
120
|
* claude fallback reads `claude/claude-sonnet-5-5`, not a bare id (PLANS.md "Mixed claude +
|
|
91
121
|
* pi fleets, part 3/4" gap 7). */
|
|
92
|
-
function fallbackPairLabel(fb,
|
|
93
|
-
const agentBackend =
|
|
94
|
-
(fb.provider !== undefined && isAgentId(fb.provider) ? fb.provider : undefined);
|
|
122
|
+
function fallbackPairLabel(fb, backendDefault) {
|
|
123
|
+
const agentBackend = fb.backend !== undefined && fb.backend !== "pi" ? fb.backend : undefined;
|
|
95
124
|
if (fb.model !== undefined) {
|
|
96
125
|
if (agentBackend !== undefined)
|
|
97
126
|
return `${agentBackend}/${fb.model}`;
|
|
@@ -99,12 +128,27 @@ function fallbackPairLabel(fb, agentDefault) {
|
|
|
99
128
|
}
|
|
100
129
|
if (fb.provider !== undefined)
|
|
101
130
|
return fb.provider;
|
|
102
|
-
return
|
|
131
|
+
return backendDefault;
|
|
103
132
|
}
|
|
104
|
-
/**
|
|
105
|
-
|
|
133
|
+
/** The backend-and-window label the role view shows for a non-claude backend's window:
|
|
134
|
+
* `backendDisplayName(billingBackend)` beside `windowLabel(windowType)` — "Codex 7d" for a
|
|
135
|
+
* codex subscription (plans/codex-backend.md part 3c/9), so a reader knows whose window it
|
|
136
|
+
* is. Claude keeps today's bare window type ("5h") so its role view stays byte-identical. */
|
|
137
|
+
function billingWindowLabel(billingBackend, windowType) {
|
|
138
|
+
const type = windowType !== undefined ? windowLabel(windowType) : "";
|
|
139
|
+
const backend = billingBackend !== undefined && billingBackend !== "claude" ? backendDisplayName(billingBackend) : "";
|
|
140
|
+
return [backend, type].filter(Boolean).join(" ");
|
|
141
|
+
}
|
|
142
|
+
/** Why a tier moved down its fallback chain, as the role view words it. The window phrase
|
|
143
|
+
* names the backend in play ("Codex 7d window used up") when a non-claude backend moved the
|
|
144
|
+
* role; claude keeps today's wording byte-identical, and an unknown backend falls back to
|
|
145
|
+
* today's hardcoded "Claude". */
|
|
146
|
+
function chainReasonPhrase(reason, billingBackend, windowType) {
|
|
106
147
|
switch (reason) {
|
|
107
148
|
case "window":
|
|
149
|
+
if (billingBackend !== undefined && billingBackend !== "claude") {
|
|
150
|
+
return `${billingWindowLabel(billingBackend, windowType)} window used up`;
|
|
151
|
+
}
|
|
108
152
|
return `${windowType !== undefined ? claudeWindowLabel(windowType) : "Claude"} window used up`;
|
|
109
153
|
case "reserve":
|
|
110
154
|
return "window reserve reached";
|
|
@@ -125,10 +169,10 @@ function chainStepLine(p) {
|
|
|
125
169
|
if (!c)
|
|
126
170
|
return null;
|
|
127
171
|
const resets = c.returnsAt !== undefined ? `, resets ${clockHm(c.returnsAt)}` : "";
|
|
128
|
-
return `- Running on fallback ${c.step} of ${c.of} (${chainReasonPhrase(c.reason, p.billingWindow)}${resets})`;
|
|
172
|
+
return `- Running on fallback ${c.step} of ${c.of} (${chainReasonPhrase(c.reason, p.billingBackend, p.billingWindow)}${resets})`;
|
|
129
173
|
}
|
|
130
|
-
/** One recent
|
|
131
|
-
* <summary>` — so `tumwater role <id>` and the TUI
|
|
174
|
+
/** One recent run outcome as a Markdown bullet line — `<time> · <result> · <span> —
|
|
175
|
+
* <summary>` — so `tumwater role <id>` and the TUI notes view read a role's discrete
|
|
132
176
|
* outcomes at a glance. `time` is the same local `YYYY-MM-DD HH:MM:SS` stamp the model-
|
|
133
177
|
* fallback `since` prints (formatTimestamp); `span` is the same short-duration phrasing
|
|
134
178
|
* shortSpanPhrase renders for holdPhrase and the event feed's countdowns; the summary is
|
|
@@ -142,29 +186,29 @@ function recentOutcomeLine(o) {
|
|
|
142
186
|
line += ` — ${o.summary}`;
|
|
143
187
|
return line;
|
|
144
188
|
}
|
|
145
|
-
/** One quiet-hours bullet: the window, whose it is, and whether it holds the
|
|
189
|
+
/** One quiet-hours bullet: the window, whose it is, and whether it holds the role now — with
|
|
146
190
|
* the same `quiet until <end>` text the status table uses. */
|
|
147
191
|
function quietHoursLine(w) {
|
|
148
192
|
const whose = w.scope === "role" ? "own window" : "team window";
|
|
149
193
|
const state = w.inWindow ? `holding now — quiet until ${quietWindowEnd(w.window)}` : "not holding now";
|
|
150
194
|
return `- Quiet hours: ${w.window} (${whose}; ${state})`;
|
|
151
195
|
}
|
|
152
|
-
/** The
|
|
196
|
+
/** The role's schedule as Markdown bullet lines — `Next run`, `Last run`, then one
|
|
153
197
|
* `Quiet hours` line per governing window (none when the payload carries no windows) — in the
|
|
154
198
|
* same words and wording family as the team surface's `next run` cell (status-render.ts's
|
|
155
|
-
* nextRunCell), so the role view and the status table cannot drift on when a
|
|
156
|
-
* a never-scheduled
|
|
199
|
+
* nextRunCell), so the role view and the status table cannot drift on when a role acts next:
|
|
200
|
+
* a never-scheduled role (nextRunAt 0) reads `not scheduled yet`; a due role reads `due now`;
|
|
157
201
|
* a future one reads `in <Ns>` through humanSeconds, prefixed `backoff ` while backoffSeconds
|
|
158
202
|
* > 0 (the wake row-action clears exactly that) — the shared nextRunPhrase, so the role view
|
|
159
203
|
* and the status `next run` cell cannot drift on the backoff prefix or the humanSeconds
|
|
160
|
-
* bucketing. `Last
|
|
161
|
-
* status `last
|
|
204
|
+
* bucketing. `Last run` reuses formatTimestamp and the same `humanSeconds … ago` phrasing the
|
|
205
|
+
* status `last run` cell ages with, or `never` for a role that has not run. `now` is
|
|
162
206
|
* injected (default Date.now()) so the renderer stays a pure function of the payload and the
|
|
163
207
|
* test can pin a fixed clock. */
|
|
164
208
|
function scheduleLine(p, now) {
|
|
165
209
|
// The yield multiplier rides the line as `×N` exactly like nextRunCell/fmtNextRun: a quiet
|
|
166
|
-
// yield-scaled
|
|
167
|
-
// gates on the multiplier too), so the Schedule must not understate when the
|
|
210
|
+
// yield-scaled role's effective gap is longer than nextRunAt's countdown shows (isEligible
|
|
211
|
+
// gates on the multiplier too), so the Schedule must not understate when the role acts next.
|
|
168
212
|
const suffix = yieldMultiplierSuffix(p.yieldMultiplier);
|
|
169
213
|
let next;
|
|
170
214
|
if (p.nextRunAt <= 0) {
|
|
@@ -175,11 +219,11 @@ function scheduleLine(p, now) {
|
|
|
175
219
|
next = nextRunPhrase(remain, p.backoffSeconds > 0, "due now", true) + suffix;
|
|
176
220
|
}
|
|
177
221
|
const last = p.lastRunEndedAt !== undefined
|
|
178
|
-
? `${formatTimestamp(p.lastRunEndedAt)} (${
|
|
222
|
+
? `${formatTimestamp(p.lastRunEndedAt)} (${humanAgo(p.lastRunEndedAt, now)})`
|
|
179
223
|
: "never";
|
|
180
224
|
return [`- Next run: ${next}`, `- Last run: ${last}`, ...(p.quietHours ?? []).map(quietHoursLine)];
|
|
181
225
|
}
|
|
182
|
-
/** Render one
|
|
226
|
+
/** Render one role's inspection payload as Markdown. `now` is injected (default Date.now())
|
|
183
227
|
* so the schedule lines stay a pure function of the payload — the test pins a fixed clock. */
|
|
184
228
|
export function renderRoleMarkdown(p, now = Date.now()) {
|
|
185
229
|
const lines = [`# tumwater role: ${p.id}`, ""];
|
|
@@ -194,15 +238,15 @@ export function renderRoleMarkdown(p, now = Date.now()) {
|
|
|
194
238
|
// unresolvable pair, a model with no declared window).
|
|
195
239
|
lines.push(`- Context window: ${p.contextWindow === null ? "unknown" : `${compactTokens(p.contextWindow)} tokens`}`);
|
|
196
240
|
// Per-provider concurrency cap (plans/provider-concurrency.md §8): name the key whose cap
|
|
197
|
-
// bounds the role's concurrent
|
|
241
|
+
// bounds the role's concurrent runs, plus the cap itself. Present only while
|
|
198
242
|
// `maxConcurrentPerProvider` maps this seam's key — a cap-less default team has no
|
|
199
243
|
// resolvable key entry, so its role view renders no new line and stays byte-identical.
|
|
200
244
|
if (p.providerKey !== undefined && p.providerCap !== undefined) {
|
|
201
245
|
lines.push(`- Provider: ${p.providerKey} (cap ${p.providerCap})`);
|
|
202
246
|
}
|
|
203
|
-
// Image input (plans/image-input.md "Surfaces", part 5/5): whether this
|
|
204
|
-
// reads images, and — when it cannot — where a
|
|
205
|
-
// `yes`/`no`: a text-only
|
|
247
|
+
// Image input (plans/image-input.md "Surfaces", part 5/5): whether this role's own model
|
|
248
|
+
// reads images, and — when it cannot — where a run that reads an image reroutes. Not just
|
|
249
|
+
// `yes`/`no`: a text-only role that falls back names the target, so `tumwater role <id>`
|
|
206
250
|
// explains the team alert without running doctor. Unknown (null) renders `unknown` rather
|
|
207
251
|
// than guessing.
|
|
208
252
|
const images = p.imageInput === true
|
|
@@ -213,14 +257,20 @@ export function renderRoleMarkdown(p, now = Date.now()) {
|
|
|
213
257
|
: "no"
|
|
214
258
|
: "unknown";
|
|
215
259
|
lines.push(`- Images: ${images}`);
|
|
260
|
+
// Whether the review gate reviews this role's commits after they merge (role-view.ts's
|
|
261
|
+
// reviewedAfterMerge). Present only while review.enabled is on and review.afterMerge lists
|
|
262
|
+
// the role's base id — a pre-merge-reviewed role or a gate-off config omits the line.
|
|
263
|
+
if (p.reviewedAfterMerge) {
|
|
264
|
+
lines.push(`- Review: after merge (a rejected change stays on main with the reviewer's recorded reasons)`);
|
|
265
|
+
}
|
|
216
266
|
// Model failure fallback, part 2/2: name the off-model pair, when the episode began, and
|
|
217
267
|
// the provider-class failure that tripped it, so `tumwater role <id>` explains the state.
|
|
218
268
|
if (p.modelFallback) {
|
|
219
|
-
const pair = fallbackPairLabel(p.modelFallback,
|
|
269
|
+
const pair = fallbackPairLabel(p.modelFallback, backendDefault(p));
|
|
220
270
|
lines.push(`- Model fallback: ${pair} — on fallback since ${formatTimestamp(p.modelFallback.since)} (primary failing: ${p.modelFallback.reason})`);
|
|
221
271
|
}
|
|
222
272
|
if (p.fallback) {
|
|
223
|
-
const pair = fallbackPairLabel(p.fallback,
|
|
273
|
+
const pair = fallbackPairLabel(p.fallback, backendDefault(p));
|
|
224
274
|
lines.push(`- Over-cap model: ${pair} (${p.fallbackFree ? "free" : "priced"})`);
|
|
225
275
|
}
|
|
226
276
|
const running = chainStepLine(p);
|
|
@@ -229,17 +279,19 @@ export function renderRoleMarkdown(p, now = Date.now()) {
|
|
|
229
279
|
// The claude seam's billing (plans/agent-backends.md §7/§8, PLANS.md part 6d/7): absent on
|
|
230
280
|
// a pi seam, so its role view is byte-identical to before.
|
|
231
281
|
if (p.billing) {
|
|
232
|
-
const window = p.billing === "subscription" && p.billingWindow
|
|
282
|
+
const window = p.billing === "subscription" && p.billingWindow
|
|
283
|
+
? ` (${billingWindowLabel(p.billingBackend, p.billingWindow)} window)`
|
|
284
|
+
: "";
|
|
233
285
|
lines.push(`- Billing: ${p.billing === "api" ? "API" : p.billing}${window}`);
|
|
234
286
|
}
|
|
235
287
|
lines.push(`- Min run interval: ${p.minRunIntervalSeconds}s`);
|
|
236
288
|
if (p.instances !== undefined)
|
|
237
289
|
lines.push(`- Instances: ${p.instances}`);
|
|
238
290
|
lines.push(`- Inbox: ${p.inboxCount}`);
|
|
239
|
-
// The
|
|
240
|
-
// same run_end events recentOutcomes reads): how much the
|
|
291
|
+
// The role's own spend over its retained event window (role-view.ts's usage, summed from the
|
|
292
|
+
// same run_end events recentOutcomes reads): how much the role burned on tokens and cost,
|
|
241
293
|
// with a notional suffix only when a claude-subscription seam burned non-zero notional spend
|
|
242
|
-
// (plans/agent-backends.md part 6a). Absent for a never-costly
|
|
294
|
+
// (plans/agent-backends.md part 6a). Absent for a never-costly role, so old `tumwater role`
|
|
243
295
|
// goldens are byte-identical.
|
|
244
296
|
if (p.usage) {
|
|
245
297
|
let spend = `- Spend: ${usd(p.usage.costUsd)} · ${compactTokens(p.usage.tokens)} tokens`;
|
|
@@ -248,7 +300,7 @@ export function renderRoleMarkdown(p, now = Date.now()) {
|
|
|
248
300
|
lines.push(spend);
|
|
249
301
|
}
|
|
250
302
|
// The per-role daily cap (role-view.ts's dailyCap): today's spend against the cap and whether
|
|
251
|
-
// it holds the
|
|
303
|
+
// it holds the role now. Absent without a cap, so old goldens are unchanged.
|
|
252
304
|
if (p.dailyCap) {
|
|
253
305
|
const dc = p.dailyCap;
|
|
254
306
|
let cap = `- Daily cap: ${usd(dc.spentUsd)} of ${usd(dc.capUsd)} spent today (${dc.over ? "holding now — no new runs until local midnight" : "not holding"})`;
|
|
@@ -256,14 +308,14 @@ export function renderRoleMarkdown(p, now = Date.now()) {
|
|
|
256
308
|
cap += ` · shared by ${dc.roleIds.join(", ")}`;
|
|
257
309
|
lines.push(cap);
|
|
258
310
|
}
|
|
259
|
-
// The
|
|
260
|
-
// the same persisted state): when it may
|
|
261
|
-
// place the team's `next run`/`last
|
|
311
|
+
// The role's schedule (role-view.ts's nextRunAt/backoffSeconds/lastRunEndedAt, read from
|
|
312
|
+
// the same persisted state): when it may run again, and when it last did — the one
|
|
313
|
+
// place the team's `next run`/`last run` vocabulary was absent. Rendered from the
|
|
262
314
|
// injected `now`, so the lines stay a pure function of the payload.
|
|
263
315
|
lines.push(...scheduleLine(p, now));
|
|
264
|
-
// The
|
|
265
|
-
// one line per outcome so `tumwater role <id>` shows what the
|
|
266
|
-
// what it is. Absent (never
|
|
316
|
+
// The role's recent run outcomes (role-view.ts's recentOutcomes, read from the event log):
|
|
317
|
+
// one line per outcome so `tumwater role <id>` shows what the role has been DOING, not just
|
|
318
|
+
// what it is. Absent (never run) renders nothing new, so old goldens are byte-identical.
|
|
267
319
|
if (p.recentOutcomes && p.recentOutcomes.length > 0) {
|
|
268
320
|
lines.push("", "## Recent runs", "");
|
|
269
321
|
for (const o of p.recentOutcomes)
|
|
@@ -272,6 +324,6 @@ export function renderRoleMarkdown(p, now = Date.now()) {
|
|
|
272
324
|
lines.push("");
|
|
273
325
|
lines.push(...fencedOrNone("Instructions override", p.instructions));
|
|
274
326
|
lines.push(...fencedOrNone("Find text", p.find, "none — the director is driven by its inbox, not by instructions"));
|
|
275
|
-
lines.push(...inspectBodyLines(p));
|
|
327
|
+
lines.push(...inspectBodyLines(p, now));
|
|
276
328
|
return lines.join("\n").trimEnd();
|
|
277
329
|
}
|