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,30 +1,32 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** The browser-side dashboard app inlined as the GUI page's only <script>. It polls /api/status
|
|
3
2
|
* every second and renders, in the order an operator needs them: the masthead's team status
|
|
4
3
|
* (running, build, main check) and team controls (budget, pause); alerts for whatever needs a
|
|
5
|
-
* human (a failing
|
|
6
|
-
* the composer that steers the director or one
|
|
7
|
-
* the
|
|
4
|
+
* human (a failing role, a red main, a spent budget, an old build, open questions, a pause);
|
|
5
|
+
* the composer that steers the director or one role; and the team view — today's progress,
|
|
6
|
+
* the roles grouped by what they are doing, the backlog, and the notable activity. The
|
|
8
7
|
* view-model, the drawer, the History/Usage/Failures/Pending views, the operator controls, the
|
|
9
8
|
* composer, the Markdown renderer, and the routing/poll boot live in their own modules and
|
|
10
9
|
* are spliced in below; everything shares one scope. The page
|
|
11
10
|
* cannot import the harness modules, so it keeps its own copies of the few display rules it
|
|
12
|
-
* needs (formatters,
|
|
11
|
+
* needs (formatters, role order), each pinned against its TypeScript twin by test. Written as
|
|
13
12
|
* String.raw templates so the served script is exactly the text below — no double escaping. */
|
|
13
|
+
import { GUI_CLIENT_BACKLOG_JS } from "./gui-client-backlog.js";
|
|
14
14
|
import { GUI_CLIENT_BOOT_JS } from "./gui-client-boot.js";
|
|
15
15
|
import { GUI_CLIENT_COMPOSER_JS } from "./gui-client-composer.js";
|
|
16
16
|
import { GUI_CLIENT_DRAWER_JS } from "./gui-client-drawer.js";
|
|
17
|
+
import { GUI_CLIENT_DRAWER_CONFIG_JS } from "./gui-client-drawer-config.js";
|
|
18
|
+
import { GUI_CLIENT_FEED_JS } from "./gui-client-feed.js";
|
|
17
19
|
import { GUI_CLIENT_TEAM_JS } from "./gui-client-team.js";
|
|
18
20
|
import { GUI_CLIENT_HISTORY_JS } from "./gui-client-history.js";
|
|
19
21
|
import { GUI_CLIENT_LABELS_JS } from "./gui-client-labels.js";
|
|
20
|
-
import {
|
|
22
|
+
import { GUI_CLIENT_ROLES_JS } from "./gui-client-roles.js";
|
|
21
23
|
import { GUI_CLIENT_MARKDOWN_JS } from "./gui-client-markdown.js";
|
|
22
24
|
import { GUI_CLIENT_MODEL_JS } from "./gui-client-model.js";
|
|
23
25
|
import { GUI_CLIENT_OPERATOR_JS } from "./gui-client-operator.js";
|
|
24
26
|
import { GUI_CLIENT_PENDING_JS } from "./gui-client-pending.js";
|
|
27
|
+
import { GUI_CLIENT_REPORT_CHART_JS } from "./gui-client-report-chart.js";
|
|
25
28
|
import { GUI_CLIENT_REPORT_JS } from "./gui-client-report.js";
|
|
26
29
|
import { GUI_CLIENT_SETTINGS_JS } from "./gui-client-settings.js";
|
|
27
|
-
import { GUI_CLIENT_SOUND_JS } from "./gui-client-sound.js";
|
|
28
30
|
import { ICON_PATHS } from "./gui-icons.js";
|
|
29
31
|
import { ACTIVE_PHASE_PREFIXES } from "../status-model.js";
|
|
30
32
|
/** The client's opening: escaping and the guarded API helpers every call goes through. Kept
|
|
@@ -86,7 +88,7 @@ const CORE_JS = String.raw ` const esc = (s) => String(s).replace(/[&<>"']/g, (
|
|
|
86
88
|
// accepts the connection but never answers
|
|
87
89
|
// would otherwise hold the poll open forever, leaving the page frozen on stale data with no
|
|
88
90
|
// offline alert — the catch in refresh() only runs when fetch rejects. The timeout aborts the
|
|
89
|
-
// request, so the poll fails, the red "Lost contact" alert shows, and
|
|
91
|
+
// request, so the poll fails, the red "Lost contact" alert shows, and polling continues.
|
|
90
92
|
// AbortSignal.timeout is standard since 2022; where a browser lacks it the fetch stays
|
|
91
93
|
// unbounded, exactly the old behavior.
|
|
92
94
|
const POLL_TIMEOUT_MS = 15000;
|
|
@@ -141,11 +143,11 @@ const FORMAT_JS = String.raw ` // format:start
|
|
|
141
143
|
const agree = (n, one, many) => (n === 1 ? one : many);
|
|
142
144
|
const plural = (n, one, many) => n + " " + agree(n, one, many || one + "s");
|
|
143
145
|
// The merged-commit work/maintenance split the sidebar's "Merged today" tile and the report's
|
|
144
|
-
// "Commits merged" tile both print. report-
|
|
146
|
+
// "Commits merged" tile both print. report-types.ts leaves the counts optional, so a missing
|
|
145
147
|
// count reads 0 here rather than "undefined".
|
|
146
148
|
const workSplit = (t) => (t.workCommits ?? 0) + " work / " + (t.maintenanceCommits ?? 0) + " maintenance";
|
|
147
149
|
// The unmerged-commit list both change views paint — each commit's sha and subject on its
|
|
148
|
-
// own clamped line. The Pending roster's Ahead cell and the
|
|
150
|
+
// own clamped line. The Pending roster's Ahead cell and the role drawer's Pending change
|
|
149
151
|
// section had the byte-identical map; a missing or non-array list paints nothing.
|
|
150
152
|
const commitRowsHtml = (commits) =>
|
|
151
153
|
(Array.isArray(commits) ? commits : []).map((c) => "<div class='mono clamp1'>" + esc(c.sha) + " " + esc(c.subject || "—") + "</div>").join("");
|
|
@@ -168,7 +170,7 @@ const FORMAT_JS = String.raw ` // format:start
|
|
|
168
170
|
};
|
|
169
171
|
// human-seconds-fmt:end
|
|
170
172
|
// active-phase-fmt:start
|
|
171
|
-
// A PERMIT-HOLDING
|
|
173
|
+
// A PERMIT-HOLDING role in flight — status-model.ts's isActivePhase. The three prefixes are
|
|
172
174
|
// interpolated from status-model.ts's ACTIVE_PHASE_PREFIXES (String.raw still substitutes),
|
|
173
175
|
// so this copy cannot drift from the server's; the running director's own director-working
|
|
174
176
|
// label is checked beside it rather than folded in, because it holds no permit (BUGS.md
|
|
@@ -176,14 +178,14 @@ const FORMAT_JS = String.raw ` // format:start
|
|
|
176
178
|
const ACTIVE_PHASE_PREFIXES = ${JSON.stringify(ACTIVE_PHASE_PREFIXES)};
|
|
177
179
|
const isActivePhase = (phase) => ACTIVE_PHASE_PREFIXES.some((p) => phase.startsWith(p));
|
|
178
180
|
// active-phase-fmt:end
|
|
179
|
-
// last-
|
|
180
|
-
// The absolute local time of a
|
|
181
|
-
// once older than a day; "-" when never
|
|
181
|
+
// last-run-fmt:start
|
|
182
|
+
// The absolute local time of a run end with its age ("14:32:05 · 3m ago"), prefixed MM-DD
|
|
183
|
+
// once older than a day; "-" when never ran — status-render.ts's lastRunCell.
|
|
182
184
|
// Whole elapsed seconds since an instant, clamped at zero and rounded to the nearest
|
|
183
|
-
// second — datetime.ts's
|
|
184
|
-
//
|
|
185
|
+
// second — datetime.ts's secondsSince (the browser runtime cannot import it), shared by
|
|
186
|
+
// fmtLastRun and fmtAgo below so the clamp cannot drift between the page's ages.
|
|
185
187
|
const ageSec = (ts) => Math.max(0, Math.round((Date.now() - ts) / 1000));
|
|
186
|
-
const
|
|
188
|
+
const fmtLastRun = (ts) => {
|
|
187
189
|
if (!ts) return "-";
|
|
188
190
|
const d = new Date(ts);
|
|
189
191
|
const p = (n) => String(n).padStart(2, "0");
|
|
@@ -193,16 +195,16 @@ const FORMAT_JS = String.raw ` // format:start
|
|
|
193
195
|
const age = humanSeconds(sec) + " ago";
|
|
194
196
|
return s + " · " + age;
|
|
195
197
|
};
|
|
196
|
-
// last-
|
|
198
|
+
// last-run-fmt:end
|
|
197
199
|
// next-run-fmt:start
|
|
198
|
-
// When an idle
|
|
200
|
+
// When an idle role may run again — status-render.ts's nextRunCell: "-" for a role in flight
|
|
199
201
|
// or parked awaiting a slot (it has no next run to speak of) and for a stopped team; "now"
|
|
200
202
|
// when due; otherwise the remaining time, prefixed "backoff " while backing off. A yield-scaled
|
|
201
203
|
// clock rides as a " ×N" suffix: a quiet role's effective gap is longer than the countdown.
|
|
202
204
|
const fmtNextRun = (l, teamRunning) => {
|
|
203
|
-
// A torn
|
|
205
|
+
// A torn role object — a payload missing its phase field — reads as the empty (inactive)
|
|
204
206
|
// phase rather than throwing: the browser copy is untyped, and its sibling phaseInfo/
|
|
205
|
-
//
|
|
207
|
+
// roleRank already coerce the same way, so one bad row must not blank the whole table.
|
|
206
208
|
const phase = String(l.phase || "");
|
|
207
209
|
const active = isActivePhase(phase) || phase.startsWith("waiting to start") || phase.startsWith("waiting for ") || phase.startsWith("director working");
|
|
208
210
|
if (!teamRunning || active) return "-";
|
|
@@ -220,7 +222,7 @@ const FORMAT_JS = String.raw ` // format:start
|
|
|
220
222
|
return sec < 60 ? "just now" : humanSeconds(sec) + " ago";
|
|
221
223
|
};
|
|
222
224
|
const fmtClock = (ts) => new Date(ts).toLocaleString([], { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
223
|
-
// A
|
|
225
|
+
// A run's duration: seconds under two minutes, then minutes, then hours. Each bucket is
|
|
224
226
|
// chosen from the rounded count so a span just under a cutoff never prints "120s" or "120m".
|
|
225
227
|
const fmtSpan = (ms) => {
|
|
226
228
|
const sec = Math.round(ms / 1000);
|
|
@@ -230,7 +232,7 @@ const FORMAT_JS = String.raw ` // format:start
|
|
|
230
232
|
return (ms / 3600000).toFixed(1) + "h";
|
|
231
233
|
};
|
|
232
234
|
// A run's wall-clock span cell: fmtSpan when a row carries a duration, a dash when it does not
|
|
233
|
-
// (a
|
|
235
|
+
// (a run whose start sits outside the window). Shared by the History table and summary rows
|
|
234
236
|
// (and any future duration cell) so the null rule and its em-dash cannot drift between them.
|
|
235
237
|
const durCell = (ms) => (ms === null || ms === undefined ? "—" : esc(fmtSpan(Number(ms))));
|
|
236
238
|
// Server text sometimes carries ISO instants (a restart cooldown's deadline); show them in
|
|
@@ -290,13 +292,23 @@ const DOM_JS = String.raw ` const ICONS = ${JSON.stringify(ICON_PATHS)};
|
|
|
290
292
|
return true;
|
|
291
293
|
}
|
|
292
294
|
// panel-build:end
|
|
295
|
+
// err-message:start
|
|
296
|
+
// The one error-message read every fetch/parse catch shares: a thrown Error's message when
|
|
297
|
+
// it has one (the server's JSON body, or the client's own throws, put it there), else the
|
|
298
|
+
// caller's fallback. Single-homed here in the core before every splice so the catch blocks
|
|
299
|
+
// cannot drift the ternary's shape; settings' clientErrorMessage feeds it String(err) as the
|
|
300
|
+
// fallback.
|
|
301
|
+
function errMessage(err, fallback) {
|
|
302
|
+
return err && err.message ? err.message : fallback;
|
|
303
|
+
}
|
|
304
|
+
// err-message:end
|
|
293
305
|
// The standard "this view could not load" panel: a title plus the server's error message,
|
|
294
306
|
// if any. cls is "empty" for the bare panels (history, drawer) and "card empty" where the
|
|
295
307
|
// view frames panels in cards (the report views). Drawer paints it through paintPanel so a
|
|
296
308
|
// retry loop does not repaint; callers that own the element assign it directly.
|
|
297
309
|
function errorPanel(title, err, cls) {
|
|
298
310
|
return "<div class='" + (cls || "empty") + "'><strong>" + esc(title) + "</strong>" +
|
|
299
|
-
esc(err
|
|
311
|
+
esc(errMessage(err, "")) + "</div>";
|
|
300
312
|
}
|
|
301
313
|
// Mark the one button of a segmented filter whose dataset[attr] matches current as
|
|
302
314
|
// "active" and clear the rest: one home for the toggle loop each of the page's segmented
|
|
@@ -349,5 +361,5 @@ const DOM_JS = String.raw ` const ICONS = ${JSON.stringify(ICON_PATHS)};
|
|
|
349
361
|
let offline = false;
|
|
350
362
|
let activeView = "team";
|
|
351
363
|
`;
|
|
352
|
-
export const GUI_CLIENT_JS = [CORE_JS, FORMAT_JS, GUI_CLIENT_LABELS_JS, GUI_CLIENT_MODEL_JS, DOM_JS, GUI_CLIENT_MARKDOWN_JS,
|
|
353
|
-
GUI_CLIENT_DRAWER_JS, GUI_CLIENT_HISTORY_JS, GUI_CLIENT_PENDING_JS, GUI_CLIENT_REPORT_JS, GUI_CLIENT_SETTINGS_JS, GUI_CLIENT_BOOT_JS].join("\n");
|
|
364
|
+
export const GUI_CLIENT_JS = [CORE_JS, FORMAT_JS, GUI_CLIENT_LABELS_JS, GUI_CLIENT_MODEL_JS, DOM_JS, GUI_CLIENT_MARKDOWN_JS, GUI_CLIENT_OPERATOR_JS, GUI_CLIENT_ROLES_JS, GUI_CLIENT_TEAM_JS, GUI_CLIENT_BACKLOG_JS, GUI_CLIENT_FEED_JS, GUI_CLIENT_COMPOSER_JS,
|
|
365
|
+
GUI_CLIENT_DRAWER_JS, GUI_CLIENT_DRAWER_CONFIG_JS, GUI_CLIENT_HISTORY_JS, GUI_CLIENT_PENDING_JS, GUI_CLIENT_REPORT_CHART_JS, GUI_CLIENT_REPORT_JS, GUI_CLIENT_SETTINGS_JS, GUI_CLIENT_BOOT_JS].join("\n");
|
|
@@ -32,8 +32,6 @@ export const ICON_PATHS = {
|
|
|
32
32
|
dot: `<circle cx="12" cy="12" r="3" ${FILLED}/>`,
|
|
33
33
|
fail: '<circle cx="12" cy="12" r="9"/><path d="M9 9l6 6M15 9l-6 6"/>',
|
|
34
34
|
offline: '<path d="M3 3l18 18M8.5 16.5a5 5 0 0 1 7 0M5 12.6a10 10 0 0 1 4.2-2.3M14.8 10.3A10 10 0 0 1 19 12.6M12 20h.01"/>',
|
|
35
|
-
sound: '<path d="M4 9.5v5h3l4.5 4v-13L7 9.5z"/><path d="M15.5 8.7a5 5 0 0 1 0 6.6M18 6.2a9 9 0 0 1 0 11.6"/>',
|
|
36
|
-
mute: '<path d="M4 9.5v5h3l4.5 4v-13L7 9.5z"/><path d="M15.5 9.5l5 5M20.5 9.5l-5 5"/>',
|
|
37
35
|
settings: '<circle cx="12" cy="12" r="3.2"/><path d="M12 3v2.6M12 18.4V21M3 12h2.6M18.4 12H21M5.6 5.6l1.9 1.9M16.5 16.5l1.9 1.9M5.6 18.4l1.9-1.9M16.5 7.5l1.9-1.9"/>',
|
|
38
36
|
};
|
|
39
37
|
/** One icon's markup — the same shape the browser script's icon() builds. */
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* views — Team's carrying a badge while something needs a human — and the team-wide
|
|
6
6
|
* controls: today's spend against the cap, and pause. The main column shows one view at a
|
|
7
7
|
* time: Team (alerts for whatever needs a human, the composer that steers the director or
|
|
8
|
-
* one
|
|
8
|
+
* one role, today's progress, every role grouped by what it is doing, the backlog, and the
|
|
9
9
|
* notable activity), History, Usage, Failures, Pending, or Settings. A drawer opens any
|
|
10
|
-
*
|
|
10
|
+
* role's detail and live transcript, or any backlog entry in full. Kept apart from
|
|
11
11
|
* gui/gui-server.ts so the server module stays about serving. */
|
|
12
12
|
import { GUI_CLIENT_JS } from "./gui-client.js";
|
|
13
13
|
import { GUI_STYLES } from "./gui-styles.js";
|
|
@@ -30,7 +30,6 @@ export const GUI_PAGE = `<!doctype html>
|
|
|
30
30
|
<div class="side-top">
|
|
31
31
|
<a class="brand" href="#team" aria-label="tumwater team">${LOGO_SVG}<span>tumwater</span></a>
|
|
32
32
|
<div class="side-top-actions">
|
|
33
|
-
<span id="soundwrap"></span>
|
|
34
33
|
<button type="button" class="icon-btn" id="themetoggle" title="Switch between light and dark" aria-label="Switch between light and dark">${iconSvg("sun", "theme-sun")}${iconSvg("moon", "theme-moon")}</button>
|
|
35
34
|
</div>
|
|
36
35
|
</div>
|
|
@@ -73,17 +72,17 @@ export const GUI_PAGE = `<!doctype html>
|
|
|
73
72
|
</div>
|
|
74
73
|
</form>
|
|
75
74
|
<div id="stats" class="stats"></div>
|
|
76
|
-
<section class="card" aria-labelledby="
|
|
75
|
+
<section class="card" aria-labelledby="roles-title">
|
|
77
76
|
<header class="card-head">
|
|
78
|
-
<h2 id="
|
|
77
|
+
<h2 id="roles-title">Roles</h2>
|
|
79
78
|
<div class="spacer"></div>
|
|
80
79
|
<button type="button" class="btn btn-sm" id="resetall" title="Zero every role's runs, commits, tokens, and cost — scheduling is untouched">${iconSvg("refresh")}<span>Reset counters</span></button>
|
|
81
80
|
<div class="menu-anchor" id="wakelaterwrap"><button type="button" class="btn btn-sm" id="wakelater" aria-haspopup="menu" title="Wake every role later">${iconSvg("clock")}<span>Wake later</span></button></div>
|
|
82
81
|
<button type="button" class="btn btn-sm" id="wakeall" title="Wake every role now, skipping any sleep">${iconSvg("bolt")}<span>Wake all</span></button>
|
|
83
82
|
</header>
|
|
84
83
|
<div class="table-wrap">
|
|
85
|
-
<table class="table
|
|
86
|
-
<thead><tr><th class="c-
|
|
84
|
+
<table class="table roles" id="rolestable">
|
|
85
|
+
<thead><tr><th class="c-role">Role</th><th class="c-status">Status</th><th class="c-activity">Now, or the last result</th><th class="c-today num">Spent today</th><th class="c-actions"><span class="sr-only">Actions</span></th></tr></thead>
|
|
87
86
|
<tbody id="rolerows"></tbody>
|
|
88
87
|
</table>
|
|
89
88
|
</div>
|
|
@@ -94,6 +93,8 @@ export const GUI_PAGE = `<!doctype html>
|
|
|
94
93
|
<h2 id="backlog-title">Backlog</h2>
|
|
95
94
|
<div class="spacer"></div>
|
|
96
95
|
<div class="seg" id="backlogtabs" role="tablist" aria-label="Backlog sections"></div>
|
|
96
|
+
<label id="backlogreadywrap"><input class="field" id="backlogready" type="checkbox"><span>Ready only</span></label>
|
|
97
|
+
<label><span class="sr-only">Search</span><input class="field" id="backloggrep" type="search" placeholder="Search backlog…" autocomplete="off"></label>
|
|
97
98
|
</header>
|
|
98
99
|
<div id="backlog" class="list"></div>
|
|
99
100
|
</section>
|
|
@@ -105,6 +106,8 @@ export const GUI_PAGE = `<!doctype html>
|
|
|
105
106
|
<button type="button" data-filter="notable" class="active">Notable</button><button type="button" data-filter="all">All events</button>
|
|
106
107
|
</div>
|
|
107
108
|
<label><span class="sr-only">Role</span><select class="field" id="feedrole"><option value="">All roles</option></select></label>
|
|
109
|
+
<label><span class="sr-only">Window</span><select class="field" id="feedwindow"></select></label>
|
|
110
|
+
<span id="feedstep" style="display:none"><button type="button" class="btn btn-sm" id="feedearlier">◀ Earlier</button><button type="button" class="btn btn-sm" id="feedlater">Later ▶</button></span>
|
|
108
111
|
<label><span class="sr-only">Search</span><input class="field" id="feedgrep" type="search" placeholder="Search activity…" autocomplete="off"></label>
|
|
109
112
|
</header>
|
|
110
113
|
<ol id="feed" class="feed"></ol>
|
|
@@ -250,7 +250,7 @@ export const GUI_STYLES = String.raw `
|
|
|
250
250
|
.settings-row .field { flex: 1; min-width: 0; }
|
|
251
251
|
.settings-row .btn { flex: none; }
|
|
252
252
|
|
|
253
|
-
/* ---- composer: the director prompt (or one
|
|
253
|
+
/* ---- composer: the director prompt (or one role's), always in reach ---- */
|
|
254
254
|
.composer { padding: 8px; border: 1px solid var(--line); border-radius: 12px;
|
|
255
255
|
background: var(--surface); box-shadow: var(--shadow-sm); }
|
|
256
256
|
.composer:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--accent-bg); }
|
|
@@ -296,6 +296,10 @@ export const GUI_STYLES = String.raw `
|
|
|
296
296
|
.card-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; padding: 10px 16px; min-height: 50px;
|
|
297
297
|
border-bottom: 1px solid var(--line); }
|
|
298
298
|
.card-head h2 { margin: 0; font-size: 14.5px; font-weight: 650; }
|
|
299
|
+
/* The Post-merge reviews card's header line and one queue entry each, beside the Merge
|
|
300
|
+
queue card's mono lines — the dashboard twin of 'tumwater reviews'. */
|
|
301
|
+
.queue-head { padding: 10px 16px 2px; font-size: 12.5px; font-weight: 600; color: var(--text-3); }
|
|
302
|
+
.queue-entry { padding: 3px 16px; }
|
|
299
303
|
.grid-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); gap: 20px; align-items: start; }
|
|
300
304
|
.grid-2.even { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; }
|
|
301
305
|
.seg { display: inline-flex; padding: 2px; gap: 2px; border-radius: 9px; background: var(--surface-3); }
|
|
@@ -320,7 +324,7 @@ export const GUI_STYLES = String.raw `
|
|
|
320
324
|
font-size: 12px; font-weight: 600; color: var(--text-3); }
|
|
321
325
|
.table tr.group:not(:first-child) td { border-top: 1px solid var(--line); }
|
|
322
326
|
.table tr.group .badge { margin-left: 6px; }
|
|
323
|
-
/* The history view's
|
|
327
|
+
/* The history view's run drill-down: the rows' details toggle and the expanded card that
|
|
324
328
|
rides beneath its row, full width. */
|
|
325
329
|
.history .c-x { width: 40px; white-space: nowrap; }
|
|
326
330
|
.hist-x { padding: 0 6px; }
|
|
@@ -336,22 +340,22 @@ export const GUI_STYLES = String.raw `
|
|
|
336
340
|
.clamp2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
|
|
337
341
|
.clamp1 { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
338
342
|
|
|
339
|
-
table.
|
|
340
|
-
table.
|
|
341
|
-
table.
|
|
342
|
-
table.
|
|
343
|
-
table.
|
|
344
|
-
.
|
|
345
|
-
.
|
|
346
|
-
.
|
|
347
|
-
.
|
|
348
|
-
.
|
|
349
|
-
.
|
|
343
|
+
table.roles .c-role { width: 15%; }
|
|
344
|
+
table.roles .c-status { width: 24%; }
|
|
345
|
+
table.roles .c-today { width: 110px; }
|
|
346
|
+
table.roles .c-actions { width: 136px; }
|
|
347
|
+
table.roles.free .c-today { display: none; }
|
|
348
|
+
.roles tr.role-row.selected td { background: var(--accent-bg); }
|
|
349
|
+
.roles tr.role-row.selected td:first-child { box-shadow: inset 3px 0 0 var(--primary); }
|
|
350
|
+
.roles tr.role-row.live td:first-child { box-shadow: inset 3px 0 0 var(--blue); }
|
|
351
|
+
.roles tr.role-row.live.selected td:first-child { box-shadow: inset 3px 0 0 var(--primary); }
|
|
352
|
+
.role-name { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
|
|
353
|
+
.role-name .role { font-family: var(--font-mono); font-weight: 600; font-size: 13.5px; }
|
|
350
354
|
.now { color: var(--text); }
|
|
351
355
|
.actions { display: flex; justify-content: flex-end; gap: 2px; }
|
|
352
|
-
tr.
|
|
353
|
-
tr.
|
|
354
|
-
@media (hover: none) { tr.
|
|
356
|
+
tr.role-row .actions { opacity: 0.55; transition: opacity 0.12s; }
|
|
357
|
+
tr.role-row:hover .actions, tr.role-row:focus-within .actions, tr.role-row.selected .actions { opacity: 1; }
|
|
358
|
+
@media (hover: none) { tr.role-row .actions { opacity: 1; } }
|
|
355
359
|
|
|
356
360
|
/* ---- backlog list ---- */
|
|
357
361
|
.list { max-height: 460px; overflow-y: auto; }
|
|
@@ -380,14 +384,14 @@ export const GUI_STYLES = String.raw `
|
|
|
380
384
|
.feed-icon svg.i { width: 15px; height: 15px; }
|
|
381
385
|
.feed-msg { color: var(--text-2); overflow-wrap: anywhere; }
|
|
382
386
|
.feed-item.k-routine .feed-msg { color: var(--text-3); }
|
|
383
|
-
.feed-
|
|
387
|
+
.feed-source { font-family: var(--font-mono); font-size: 12.5px; font-weight: 600; color: var(--text); margin-right: 4px; }
|
|
384
388
|
.feed-time { font-size: 12px; color: var(--text-4); white-space: nowrap; font-variant-numeric: tabular-nums; padding-top: 1px; }
|
|
385
389
|
.feed-tally { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 16px 6px; border-bottom: 1px solid var(--line-soft); }
|
|
386
390
|
.feed-tally .chip { height: 22px; padding: 0 9px; font-size: 12px; font-weight: 500; }
|
|
387
391
|
.feed-tally button.chip { cursor: pointer; }
|
|
388
392
|
.feed-tally .chip.active { border-color: var(--accent); background: var(--accent-bg); color: var(--text); }
|
|
389
393
|
|
|
390
|
-
/* ---- drawer: a
|
|
394
|
+
/* ---- drawer: a role's detail and live transcript, or one backlog entry ---- */
|
|
391
395
|
.drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 50; width: min(660px, 100vw); display: flex;
|
|
392
396
|
flex-direction: column; background: var(--bg); border-left: 1px solid var(--line); box-shadow: var(--shadow-lg);
|
|
393
397
|
animation: slidein 0.16s ease-out; }
|
|
@@ -412,11 +416,11 @@ export const GUI_STYLES = String.raw `
|
|
|
412
416
|
.kv dt { font-size: 12px; color: var(--text-3); }
|
|
413
417
|
.kv dd { margin: 1px 0 0; font-weight: 600; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
414
418
|
.note { padding: 11px 13px; border-radius: 10px; border: 1px solid var(--line); background: var(--surface); overflow-wrap: anywhere; }
|
|
415
|
-
.
|
|
416
|
-
.
|
|
419
|
+
.run-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--surface); }
|
|
420
|
+
.run-list li { display: grid; grid-template-columns: 116px minmax(0, 1fr) auto; gap: 10px; padding: 8px 12px;
|
|
417
421
|
border-bottom: 1px solid var(--line-soft); font-size: 13px; }
|
|
418
|
-
.
|
|
419
|
-
.
|
|
422
|
+
.run-list li:last-child { border-bottom: 0; }
|
|
423
|
+
.run-list .when { color: var(--text-4); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
420
424
|
.transcript-sec { flex: 1; min-height: 320px; display: flex; flex-direction: column; }
|
|
421
425
|
.transcript { flex: 1; min-height: 280px; margin: 0; overflow: auto; padding: 12px 14px; border-radius: 10px;
|
|
422
426
|
border: 1px solid var(--line); background: var(--surface); font: 12.5px/1.6 var(--font-mono);
|
|
@@ -500,7 +504,7 @@ export const GUI_STYLES = String.raw `
|
|
|
500
504
|
.menu-anchor.up .popover { top: calc(100% + 8px); bottom: auto; }
|
|
501
505
|
.main { padding-left: 16px; padding-right: 16px; }
|
|
502
506
|
.stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
503
|
-
table.
|
|
507
|
+
table.roles .c-today { display: none; }
|
|
504
508
|
.kv { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
505
509
|
.history .c-usage, .history .c-dur, .history .c-model { display: none; }
|
|
506
510
|
}
|
|
@@ -508,22 +512,22 @@ export const GUI_STYLES = String.raw `
|
|
|
508
512
|
.stats.six { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
509
513
|
.stat-value { font-size: 21px; }
|
|
510
514
|
.composer-foot #prompthint { display: none; }
|
|
511
|
-
table.
|
|
512
|
-
table.
|
|
513
|
-
table.
|
|
515
|
+
table.roles thead { display: none; }
|
|
516
|
+
table.roles, table.roles tbody { display: block; }
|
|
517
|
+
table.roles tr.role-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px;
|
|
514
518
|
padding: 10px 16px; border-bottom: 1px solid var(--line-soft); }
|
|
515
|
-
table.
|
|
516
|
-
table.
|
|
517
|
-
table.
|
|
518
|
-
table.
|
|
519
|
+
table.roles tr.role-row td { display: block; width: auto; padding: 0; border: 0; background: none !important; box-shadow: none !important; }
|
|
520
|
+
table.roles tr.role-row td.c-status, table.roles tr.role-row td.c-activity { grid-column: 1 / -1; margin-top: 6px; }
|
|
521
|
+
table.roles tr.role-row td.c-actions { grid-row: 1; grid-column: 2; }
|
|
522
|
+
table.roles tr.role-row td.c-today { display: none; }
|
|
519
523
|
.composer-row { flex-wrap: wrap; }
|
|
520
524
|
.composer textarea { order: -1; flex-basis: 100%; }
|
|
521
525
|
.composer-target { flex: 1; }
|
|
522
526
|
.composer-target select { max-width: none; width: 100%; }
|
|
523
|
-
table.
|
|
524
|
-
.history .c-
|
|
525
|
-
.
|
|
526
|
-
.
|
|
527
|
+
table.roles tr.group, table.roles tr.group td { display: block; }
|
|
528
|
+
.history .c-run, .history .c-detail { display: none; }
|
|
529
|
+
.run-list li { grid-template-columns: minmax(0, 1fr) auto; }
|
|
530
|
+
.run-list .when:first-child { grid-column: 1 / -1; }
|
|
527
531
|
.md { padding: 4px 16px 16px; }
|
|
528
532
|
}
|
|
529
533
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { applyToolExecutionEvent, parsePiEventLine, toolCallCommand, } from "../pi/pi-event-line.js";
|
|
4
|
-
import { bufferedCommandStallMs,
|
|
5
|
-
import { streamsToolOutput } from "../agent/backend-traits.js";
|
|
3
|
+
import { bufferedCommandStallMs, callBuffersOutput } from "../pi/command-shape.js";
|
|
6
4
|
import { describeToolCall } from "../text/phrases.js";
|
|
7
5
|
import { squash } from "../text/text.js";
|
|
8
6
|
import { defaultConfig, liveConfig } from "../config/config.js";
|
|
@@ -17,7 +15,7 @@ const TAIL_BYTES = 4 * 1024 * 1024;
|
|
|
17
15
|
/** Byte offset a first observation of the log (size `size`) seeds from: the start of the
|
|
18
16
|
* smallest suffix window, grown from TAIL_BYTES in doubling steps, that contains a complete
|
|
19
17
|
* `session` event line — or 0 when the log carries none. A bare `size - TAIL_BYTES` seed
|
|
20
|
-
* opens mid-run whenever the log (which accumulates across
|
|
18
|
+
* opens mid-run whenever the log (which accumulates across runs up to logMaxBytes) is
|
|
21
19
|
* larger than the window, and the first observation then counts every assistant turn after
|
|
22
20
|
* that offset as if it were one run — a number with no defined meaning (BUGS.md 2026-09-22).
|
|
23
21
|
* Seeding at the window that contains the last session anchors the read at a real run
|
|
@@ -103,7 +101,7 @@ const PROGRESS_TYPES = new Set([
|
|
|
103
101
|
/** Apply one parsed progress event to a progress object (mutates it). */
|
|
104
102
|
function feedLine(progress, event) {
|
|
105
103
|
switch (event.type) {
|
|
106
|
-
case "session": // A new run starts: everything before it was a previous
|
|
104
|
+
case "session": // A new run starts: everything before it was a previous run — restore the at-time-zero state.
|
|
107
105
|
Object.assign(progress, freshProgress(progress.quietMs));
|
|
108
106
|
break;
|
|
109
107
|
case "tool_execution_start": {
|
|
@@ -143,7 +141,7 @@ function feedLine(progress, event) {
|
|
|
143
141
|
progress.outputTokens += nonNegativeNumber(usage.output, 0);
|
|
144
142
|
progress.peakContextTokens = Math.max(progress.peakContextTokens, nonNegativeNumber(usage.totalTokens, 0));
|
|
145
143
|
}
|
|
146
|
-
// The first text the
|
|
144
|
+
// The first text the role speaks in this run is its work item ("I'll implement plan X");
|
|
147
145
|
// later messages never replace it.
|
|
148
146
|
if (!progress.currentWork)
|
|
149
147
|
progress.currentWork = workItemFromContent(event.message.content);
|
|
@@ -180,7 +178,7 @@ export function toolCallStallMs(root) {
|
|
|
180
178
|
* line, so this runs on every read rather than in feedLine; `now` and `stallMs` are injectable
|
|
181
179
|
* for tests (freshly fed lines stamp Date.now(), so nothing is stalled right after parsing).
|
|
182
180
|
* A call whose stdout is piped or redirected holds its bytes away from pi until it exits
|
|
183
|
-
* (BUGS.md 2026-09-28: the
|
|
181
|
+
* (BUGS.md 2026-09-28: the run prompt itself prescribes `npm run test 2>&1 | tail`), so its
|
|
184
182
|
* silence is the prescribed shape and never evidence of a hang — but the command can still
|
|
185
183
|
* hang (a leaked grandchild holding the pipe open), so past a wall-clock threshold it is
|
|
186
184
|
* flagged anyway (BUGS.md 2026-10-06), the same threshold runPi's warning applies so the
|
|
@@ -192,7 +190,7 @@ export function stalledToolLabel(open, now = Date.now(), stallMs = defaultConfig
|
|
|
192
190
|
// claude never sends content-bearing tool updates, so silence is expected for every call
|
|
193
191
|
// and only the wall-clock duration can show a hang (plans/agent-backends.md "Watchdogs and
|
|
194
192
|
// progress"); pi keeps the per-command classification.
|
|
195
|
-
if (
|
|
193
|
+
if (callBuffersOutput(agent, call.command || call.label)) {
|
|
196
194
|
if (now - call.lastActivityAt >= bufferedCommandStallMs(stallMs))
|
|
197
195
|
return call.label;
|
|
198
196
|
continue;
|
|
@@ -233,7 +231,7 @@ function feedDemuxed(tail, line, gateCwd) {
|
|
|
233
231
|
// accumulator as soon as the marker's stage says `reviewing` — a poll that can land
|
|
234
232
|
// before the session event. Resetting here means a previous run's turns/context (the
|
|
235
233
|
// last review, or another run the gate spent) can never show in the new run's cell.
|
|
236
|
-
// Safe for the in-
|
|
234
|
+
// Safe for the in-run reviewing cell too: a role's gate is serial, so a marker ends
|
|
237
235
|
// the previous run.
|
|
238
236
|
tail.cur = kind;
|
|
239
237
|
tail.kindFromMarker = true;
|
|
@@ -249,8 +247,8 @@ function feedDemuxed(tail, line, gateCwd) {
|
|
|
249
247
|
}
|
|
250
248
|
feedLine(tail[tail.cur], event);
|
|
251
249
|
}
|
|
252
|
-
/** Live progress for one of a
|
|
253
|
-
* the role's own worktree, the default; `gate` — the review gate's runs in a leased pool
|
|
250
|
+
/** Live progress for one of a role's agent run kinds (`author` — the in-flight authoring agent
|
|
251
|
+
* run in the role's own worktree, the default; `gate` — the review gate's runs in a leased pool
|
|
254
252
|
* slot, what the reviewing cell shows), or null when there is no log yet. The raw log is
|
|
255
253
|
* append-only while pi runs and every run starts with a `tumwater_run` marker
|
|
256
254
|
* (src/agent/run-agent.ts), so after seeding from the tail window once we only read and parse
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { readLiveProgress } from "./progress-data.js";
|
|
2
2
|
import { compactTokens } from "../text/format.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { pad2 } from "../text/datetime.js";
|
|
4
|
+
/** The in-flight run's PROGRESS display model (split from status-model.ts, which keeps the
|
|
5
|
+
* role-phase ladder, the merge cells, and the row derivations): how an in-flight run renders
|
|
5
6
|
* its live detail — elapsed, turn, context, current tool, stall — derived from the live log
|
|
6
7
|
* tail (progress-data.ts) and shared by BOTH observer surfaces: the terminal table
|
|
7
8
|
* (status-render.ts's state cell) and the JSON/GUI payload (status-payload.ts), plus the
|
|
8
|
-
* phase ladder's in-flight branches (status-model.ts's
|
|
9
|
+
* phase ladder's in-flight branches (status-model.ts's rolePhase), so the three cannot
|
|
9
10
|
* drift apart. This is the disk-reading half: every helper here reads (or accepts a caller's
|
|
10
11
|
* precomputed) live log tail, while status-model.ts derives labels from the snapshot. */
|
|
11
12
|
/** Seconds/minutes/hours elapsed formatting shared by the progress helpers and the phase
|
|
12
|
-
* ladder's elapsed branches (
|
|
13
|
+
* ladder's elapsed branches (rolePhase's merge and parked branches). The hours bucket
|
|
13
14
|
* rounds to whole minutes off the total, so a rounded-up 59m5Xs carries into the next hour
|
|
14
15
|
* ("2h0m"); rounding the remainder alone would print the impossible "1h60m". */
|
|
15
16
|
export function duration(ms) {
|
|
@@ -17,41 +18,41 @@ export function duration(ms) {
|
|
|
17
18
|
if (s < 60)
|
|
18
19
|
return `${s}s`;
|
|
19
20
|
if (s < 3600)
|
|
20
|
-
return `${Math.floor(s / 60)}m${
|
|
21
|
+
return `${Math.floor(s / 60)}m${pad2(s % 60)}s`;
|
|
21
22
|
const totalMinutes = Math.round(s / 60);
|
|
22
23
|
return `${Math.floor(totalMinutes / 60)}h${totalMinutes % 60}m`;
|
|
23
24
|
}
|
|
24
|
-
/** The label for a
|
|
25
|
+
/** The label for a role's in-flight run: `<label>` plus how long it has been running
|
|
25
26
|
* ("working 3m", "reviewing 2m") — shared by workingDetail and the review-gate branch of
|
|
26
|
-
*
|
|
27
|
-
* renders as just the bare label. (A merge's elapsed is its marker's, never the
|
|
28
|
-
*
|
|
27
|
+
* rolePhase so their elapsed formatting cannot drift. A run with no recorded start time
|
|
28
|
+
* renders as just the bare label. (A merge's elapsed is its marker's, never the run's —
|
|
29
|
+
* rolePhase's merge branch builds that head itself.) */
|
|
29
30
|
export function inFlightLabel(s, label) {
|
|
30
31
|
const elapsed = s.lastRunStartedAt ? duration(Date.now() - s.lastRunStartedAt) : "";
|
|
31
32
|
return `${label} ${elapsed}`.trim();
|
|
32
33
|
}
|
|
33
|
-
/** One rule for whether a log tail's progress describes THIS
|
|
34
|
-
* (quietMs is measured from the raw log's mtime) must have happened after the
|
|
35
|
-
* Until
|
|
36
|
-
* baseline check (worktree reset plus suite) can take 30–130 s, and a
|
|
34
|
+
/** One rule for whether a log tail's progress describes THIS run: the log's newest write
|
|
35
|
+
* (quietMs is measured from the raw log's mtime) must have happened after the run started.
|
|
36
|
+
* Until the current agent run writes its first line, the log's tail is the PREVIOUS run — the
|
|
37
|
+
* baseline check (worktree reset plus suite) can take 30–130 s, and a run waking after 5+
|
|
37
38
|
* minutes idle would otherwise show the earlier run's turn/context/tool and a "no pi output"
|
|
38
|
-
* quiet time measured from before the
|
|
39
|
-
* such
|
|
40
|
-
*
|
|
41
|
-
* Applied by every progress reader (workingDetail, the reviewing branch of
|
|
42
|
-
* token metrics,
|
|
43
|
-
*
|
|
39
|
+
* quiet time measured from before the run even began, tripping the STALL alert on every
|
|
40
|
+
* such run's baseline (BUGS.md 2026-09-30). Once the run writes, its mtime is inside the
|
|
41
|
+
* run, so quietMs can never exceed the run's own age and the honest quiet measure survives.
|
|
42
|
+
* Applied by every progress reader (workingDetail, the reviewing branch of rolePhase, the
|
|
43
|
+
* token metrics, roleRowCells' precomputed tail) and by status-render's state cell via
|
|
44
|
+
* runProgress, so the TUI, the GUI payload, and the alert cannot drift apart. A state with
|
|
44
45
|
* no recorded start (a stale `running` flag after a crash) cannot be judged and keeps the
|
|
45
46
|
* tail as before. `p` may be undefined (the caller's "no tail fetched" sentinel) or null
|
|
46
47
|
* ("no log"); both read as no progress. */
|
|
47
|
-
function
|
|
48
|
+
function progressOfRun(s, p) {
|
|
48
49
|
if (!p)
|
|
49
50
|
return null;
|
|
50
51
|
if (s.lastRunStartedAt === undefined)
|
|
51
52
|
return p;
|
|
52
53
|
const elapsed = Math.max(0, Date.now() - s.lastRunStartedAt);
|
|
53
54
|
if (p.quietMs > elapsed)
|
|
54
|
-
return null; // Newest write predates this
|
|
55
|
+
return null; // Newest write predates this run: a previous run's tail.
|
|
55
56
|
return { ...p, quietMs: Math.min(p.quietMs, elapsed) };
|
|
56
57
|
}
|
|
57
58
|
/** The stall phrases a phase label can carry — inFlightDetail appends "tool call stalled:
|
|
@@ -65,7 +66,7 @@ export const STALL_SOURCE = String.raw `tool call stalled[^·]*|no agent output
|
|
|
65
66
|
/** STALL_SOURCE compiled — the server-side matcher (team-alerts.ts's stuck alert). */
|
|
66
67
|
export const STALL_RE = new RegExp(STALL_SOURCE);
|
|
67
68
|
/** The shared parts assembly for an in-flight state cell: `head` (the phase label with its
|
|
68
|
-
* own elapsed — inFlightLabel for a
|
|
69
|
+
* own elapsed — inFlightLabel for a run, the merge branch's own for a merge) plus turn,
|
|
69
70
|
* live context, current tool, and the ≥5-min no-output stall flag. `p` is null when there is
|
|
70
71
|
* no progress (no log yet) — falls back to the bare head. */
|
|
71
72
|
export function inFlightDetail(head, p) {
|
|
@@ -87,31 +88,31 @@ export function inFlightDetail(head, p) {
|
|
|
87
88
|
parts.push(`no agent output for ${duration(p.quietMs)}`);
|
|
88
89
|
return parts.join(" · ");
|
|
89
90
|
}
|
|
90
|
-
/** Which pi run kind (progress-data.ts's ProgressRunKind) a
|
|
91
|
-
* the review gate's reviewer run ("gate") while the
|
|
91
|
+
/** Which pi run kind (progress-data.ts's ProgressRunKind) a role's in-flight cells should read:
|
|
92
|
+
* the review gate's reviewer run ("gate") while the run is under review — its `session`
|
|
92
93
|
* event is the log's newest and its counts are what "reviewing" describes — the author's
|
|
93
94
|
* own run ("author") for every other in-flight phase. One home for the rule so the TUI
|
|
94
95
|
* table and the GUI payload cannot drift (the precomputed `live` tail must name the same
|
|
95
|
-
* run the phase label does). status-model's
|
|
96
|
+
* run the phase label does). status-model's roleRowCells is its only reader. */
|
|
96
97
|
export function progressKind(s) {
|
|
97
98
|
return s.phase === "review" ? "gate" : "author";
|
|
98
99
|
}
|
|
99
|
-
/**
|
|
100
|
+
/** progressOfRun with the tail read folded in — the one home for the
|
|
100
101
|
* `live === undefined ? readLiveProgress(...) : live` idiom. Callers holding this frame's
|
|
101
|
-
* already-fetched tail pass it as `live` (renderStatus reads once per running
|
|
102
|
+
* already-fetched tail pass it as `live` (renderStatus reads once per running role and
|
|
102
103
|
* threads it through every helper); standalone callers pass undefined and this reads the
|
|
103
104
|
* role's log itself — the author accumulator by default, the gate one via `kind`. Every
|
|
104
105
|
* tail-reading caller outside this module routes through it; status-model.ts's staged branch
|
|
105
106
|
* is the one exception, keeping its raw readLiveProgress call because it feeds inFlightDetail
|
|
106
107
|
* a freshly read gate tail for the merge label, not a per-frame threaded one. */
|
|
107
|
-
export function
|
|
108
|
-
return
|
|
108
|
+
export function runProgress(root, s, live, kind = "author") {
|
|
109
|
+
return progressOfRun(s, live === undefined ? readLiveProgress(root, s.role, kind) : live);
|
|
109
110
|
}
|
|
110
|
-
/** The state cell for a working
|
|
111
|
-
* `live` — this frame's already-fetched tail (renderStatus reads once per running
|
|
111
|
+
/** The state cell for a working role: elapsed · turns · live context · current tool. Pass
|
|
112
|
+
* `live` — this frame's already-fetched tail (renderStatus reads once per running role and
|
|
112
113
|
* threads it through every helper) — to avoid re-reading the log; without it, this reads on
|
|
113
114
|
* its own for standalone callers. */
|
|
114
115
|
export function workingDetail(root, s, live) {
|
|
115
|
-
const p =
|
|
116
|
+
const p = runProgress(root, s, live);
|
|
116
117
|
return inFlightDetail(inFlightLabel(s, "working"), p);
|
|
117
118
|
}
|