tumwater 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +42 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +4 -3
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +402 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +246 -55
- package/dist/src/backlog/backlog-cli-view.js +280 -0
- package/dist/src/backlog/backlog-cli.js +85 -274
- package/dist/src/backlog/backlog-commit.js +4 -5
- package/dist/src/backlog/backlog-eligibility.js +175 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +254 -0
- package/dist/src/backlog/backlog-release.js +117 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-culprit.js +94 -0
- package/dist/src/baseline/main-guardrails.js +209 -0
- package/dist/src/baseline/main-red.js +139 -32
- package/dist/src/baseline/main-revert.js +133 -0
- package/dist/src/baseline/main-watch.js +184 -0
- package/dist/src/brief/brief-edit.js +9 -11
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget.js +30 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +1 -2
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +118 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +150 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +308 -590
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-role-command.js +420 -0
- package/dist/src/cli/cli-start-summary.js +160 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
- package/dist/src/cli/completion.js +149 -22
- package/dist/src/cli/config-commands.js +41 -18
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +189 -73
- package/dist/src/cli/log-commands.js +148 -82
- package/dist/src/cli/question-commands.js +205 -10
- package/dist/src/cli.js +106 -43
- package/dist/src/collections.js +26 -10
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +13 -1
- package/dist/src/config/config-fallbacks.js +93 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +141 -199
- package/dist/src/config/config-views.js +127 -53
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +131 -264
- package/dist/src/config/config.js +48 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
- package/dist/src/doctor/doctor-backlog-plans.js +263 -0
- package/dist/src/doctor/doctor-backlog.js +100 -496
- package/dist/src/doctor/doctor-check-names.js +81 -0
- package/dist/src/doctor/doctor-checks.js +52 -579
- package/dist/src/doctor/doctor-claude-checks.js +145 -0
- package/dist/src/doctor/doctor-codex-checks.js +279 -0
- package/dist/src/doctor/doctor-contention-checks.js +380 -0
- package/dist/src/doctor/doctor-holds.js +82 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +236 -402
- package/dist/src/doctor/doctor-notify.js +3 -4
- package/dist/src/doctor/doctor-opencode-checks.js +162 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-project-checks.js +303 -0
- package/dist/src/doctor/doctor.js +121 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +7 -11
- package/dist/src/events/event-format.js +181 -86
- package/dist/src/events/event-labels.js +12 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +39 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +60 -24
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +56 -56
- package/dist/src/failure/failure-render.js +31 -23
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +99 -35
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +177 -84
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +108 -58
- package/dist/src/gates/maintenance-quota.js +10 -13
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +77 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +36 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +42 -18
- package/dist/src/gui/gui-backlog-endpoints.js +155 -0
- package/dist/src/gui/gui-command.js +8 -13
- package/dist/src/gui/gui-config-commands.js +94 -72
- package/dist/src/gui/gui-endpoint-commands.js +4 -3
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +108 -13
- package/dist/src/gui/gui-prompt-commands.js +11 -14
- package/dist/src/gui/gui-report-endpoints.js +90 -0
- package/dist/src/gui/gui-server.js +11 -4
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +147 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +193 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +25 -9
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +81 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +150 -11
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +90 -0
- package/dist/src/merge/merge-queue-render.js +49 -11
- package/dist/src/merge/merge-queue.js +31 -15
- package/dist/src/merge/merge-requeue.js +102 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +33 -11
- package/dist/src/merge/merge-to-main.js +86 -27
- package/dist/src/merge/merge-top.js +69 -0
- package/dist/src/merge/merge-verify.js +12 -10
- package/dist/src/notes-cli.js +30 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +320 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
- package/dist/src/orchestrator/orchestrator.js +128 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +201 -0
- package/dist/src/orchestrator/scheduling-skip.js +185 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +116 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +18 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +121 -211
- package/dist/src/prompt/notes-backlog.js +181 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +129 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +161 -77
- package/dist/src/report/report-fold.js +129 -52
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +133 -64
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +26 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/known-flakes.js +100 -1
- package/dist/src/review/post-merge-review.js +106 -0
- package/dist/src/review/protected-edits.js +4 -5
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +155 -360
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +69 -12
- package/dist/src/roles/role-guidance.js +55 -20
- package/dist/src/roles/role-labels.js +1 -2
- package/dist/src/roles/role-render.js +67 -50
- package/dist/src/roles/role-view.js +59 -47
- package/dist/src/roles/roles.js +31 -31
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/{tick → run}/qa-coverage.js +9 -27
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +179 -0
- package/dist/src/run/run-detail-render.js +98 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +108 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +108 -50
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +91 -56
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +172 -0
- package/dist/src/run/stage-path-checks.js +730 -0
- package/dist/src/{loop → runner}/leftover.js +80 -25
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +202 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +107 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +21 -15
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +102 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +43 -16
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +28 -28
- package/dist/src/status/status-roles.js +39 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +5 -6
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +63 -17
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +57 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +67 -13
- package/dist/src/ui/badges.js +65 -37
- package/dist/src/ui/gui/gui-client-backlog.js +292 -0
- package/dist/src/ui/gui/gui-client-boot.js +32 -26
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
- package/dist/src/ui/gui/gui-client-drawer.js +126 -285
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +434 -67
- package/dist/src/ui/gui/gui-client-labels.js +1 -2
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +55 -51
- package/dist/src/ui/gui/gui-client-pending.js +227 -23
- package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
- package/dist/src/ui/gui/gui-client-report.js +87 -427
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +56 -4
- package/dist/src/ui/gui/gui-client-team.js +25 -465
- package/dist/src/ui/gui/gui-client.js +27 -25
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +9 -7
- package/dist/src/ui/gui/gui-styles.js +34 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +136 -49
- package/dist/src/ui/status-render.js +101 -82
- package/dist/src/ui/team-alerts.js +248 -57
- package/dist/src/ui/tone.js +5 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +51 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +3 -5
- package/dist/src/ui/tui/tui-editor-backends.js +132 -0
- package/dist/src/ui/tui/tui-editor-brief.js +10 -12
- package/dist/src/ui/tui/tui-editor-budget.js +35 -31
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
- package/dist/src/ui/tui/tui-editor-config.js +86 -0
- package/dist/src/ui/tui/tui-editor-entry.js +36 -47
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +37 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
- package/dist/src/ui/tui/tui-editor-interval.js +11 -9
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +3 -5
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +99 -35
- package/dist/src/ui/tui/tui-editor-retire.js +4 -6
- package/dist/src/ui/tui/tui-editor-role-key.js +76 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +60 -34
- package/dist/src/ui/tui/tui-editor-slots.js +23 -0
- package/dist/src/ui/tui/tui-editors.js +35 -2
- package/dist/src/ui/tui/tui-frame.js +56 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +24 -9
- package/dist/src/ui/tui/tui-pane-activity.js +14 -11
- package/dist/src/ui/tui/tui-pane-backlog.js +171 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +58 -8
- package/dist/src/ui/tui/tui-pane-history.js +402 -82
- package/dist/src/ui/tui/tui-pane-pending.js +308 -13
- package/dist/src/ui/tui/tui-pane-queued.js +71 -55
- package/dist/src/ui/tui/tui-pane-report.js +46 -14
- package/dist/src/ui/tui/tui-pane-session.js +25 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +80 -23
- package/dist/src/ui/tui/tui-panes.js +100 -30
- package/dist/src/ui/tui/tui.js +14 -14
- package/dist/src/verdict/fix-claim.js +82 -32
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +42 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Event-log folding for the usage report: turn raw harness events (run_end/merged/…) into
|
|
3
2
|
* per-day and whole-window `UsageFold` accumulators, memoizing the day-keyed read per
|
|
4
3
|
* (root, fromKey) so a dashboard polling /api/report only folds appended lines instead of
|
|
@@ -7,19 +6,21 @@
|
|
|
7
6
|
* --since and day windows present cannot drift apart; it lives here matching its own test
|
|
8
7
|
* (test/report-fold-cache.test.ts). Zero incidental runtime dependencies: node built-ins and
|
|
9
8
|
* the app's own modules only. */
|
|
10
|
-
import { sameStatIdentity, statOrNull } from "../files/files.js";
|
|
9
|
+
import { sameStatIdentity, statIdentityOrZero, statOrNull } from "../files/files.js";
|
|
11
10
|
import { readWindowEvents } from "../events/event-window.js";
|
|
12
11
|
import { eventDayKey, eventRole, eventUsage, parseEventLine } from "../events/event-read.js";
|
|
13
12
|
import { readCompleteLines } from "../files/tail.js";
|
|
14
13
|
import { eventsLogPath } from "../paths.js";
|
|
15
14
|
import { isPassingFullCheck, isRedFullCheck } from "../build/build-check-events.js";
|
|
15
|
+
import { isPassingMainCheck, isRedMain } from "../baseline/main-guardrails.js";
|
|
16
16
|
import { addTo, memoSetLru } from "../collections.js";
|
|
17
|
+
import { asList } from "../text/text.js";
|
|
17
18
|
import { finiteNumber } from "../files/json-object.js";
|
|
18
19
|
import { OUTCOME_CLASS } from "../failure/time-spend.js";
|
|
19
|
-
import { baseRoleOf } from "../roles/
|
|
20
|
+
import { baseRoleOf } from "../roles/runner-ids.js";
|
|
20
21
|
import { commitTier } from "../roles/roles.js";
|
|
21
22
|
/** Fold one event's `providerCost` map (`Record<provider, {costUsd, notionalCostUsd}>` — the
|
|
22
|
-
* shape
|
|
23
|
+
* shape run-finalize.ts's run_end and merge-slot.ts's merge_done/merge_failed emit) into the
|
|
23
24
|
* per-provider tallies, one addTo per provider per nonzero figure so zero stays absent. A
|
|
24
25
|
* missing, foreign, or empty map folds nothing, so old logs render byte-identically. */
|
|
25
26
|
function foldProviderCost(target, providerCost) {
|
|
@@ -37,28 +38,28 @@ function foldProviderCost(target, providerCost) {
|
|
|
37
38
|
addTo(target.notionalByProvider, provider, notionalCostUsd);
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
/** Push
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
list.push(
|
|
41
|
+
/** Push `ms` into the accumulator list a day median reads, when it is positive: the event
|
|
42
|
+
* fields that feed these medians are missing or 0 for the same event kinds (short runs, build
|
|
43
|
+
* pre-checks, precedent legacy events, probe-seam waits), and those contribute nothing — a
|
|
44
|
+
* median over only real durations/wait times. Every median list folds through here, so the
|
|
45
|
+
* "positive-only" rule cannot drift between fields. */
|
|
46
|
+
function pushPositiveMs(list, ms) {
|
|
47
|
+
if (ms > 0)
|
|
48
|
+
list.push(ms);
|
|
48
49
|
}
|
|
49
|
-
/** Fold one event into a usage accumulator: run_end events add a
|
|
50
|
-
* the target counts
|
|
50
|
+
/** Fold one event into a usage accumulator: run_end events add a run (per role and, when
|
|
51
|
+
* the target counts runs, in total), their output tokens, and their cost — zero-cost runs
|
|
51
52
|
* contribute nothing, so they leave no costByRole key, keeping the render's "$0 roles are
|
|
52
53
|
* omitted" rule true on the aggregation itself, not just at display time; merged events add
|
|
53
54
|
* a commit; merge_done/merge_failed events add a merge run and
|
|
54
|
-
* accumulate their tokens/cost into the merge fields only — costByRole stays a
|
|
55
|
+
* accumulate their tokens/cost into the merge fields only — costByRole stays a runs-only
|
|
55
56
|
* breakdown, and the merge line is how the reviewer's share is named. Both collectors fold
|
|
56
57
|
* through this one place, so the two windows' aggregation rules cannot drift apart. */
|
|
57
58
|
export function foldUsageEvent(target, ev) {
|
|
58
59
|
if (ev.type === "run_end") {
|
|
59
60
|
const role = eventRole(ev);
|
|
60
61
|
addTo(target.runsByRole, role, 1);
|
|
61
|
-
// Error-class
|
|
62
|
+
// Error-class runs get their own parallel tally — the day report's ``Failed runs by role``
|
|
62
63
|
// line — reusing the digest's OUTCOME_CLASS so "failed" cannot drift from the failure
|
|
63
64
|
// report's meaning. Never subtracted from runsByRole; the two are independent counts.
|
|
64
65
|
if (OUTCOME_CLASS[ev.result] === "error")
|
|
@@ -66,12 +67,13 @@ export function foldUsageEvent(target, ev) {
|
|
|
66
67
|
// A refusal is its own deliberate outcome (src/verdict/refusal.ts), not error-class, so
|
|
67
68
|
// it needs an explicit result check: the one per-role rejection-without-review count a
|
|
68
69
|
// day report should surface beside rejections, revisions and falls. Never subtracted from
|
|
69
|
-
// runsByRole; a refused
|
|
70
|
+
// runsByRole; a refused run still counts as a run.
|
|
70
71
|
if (ev.result === "refused")
|
|
71
72
|
addTo(target.refusalsByRole, role, 1);
|
|
72
73
|
if (target.runs !== undefined)
|
|
73
74
|
target.runs++;
|
|
74
75
|
const { tokens, costUsd, notionalCostUsd } = eventUsage(ev);
|
|
76
|
+
pushPositiveMs(target.runDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
75
77
|
addTo(target.tokensByRole, role, tokens);
|
|
76
78
|
target.tokensOut += tokens;
|
|
77
79
|
target.costUsd += costUsd;
|
|
@@ -80,26 +82,48 @@ export function foldUsageEvent(target, ev) {
|
|
|
80
82
|
addTo(target.costByRole, role, costUsd);
|
|
81
83
|
if (notionalCostUsd !== 0)
|
|
82
84
|
addTo(target.notionalByRole, role, notionalCostUsd);
|
|
83
|
-
// The
|
|
85
|
+
// The notional spend's backend (plans/codex-backend.md part 3d/9): the subscription seam
|
|
86
|
+
// whose runs made the run's API-equivalent cost, from the run_end's `agent` (run-finalize
|
|
87
|
+
// carries it when the run reported billing/rate windows) — falling back to "claude" when
|
|
88
|
+
// a legacy window event (no agent, subscription billing) attributed its spend, so the old
|
|
89
|
+
// default stays the report's only backend. A run with no backend and no subscription
|
|
90
|
+
// billing is unattributed and adds no key, so the render keeps its generic line for it.
|
|
91
|
+
const notionalBackend = typeof ev.agent === "string" && ev.agent !== ""
|
|
92
|
+
? ev.agent
|
|
93
|
+
: ev.billing === "subscription"
|
|
94
|
+
? "claude"
|
|
95
|
+
: undefined;
|
|
96
|
+
if (notionalBackend !== undefined && notionalCostUsd !== 0)
|
|
97
|
+
addTo(target.notionalByBackend, notionalBackend, notionalCostUsd);
|
|
98
|
+
// The agent runs' per-provider spend (run-finalize.ts emits providerCost on run_end)
|
|
84
99
|
// — folded per provider beside the per-role maps, so a mixed team's `Cost by provider`
|
|
85
100
|
// line names the expensive seam.
|
|
86
101
|
foldProviderCost(target, ev.providerCost);
|
|
87
102
|
}
|
|
88
103
|
else if (ev.type === "review_rejected") {
|
|
89
|
-
// One rejection per event, on the day it happened, per
|
|
104
|
+
// One rejection per event, on the day it happened, per role. Zero-means-absent: a role
|
|
90
105
|
// that never rejected stays absent, like costByRole.
|
|
91
106
|
addTo(target.rejectionsByRole, eventRole(ev), 1);
|
|
107
|
+
// A rejection that carried a positive durationMs means a reviewer actually ran the gate
|
|
108
|
+
// and reached a verdict (post-merge rejections do; the build pre-check contributes no
|
|
109
|
+
// duration), so it joins the review-duration median beside approvals. durationMs: 0 and
|
|
110
|
+
// a duration-less event contribute nothing.
|
|
111
|
+
pushPositiveMs(target.reviewDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
112
|
+
}
|
|
113
|
+
else if (ev.type === "review_verdict") {
|
|
114
|
+
// An approval that reached a verdict. Every reviewer run that reached a verdict, approval
|
|
115
|
+
// or rejection, is one entry in the review-duration median; review_failed stays out — it
|
|
116
|
+
// has no verdict. Mirrors the rejection branch above, on the same-day count.
|
|
117
|
+
pushPositiveMs(target.reviewDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
92
118
|
}
|
|
93
119
|
else if (ev.type === "revision") {
|
|
94
|
-
// One rework round per event, on the day it happened, per
|
|
120
|
+
// One rework round per event, on the day it happened, per role. Zero-means-absent: a role
|
|
95
121
|
// that never reworked a rejected change stays absent, like rejectionsByRole.
|
|
96
122
|
addTo(target.revisionsByRole, eventRole(ev), 1);
|
|
97
123
|
}
|
|
98
124
|
else if (isPassingFullCheck(ev)) {
|
|
99
125
|
// The merge slot's passing full-suite checks, for the day report's check-time median.
|
|
100
|
-
|
|
101
|
-
if (durationMs > 0)
|
|
102
|
-
target.checkDurationsMs.push(durationMs);
|
|
126
|
+
pushPositiveMs(target.checkDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
103
127
|
}
|
|
104
128
|
else if (isRedFullCheck(ev)) {
|
|
105
129
|
// The merge slot's red full-suite checks, for the day report's red-check count.
|
|
@@ -114,7 +138,7 @@ export function foldUsageEvent(target, ev) {
|
|
|
114
138
|
addTo(target.imageReroutesByRole, eventRole(ev), 1);
|
|
115
139
|
}
|
|
116
140
|
else if (ev.type === "run_deferred") {
|
|
117
|
-
// One deferral per event, a due maintenance
|
|
141
|
+
// One deferral per event, a due maintenance run that stood down. Bucket by the raw
|
|
118
142
|
// reason code ("backlog", "plans-full", else "no-work" for a missing/foreign/torn
|
|
119
143
|
// reason — the same fallback deferredReasonText applies in the feed), so the collector
|
|
120
144
|
// stays free of a presentation import and the render prints the code the event carried.
|
|
@@ -134,6 +158,15 @@ export function foldUsageEvent(target, ev) {
|
|
|
134
158
|
else if (tier === "maintenance")
|
|
135
159
|
target.maintenanceCommits++;
|
|
136
160
|
}
|
|
161
|
+
else if (ev.type === "main_revert") {
|
|
162
|
+
// Which role's merged change the main watch took back off main, keyed by the culprit's
|
|
163
|
+
// `runner` — a revert is a merge outcome, so it counts under the role that merged the
|
|
164
|
+
// culprit, folded to base role like commitsByRole/mergedByRole (`feature-2` → `feature`).
|
|
165
|
+
// A revert with no `runner` (a hand-made or director commit) adds nothing — no
|
|
166
|
+
// `(unknown)` key — matching the zero-means-absent rule of the other role maps.
|
|
167
|
+
if (typeof ev.runner === "string" && ev.runner !== "")
|
|
168
|
+
addTo(target.revertsByRole, baseRoleOf(ev.runner), 1);
|
|
169
|
+
}
|
|
137
170
|
else if (ev.type === "run_start") {
|
|
138
171
|
// One tally per run start on a configured model: the same `model` field the CLI's
|
|
139
172
|
// `run #N started on <model>` line prints, and the only event that carries a model
|
|
@@ -146,19 +179,24 @@ export function foldUsageEvent(target, ev) {
|
|
|
146
179
|
// The day report's provider-slot wait median, mirroring the slot_wait push: a wait only
|
|
147
180
|
// event-logged at or above the 30 s threshold counts, so a 0 ms wait (a probe seam) adds
|
|
148
181
|
// nothing and the median reflects real blocked admissions only.
|
|
149
|
-
|
|
182
|
+
pushPositiveMs(target.providerWaitsMs, finiteNumber(ev.waitedMs, 0));
|
|
150
183
|
}
|
|
151
184
|
else if (ev.type === "slot_wait") {
|
|
152
185
|
// The day report's workspace-slot wait median, mirroring the provider_wait push: a wait
|
|
153
186
|
// only event-logged at or above the 30 s threshold counts, so a 0 ms wait (a probe seam)
|
|
154
187
|
// or a pre-waitedMs event adds nothing.
|
|
155
|
-
|
|
188
|
+
pushPositiveMs(target.slotWaitsMs, finiteNumber(ev.waitedMs, 0));
|
|
189
|
+
}
|
|
190
|
+
else if (ev.type === "check_wait") {
|
|
191
|
+
// The day report's check-slot wait median, mirroring the slot_wait push: only waits logged
|
|
192
|
+
// at or above the 30 s threshold count, so a 0 ms or pre-waitedMs event adds nothing.
|
|
193
|
+
pushPositiveMs(target.checkWaitsMs, finiteNumber(ev.waitedMs, 0));
|
|
156
194
|
}
|
|
157
195
|
else if (ev.type === "merge_done" || ev.type === "merge_failed") {
|
|
158
196
|
target.mergeRuns = (target.mergeRuns ?? 0) + 1;
|
|
159
197
|
if (ev.type === "merge_failed")
|
|
160
198
|
target.mergeFailed = (target.mergeFailed ?? 0) + 1;
|
|
161
|
-
// Attribute the outcome to the authoring role (writeMergeOutcome logs
|
|
199
|
+
// Attribute the outcome to the authoring role (writeMergeOutcome logs role: entry.role)
|
|
162
200
|
// folded to base role, the same normalization the merged branch uses, so `feature-2`
|
|
163
201
|
// aggregates into `feature`. A parallel tally beside the team run counts, never
|
|
164
202
|
// subtracted from mergeRuns/mergeFailed.
|
|
@@ -166,13 +204,15 @@ export function foldUsageEvent(target, ev) {
|
|
|
166
204
|
if (ev.type === "merge_done") {
|
|
167
205
|
addTo(target.mergedByRole, role, 1);
|
|
168
206
|
// Events logged before queuedMs existed carry none: skipped, not counted as zero.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
207
|
+
pushPositiveMs(target.mergeWaitsMs, finiteNumber(ev.queuedMs, 0));
|
|
208
|
+
// How long the merge slot itself held the change, from the verification's start to the
|
|
209
|
+
// outcome. Like mergeWaitsMs, only a landed merge feeds it, and a pre-durationMs event
|
|
210
|
+
// (or 0) contributes nothing.
|
|
211
|
+
pushPositiveMs(target.mergeDurationsMs, finiteNumber(ev.durationMs, 0));
|
|
172
212
|
}
|
|
173
213
|
else {
|
|
174
214
|
addTo(target.mergeFailedByRole, role, 1);
|
|
175
|
-
// The event's result (writeMergeOutcome's
|
|
215
|
+
// The event's result (writeMergeOutcome's RunResult) names WHY the merge bounced
|
|
176
216
|
// off the gate — rejected/merge_conflict/merge_blocked/aborted. A legacy event with
|
|
177
217
|
// no result folds under `unknown`, so the reason buckets always sum to mergeFailed.
|
|
178
218
|
const reason = typeof ev.result === "string" && ev.result.length > 0 ? ev.result : "unknown";
|
|
@@ -184,6 +224,14 @@ export function foldUsageEvent(target, ev) {
|
|
|
184
224
|
// A subscription merge's API-equivalent spend joins the notional line, never the
|
|
185
225
|
// budgeted cost totals (plans/agent-backends.md part 6a).
|
|
186
226
|
target.notionalCostUsd += notionalCostUsd;
|
|
227
|
+
// The merge's notional spend per backend (merge-slot.ts emits it on the event, keyed by
|
|
228
|
+
// each subscription run's agent) — folded beside the run-end per-backend map, so a codex
|
|
229
|
+
// merge's subscription spend names codex instead of falling back to the generic line.
|
|
230
|
+
for (const [backend, c] of Object.entries(ev.notionalByBackend ?? {})) {
|
|
231
|
+
const amt = finiteNumber(c, 0);
|
|
232
|
+
if (amt !== 0)
|
|
233
|
+
addTo(target.notionalByBackend, backend, amt);
|
|
234
|
+
}
|
|
187
235
|
// The merge's per-provider spend (merge-slot.ts keys it to its reviewer seam), so a
|
|
188
236
|
// merge's costs appear under the provider that ran the reviewer, matching the author
|
|
189
237
|
// side's foldMergeUsage charge.
|
|
@@ -209,34 +257,58 @@ export function zeroCommitCounts() {
|
|
|
209
257
|
export function zeroMergeCounts() {
|
|
210
258
|
return { mergeRuns: 0, mergeTokens: 0, mergeCostUsd: 0 };
|
|
211
259
|
}
|
|
212
|
-
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
260
|
+
/** The base roles a report scope names: undefined and an empty list mean no scope (the team
|
|
261
|
+
* report); otherwise each id folded through `baseRoleOf`, deduplicated in first-seen order, so
|
|
262
|
+
* `feature-2,feature` is one base. */
|
|
263
|
+
export function scopeBases(role) {
|
|
264
|
+
if (role === undefined)
|
|
265
|
+
return undefined;
|
|
266
|
+
const ids = asList(role);
|
|
267
|
+
if (ids.length === 0)
|
|
268
|
+
return undefined;
|
|
269
|
+
const out = [];
|
|
270
|
+
for (const id of ids) {
|
|
271
|
+
const base = baseRoleOf(id);
|
|
272
|
+
if (!out.includes(base))
|
|
273
|
+
out.push(base);
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
/** Sum a per-role-id count/cost map over the scoped base roles: instance keys (`feature-2`)
|
|
278
|
+
* fold into their base (`feature`), so a scoped report aggregates a whole role group exactly
|
|
279
|
+
* as the per-role cap's group does. Runs/tokens/cost are keyed by exact role id while commits are
|
|
215
280
|
* already base-role keyed; running every key through `baseRoleOf` reads both shapes the same
|
|
216
281
|
* and returns 0 when nothing matches. */
|
|
217
|
-
export function roleSum(record,
|
|
282
|
+
export function roleSum(record, bases) {
|
|
283
|
+
const list = asList(bases);
|
|
218
284
|
let sum = 0;
|
|
219
285
|
for (const [key, n] of Object.entries(record)) {
|
|
220
|
-
if (baseRoleOf(key)
|
|
286
|
+
if (list.includes(baseRoleOf(key)))
|
|
221
287
|
sum += n;
|
|
222
288
|
}
|
|
223
289
|
return sum;
|
|
224
290
|
}
|
|
225
|
-
/** Narrow a per-
|
|
226
|
-
* from the map (no
|
|
227
|
-
* same zero-means-absent rule the team render applies. Used by the
|
|
228
|
-
* scoped series derives from the fold's per-role maps without
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
291
|
+
/** Narrow a per-role-id count/cost map to the scoped base roles, one entry per base keyed by
|
|
292
|
+
* that base; a role absent from the map (no runs, or no nonzero cost) yields no entry, never
|
|
293
|
+
* a zero one — the same zero-means-absent rule the team render applies. Used by the
|
|
294
|
+
* role-scoped collectors so a scoped series derives from the fold's per-role maps without
|
|
295
|
+
* inventing entries. */
|
|
296
|
+
export function narrowToRole(record, bases) {
|
|
297
|
+
const out = {};
|
|
298
|
+
for (const base of asList(bases)) {
|
|
299
|
+
const n = roleSum(record, base);
|
|
300
|
+
if (n !== 0)
|
|
301
|
+
out[base] = n;
|
|
302
|
+
}
|
|
303
|
+
return out;
|
|
232
304
|
}
|
|
233
|
-
/** A per-
|
|
234
|
-
* set (a team report), else the same map narrowed to `
|
|
305
|
+
/** A per-role map scoped to the base roles of a report: the full map as-is when no scope is
|
|
306
|
+
* set (a team report), else the same map narrowed to `bases` — narrowToRole's zero-means-absent
|
|
235
307
|
* rule, so a scoped report never invents a zero entry. The one home of the "keep everything,
|
|
236
308
|
* or keep only the named base role" rule: the 13 per-role/pair fields of the `--since` report's
|
|
237
309
|
* output all shape through it, so the scoping rule cannot drift between them. */
|
|
238
|
-
export function scopedByRole(record,
|
|
239
|
-
return
|
|
310
|
+
export function scopedByRole(record, bases) {
|
|
311
|
+
return bases === undefined ? record : narrowToRole(record, bases);
|
|
240
312
|
}
|
|
241
313
|
function dayFoldFor(entry, dayKey) {
|
|
242
314
|
let fold = entry.days.get(dayKey);
|
|
@@ -250,11 +322,16 @@ function dayFoldFor(entry, dayKey) {
|
|
|
250
322
|
rejectionsByRole: {},
|
|
251
323
|
revisionsByRole: {},
|
|
252
324
|
refusalsByRole: {},
|
|
325
|
+
revertsByRole: {},
|
|
253
326
|
checkDurationsMs: [],
|
|
254
327
|
checkFailures: 0,
|
|
255
328
|
mergeWaitsMs: [],
|
|
329
|
+
mergeDurationsMs: [],
|
|
330
|
+
runDurationsMs: [],
|
|
256
331
|
providerWaitsMs: [],
|
|
257
332
|
slotWaitsMs: [],
|
|
333
|
+
checkWaitsMs: [],
|
|
334
|
+
reviewDurationsMs: [],
|
|
258
335
|
failedRunsByRole: {},
|
|
259
336
|
fallbacksByRole: {},
|
|
260
337
|
imageReroutesByRole: {},
|
|
@@ -267,6 +344,7 @@ function dayFoldFor(entry, dayKey) {
|
|
|
267
344
|
mergeFailedByReason: {},
|
|
268
345
|
costByProvider: {},
|
|
269
346
|
notionalByProvider: {},
|
|
347
|
+
notionalByBackend: {},
|
|
270
348
|
runsByModel: {},
|
|
271
349
|
deferredByReason: {},
|
|
272
350
|
};
|
|
@@ -286,6 +364,8 @@ function foldEventInto(entry, ev) {
|
|
|
286
364
|
entry.hadEvents = true;
|
|
287
365
|
entry.firstEventTs = typeof ev.ts === "number" ? ev.ts : undefined;
|
|
288
366
|
}
|
|
367
|
+
if (isRedMain(ev) || isPassingMainCheck(ev))
|
|
368
|
+
entry.redEvents.push(ev);
|
|
289
369
|
foldUsageEvent(dayFoldFor(entry, dayKey), ev);
|
|
290
370
|
}
|
|
291
371
|
/** Parse one appended log line and fold it; a torn or non-event line folds nothing. */
|
|
@@ -307,11 +387,7 @@ function foldLineInto(entry, line) {
|
|
|
307
387
|
* carrying yesterday's proof forward. */
|
|
308
388
|
export function foldWindowEvents(root, fromKey) {
|
|
309
389
|
const key = `${root}\0${fromKey}`;
|
|
310
|
-
const
|
|
311
|
-
const size = liveStat?.size ?? 0;
|
|
312
|
-
const mtimeMs = liveStat?.mtimeMs ?? 0;
|
|
313
|
-
const dev = liveStat?.dev ?? 0;
|
|
314
|
-
const ino = liveStat?.ino ?? 0;
|
|
390
|
+
const { size, mtimeMs, dev, ino } = statIdentityOrZero(statOrNull(eventsLogPath(root)));
|
|
315
391
|
const cached = reportFoldCache.get(key);
|
|
316
392
|
if (cached &&
|
|
317
393
|
sameStatIdentity({ dev, ino, mtimeMs, size }, { dev: cached.dev, ino: cached.ino, mtimeMs: cached.mtimeMs, size: cached.offset })) {
|
|
@@ -345,6 +421,7 @@ export function foldWindowEvents(root, fromKey) {
|
|
|
345
421
|
fileCovers: raw.coversFullWindow,
|
|
346
422
|
hadEvents: false,
|
|
347
423
|
days: new Map(),
|
|
424
|
+
redEvents: [],
|
|
348
425
|
};
|
|
349
426
|
for (const ev of raw.events)
|
|
350
427
|
foldEventInto(entry, ev);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Main's red time per local calendar day: how long main had no passing full check, from the
|
|
2
|
+
* same `main_check` / `main_red_hold` event trail G1 uses (src/baseline/main-guardrails.ts).
|
|
3
|
+
* Pure and synchronous over an event list and a `[fromMs, toMs)` window, so the usage
|
|
4
|
+
* report's day and --since collectors both call it without reading the clock or the log
|
|
5
|
+
* again. This is main's own wall-clock red time, not any role's, so the report carries it
|
|
6
|
+
* only on the team scope. */
|
|
7
|
+
import { dayKey } from "../text/datetime.js";
|
|
8
|
+
import { isPassingMainCheck, isRedMain } from "../baseline/main-guardrails.js";
|
|
9
|
+
/** Add a spell's ms, split across the local calendar days it spans, to `map` (a Map, so the
|
|
10
|
+
* caller keeps the day-key order the walk produced). */
|
|
11
|
+
function addSpell(map, start, end) {
|
|
12
|
+
let cur = start;
|
|
13
|
+
while (cur < end) {
|
|
14
|
+
// The Date constructor's month/date fields cross the local midnight (and any DST shift
|
|
15
|
+
// at it) exactly as dayAt does, so an hour cannot leak into the next day.
|
|
16
|
+
const d = new Date(cur);
|
|
17
|
+
const nextMidnight = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1).getTime();
|
|
18
|
+
const segEnd = Math.min(end, nextMidnight);
|
|
19
|
+
const ms = segEnd - cur;
|
|
20
|
+
if (ms > 0)
|
|
21
|
+
map.set(dayKey(cur), (map.get(dayKey(cur)) ?? 0) + ms);
|
|
22
|
+
cur = segEnd;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Main's red wall-clock time per local calendar day (`YYYY-MM-DD` → ms), over the window
|
|
26
|
+
* `[fromMs, toMs)`. A red spell is G1's rule (isRedMain / isPassingMainCheck): it opens at a
|
|
27
|
+
* red event while none is open (a further red while open keeps the earliest start) and closes
|
|
28
|
+
* at the next passing full `main_check`; a spell still open at `toMs` runs to the window's
|
|
29
|
+
* end. Every spell is split across local calendar days (dayKey) with midnight arithmetic, so
|
|
30
|
+
* a DST shift cannot leak an hour into the next day; only nonzero daily entries are returned.
|
|
31
|
+
* A spell already open before `fromMs` is not counted, because its opener lies outside the
|
|
32
|
+
* window — the report measures main's own red time within the window it was asked for. */
|
|
33
|
+
export function mainRedMinutesByDay(events, fromMs, toMs) {
|
|
34
|
+
const map = new Map();
|
|
35
|
+
const inWindow = events
|
|
36
|
+
.filter((e) => typeof e.ts === "number" && e.ts >= fromMs && e.ts < toMs)
|
|
37
|
+
.sort((a, b) => a.ts - b.ts);
|
|
38
|
+
let openStart;
|
|
39
|
+
for (const e of inWindow) {
|
|
40
|
+
const ts = e.ts;
|
|
41
|
+
if (isRedMain(e)) {
|
|
42
|
+
if (openStart === undefined)
|
|
43
|
+
openStart = ts;
|
|
44
|
+
}
|
|
45
|
+
else if (isPassingMainCheck(e)) {
|
|
46
|
+
if (openStart !== undefined) {
|
|
47
|
+
addSpell(map, openStart, ts);
|
|
48
|
+
openStart = undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (openStart !== undefined)
|
|
53
|
+
addSpell(map, openStart, toMs);
|
|
54
|
+
return map;
|
|
55
|
+
}
|