tumwater 0.4.2 → 0.4.4
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 +6 -6
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-backend.js +6 -6
- package/dist/src/agent/{run-agent.js → agent-run.js} +27 -13
- package/dist/src/agent/{run-settle.js → agent-settle.js} +48 -24
- package/dist/src/agent/{run-spawn.js → agent-spawn.js} +21 -12
- package/dist/src/agent/{run-stream.js → agent-stream.js} +4 -4
- package/dist/src/agent/backend-traits.js +2 -2
- package/dist/src/agent/claude/claude-account.js +6 -27
- package/dist/src/agent/claude/claude-backend.js +3 -3
- package/dist/src/agent/claude/claude-env.js +27 -31
- package/dist/src/agent/claude/claude-stream.js +111 -54
- package/dist/src/agent/codex/codex-account.js +8 -0
- package/dist/src/agent/codex/codex-args.js +5 -5
- package/dist/src/agent/codex/codex-backend.js +2 -2
- package/dist/src/agent/codex/codex-env.js +28 -15
- package/dist/src/agent/codex/codex-hook-trust.js +39 -20
- package/dist/src/agent/codex/codex-rollout.js +93 -56
- package/dist/src/agent/codex/codex-stream.js +1 -1
- package/dist/src/agent/env-scrub.js +18 -0
- package/dist/src/agent/image-input.js +68 -11
- package/dist/src/agent/notes-shim.js +2 -2
- package/dist/src/agent/opencode/opencode-backend.js +26 -24
- package/dist/src/agent/opencode/opencode-catalog.js +85 -36
- package/dist/src/agent/opencode/opencode-config.js +32 -14
- package/dist/src/agent/opencode/opencode-env.js +12 -13
- package/dist/src/agent/opencode/opencode-stream.js +47 -25
- package/dist/src/agent/session-ledger.js +23 -27
- package/dist/src/agent/subscription-account.js +2 -83
- package/dist/src/backlog/backlog-archive.js +3 -4
- package/dist/src/backlog/backlog-cli-view.js +81 -41
- package/dist/src/backlog/backlog-cli.js +57 -26
- package/dist/src/backlog/backlog-eligibility.js +56 -122
- package/dist/src/backlog/backlog-md.js +5 -5
- package/dist/src/backlog/backlog-parts.js +65 -27
- package/dist/src/backlog/{question-answer.js → backlog-question-answer.js} +1 -1
- package/dist/src/backlog/backlog-release.js +12 -12
- package/dist/src/backlog/backlog-structure.js +114 -61
- package/dist/src/backlog/backlog.js +3 -2
- package/dist/src/baseline/main-baseline.js +148 -84
- package/dist/src/baseline/main-guardrails.js +2 -2
- package/dist/src/baseline/main-watch.js +84 -50
- package/dist/src/brief/brief.js +26 -13
- package/dist/src/budget/budget-fallback-view.js +100 -243
- package/dist/src/budget/budget-wiring.js +29 -65
- package/dist/src/budget/budget.js +4 -5
- package/dist/src/budget/fallback-breaker.js +2 -2
- package/dist/src/build/build-check-detect.js +43 -14
- package/dist/src/build/build-check-events.js +2 -2
- package/dist/src/build/build-check-report.js +10 -0
- package/dist/src/build/build-check-scoped.js +40 -18
- package/dist/src/build/build-check.js +13 -5
- package/dist/src/build/build-stage.js +6 -4
- package/dist/src/change/change-data.js +1 -4
- package/dist/src/cli/cli-command-args.js +89 -52
- package/dist/src/cli/cli-completion-command.js +75 -0
- package/dist/src/cli/{config-commands.js → cli-config-commands.js} +82 -71
- package/dist/src/cli/cli-doctor-command.js +103 -0
- package/dist/src/cli/cli-flag-specs.js +42 -22
- package/dist/src/cli/cli-init.js +36 -14
- package/dist/src/cli/{log-commands.js → cli-log-commands.js} +43 -23
- package/dist/src/cli/{notify-command.js → cli-notify-command.js} +2 -2
- package/dist/src/cli/cli-query-commands.js +2 -2
- package/dist/src/cli/{question-commands.js → cli-question-commands.js} +86 -60
- package/dist/src/cli/cli-repo-gate.js +2 -2
- package/dist/src/cli/cli-role-command.js +2 -41
- package/dist/src/cli/cli-start-summary.js +4 -3
- package/dist/src/cli/cli-start-supervisor.js +190 -0
- package/dist/src/cli/cli-start.js +94 -244
- package/dist/src/cli/completion.js +85 -49
- package/dist/src/cli/follow-view.js +20 -2
- package/dist/src/cli/help.js +6 -13
- package/dist/src/cli.js +70 -176
- package/dist/src/collections.js +39 -27
- package/dist/src/concurrency/check-slots.js +70 -0
- package/dist/src/concurrency/lock.js +23 -1
- package/dist/src/concurrency/run-permit.js +49 -0
- package/dist/src/concurrency/semaphore.js +46 -250
- package/dist/src/config/config-editable-keys.js +4 -7
- package/dist/src/config/config-fallbacks.js +81 -101
- package/dist/src/config/config-field-checks.js +66 -37
- package/dist/src/config/config-keys.js +66 -40
- package/dist/src/config/config-live.js +4 -28
- package/dist/src/config/{model-selector.js → config-model-selector.js} +4 -4
- package/dist/src/config/config-request.js +163 -102
- package/dist/src/config/config-schema.js +10 -12
- package/dist/src/config/config-selector-checks.js +1 -1
- package/dist/src/config/config-validation-agents.js +2 -2
- package/dist/src/config/config-validation-roles.js +8 -72
- package/dist/src/config/config-validation.js +4 -39
- package/dist/src/config/config-views.js +26 -50
- package/dist/src/config/config-write.js +128 -102
- package/dist/src/config/config.js +5 -14
- package/dist/src/doctor/doctor-backlog-bugs.js +7 -6
- package/dist/src/doctor/doctor-backlog-plans.js +53 -120
- package/dist/src/doctor/doctor-backlog.js +16 -14
- package/dist/src/doctor/doctor-check-names.js +3 -6
- package/dist/src/doctor/doctor-checks.js +8 -8
- package/dist/src/doctor/doctor-claude-checks.js +70 -36
- package/dist/src/doctor/doctor-codex-checks.js +6 -6
- package/dist/src/doctor/doctor-contention-checks.js +57 -117
- package/dist/src/doctor/doctor-fallback-checks.js +48 -26
- package/dist/src/doctor/doctor-holds.js +8 -47
- package/dist/src/doctor/doctor-install.js +1 -1
- package/dist/src/doctor/doctor-launch-services.js +1 -1
- package/dist/src/doctor/doctor-model-checks.js +178 -94
- package/dist/src/doctor/doctor-notify.js +2 -2
- package/dist/src/doctor/doctor-opencode-checks.js +5 -4
- package/dist/src/doctor/doctor-orphans.js +122 -21
- package/dist/src/doctor/{outcome.js → doctor-outcome.js} +7 -0
- package/dist/src/doctor/doctor-pi-checks.js +2 -2
- package/dist/src/doctor/doctor-principles.js +3 -3
- package/dist/src/doctor/doctor-project-checks.js +24 -11
- package/dist/src/doctor/doctor-role-notes.js +1 -1
- package/dist/src/doctor/doctor.js +8 -11
- package/dist/src/events/event-format.js +44 -64
- package/dist/src/events/event-labels.js +1 -5
- package/dist/src/events/event-legacy.js +3 -5
- package/dist/src/events/{notify.js → event-notify.js} +6 -6
- package/dist/src/events/event-read.js +1 -1
- package/dist/src/events/event-window.js +1 -1
- package/dist/src/events/events.js +8 -0
- package/dist/src/failure/failure-cluster.js +9 -18
- package/dist/src/failure/failure-data.js +12 -8
- package/dist/src/failure/failure-render.js +46 -36
- package/dist/src/failure/failure-state-change.js +54 -120
- package/dist/src/failure/{time-spend.js → failure-time-spend.js} +117 -84
- package/dist/src/files/files.js +30 -0
- package/dist/src/files/json-object.js +8 -8
- package/dist/src/files/stat-cache.js +12 -8
- package/dist/src/gates/budget-gates.js +85 -84
- package/dist/src/gates/gate-polls.js +32 -74
- package/dist/src/gates/pause-gates.js +16 -2
- package/dist/src/gates/readiness.js +1 -1
- package/dist/src/gates/role-cap-gates.js +44 -35
- package/dist/src/gates/{startup-gate.js → startup-gates.js} +9 -8
- package/dist/src/gates/{streak-gate.js → streak-gates.js} +75 -52
- package/dist/src/git/git-diff.js +6 -2
- package/dist/src/git/git.js +75 -45
- package/dist/src/git/worktree-pool.js +3 -6
- package/dist/src/gui/gui-admin-endpoints.js +3 -3
- package/dist/src/gui/gui-args.js +12 -0
- package/dist/src/gui/gui-backlog-commands.js +4 -4
- package/dist/src/gui/gui-backlog-endpoints.js +61 -41
- package/dist/src/gui/gui-command.js +43 -24
- package/dist/src/gui/gui-config-commands.js +2 -64
- package/dist/src/gui/gui-endpoint-commands.js +1 -1
- package/dist/src/gui/gui-endpoint-common.js +19 -1
- package/dist/src/gui/gui-history-endpoints.js +100 -52
- package/dist/src/gui/gui-operator-commands.js +43 -48
- package/dist/src/gui/gui-prompt-commands.js +25 -25
- package/dist/src/gui/gui-report-endpoints.js +1 -1
- package/dist/src/gui/gui-server.js +1 -2
- package/dist/src/gui/gui-team-commands.js +2 -1
- package/dist/src/history/history-data.js +71 -44
- package/dist/src/history/history-queued.js +49 -27
- package/dist/src/history/history.js +54 -36
- package/dist/src/inbox/prompt-commands.js +59 -42
- package/dist/src/init/init.js +88 -40
- package/dist/src/merge/merge-backlog-conflicts.js +1 -1
- package/dist/src/merge/merge-check-failures.js +12 -9
- package/dist/src/merge/merge-core.js +7 -32
- package/dist/src/merge/merge-drain.js +11 -13
- package/dist/src/merge/merge-pipeline.js +6 -7
- package/dist/src/merge/merge-post-review-drain.js +11 -14
- package/dist/src/merge/merge-queue-render.js +3 -3
- package/dist/src/merge/merge-requeue.js +1 -1
- package/dist/src/merge/merge-slot.js +0 -8
- package/dist/src/merge/merge-stack.js +17 -18
- package/dist/src/merge/merge-to-main.js +13 -58
- package/dist/src/merge/merge-verify.js +12 -21
- package/dist/src/notes-cli.js +52 -42
- package/dist/src/operator/operator-commands.js +80 -47
- package/dist/src/operator/operator-intent.js +3 -3
- package/dist/src/orchestrator/orchestrator-launch.js +31 -63
- package/dist/src/orchestrator/orchestrator-poll.js +44 -69
- package/dist/src/orchestrator/orchestrator-scheduling.js +5 -9
- package/dist/src/orchestrator/orchestrator.js +8 -21
- package/dist/src/orchestrator/scheduling-admit.js +101 -68
- package/dist/src/orchestrator/scheduling-scope.js +18 -27
- package/dist/src/orchestrator/scheduling-skip.js +10 -14
- package/dist/src/orchestrator/startup-migrations.js +1 -1
- package/dist/src/paths.js +10 -9
- package/dist/src/pi/pi-args.js +5 -2
- package/dist/src/pi/pi-backend.js +2 -2
- package/dist/src/pi/pi-bin.js +3 -3
- package/dist/src/pi/pi-event-line.js +28 -1
- package/dist/src/pi/pi-listed-models.js +13 -0
- package/dist/src/pi/pi-models.js +43 -29
- package/dist/src/pi/pi-settings.js +43 -20
- package/dist/src/pi/pi-stream.js +41 -8
- package/dist/src/pi/pi-watchdogs.js +43 -15
- package/dist/src/pi/pi.js +2 -2
- package/dist/src/pi-extension/context-shake.js +32 -20
- package/dist/src/pi-extension/kill-guard.js +69 -0
- package/dist/src/process/process-group.js +51 -26
- package/dist/src/process/process.js +20 -12
- package/dist/src/process/run-marker.js +33 -15
- package/dist/src/process/supervisor.js +40 -28
- package/dist/src/prompt/dialect.js +1 -1
- package/dist/src/prompt/gate-notes.js +2 -2
- package/dist/src/prompt/gate-prompts.js +1 -44
- package/dist/src/prompt/notes-backlog.js +66 -37
- package/dist/src/prompt/principles.js +6 -4
- package/dist/src/prompt/prompt-followup.js +12 -4
- package/dist/src/prompt/prompt.js +88 -38
- package/dist/src/redeploy/redeployer.js +21 -1
- package/dist/src/report/report-data.js +53 -37
- package/dist/src/report/report-fold.js +16 -9
- package/dist/src/report/report-render.js +21 -194
- package/dist/src/report/report-since-data.js +4 -3
- package/dist/src/report/report-since-render.js +173 -0
- package/dist/src/report/report-usage-fold.js +8 -8
- package/dist/src/report/report.js +46 -22
- package/dist/src/review/diff-rules.js +35 -21
- package/dist/src/review/post-merge-review-render.js +9 -3
- package/dist/src/review/post-merge-review.js +48 -41
- package/dist/src/review/review-precheck.js +14 -4
- package/dist/src/review/review.js +48 -170
- package/dist/src/review/secret-leaks.js +26 -16
- package/dist/src/roles/legacy-role-migration.js +6 -3
- package/dist/src/roles/role-catalog.js +11 -3
- package/dist/src/roles/role-guidance.js +16 -12
- package/dist/src/roles/role-render.js +7 -46
- package/dist/src/roles/role-view.js +10 -33
- package/dist/src/run/acceptance-greps.js +88 -45
- package/dist/src/run/ci-parity.js +19 -8
- package/dist/src/run/run-apply.js +12 -15
- package/dist/src/run/run-detail-data.js +121 -68
- package/dist/src/run/run-detail-render.js +92 -35
- package/dist/src/run/run-detail.js +72 -41
- package/dist/src/run/run-prompt.js +63 -50
- package/dist/src/run/run-resume.js +76 -29
- package/dist/src/run/run-stage.js +141 -90
- package/dist/src/run/run-timing.js +8 -2
- package/dist/src/run/run-usage.js +31 -1
- package/dist/src/run/run-verdict.js +128 -50
- package/dist/src/run/stage-check.js +60 -50
- package/dist/src/run/stage-checks-shared.js +28 -0
- package/dist/src/run/stage-name-checks.js +111 -92
- package/dist/src/run/stage-path-checks.js +69 -42
- package/dist/src/run/stage-prose-checks.js +55 -40
- package/dist/src/runner/{leftover.js → runner-leftover.js} +9 -26
- package/dist/src/runner/runner-outcome.js +7 -2
- package/dist/src/runner/runner-pi.js +9 -22
- package/dist/src/runner/runner-recovery.js +5 -13
- package/dist/src/runner/{revision.js → runner-revision.js} +1 -2
- package/dist/src/runner/runner-run.js +103 -50
- package/dist/src/runner/runner-state-load.js +18 -28
- package/dist/src/runner/runner-state.js +0 -14
- package/dist/src/runner/runner.js +41 -25
- package/dist/src/scheduling/backoff.js +8 -3
- package/dist/src/scheduling/claim-entries.js +2 -1
- package/dist/src/scheduling/claims.js +0 -4
- package/dist/src/scheduling/scheduling.js +53 -66
- package/dist/src/status/status-budget.js +4 -43
- package/dist/src/status/status-data.js +35 -39
- package/dist/src/status/status-role-notes.js +2 -2
- package/dist/src/status/status-roles.js +9 -18
- package/dist/src/team/{error-storm.js → team-error-storm.js} +1 -1
- package/dist/src/team/{failure-spread.js → team-failure-spread.js} +5 -5
- package/dist/src/team/team-hold.js +105 -70
- package/dist/src/team/{orchestrator-info.js → team-orchestrator-info.js} +55 -36
- package/dist/src/team/team-polls.js +53 -201
- package/dist/src/team/{reclaim.js → team-reclaim.js} +61 -31
- package/dist/src/team/team-state.js +4 -13
- package/dist/src/text/datetime.js +16 -7
- package/dist/src/text/markdown.js +1 -1
- package/dist/src/text/phrases.js +29 -15
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +6 -5
- package/dist/src/ui/alert-feeds.js +46 -111
- package/dist/src/ui/badges.js +17 -88
- package/dist/src/ui/gui/gui-client-boot.js +2 -8
- package/dist/src/ui/gui/gui-client-composer.js +1 -1
- package/dist/src/ui/gui/gui-client-drawer-config.js +8 -33
- package/dist/src/ui/gui/gui-client-drawer.js +1 -1
- package/dist/src/ui/gui/gui-client-feed.js +1 -1
- package/dist/src/ui/gui/gui-client-history.js +28 -14
- package/dist/src/ui/gui/gui-client-model.js +0 -12
- package/dist/src/ui/gui/gui-client-operator.js +7 -5
- package/dist/src/ui/gui/gui-client-pending.js +7 -6
- package/dist/src/ui/gui/gui-client-report-chart.js +5 -5
- package/dist/src/ui/gui/gui-client-report.js +1 -1
- package/dist/src/ui/gui/gui-client-roles.js +0 -1
- package/dist/src/ui/gui/gui-client-settings.js +43 -84
- package/dist/src/ui/gui/gui-client-team.js +12 -6
- package/dist/src/ui/gui/gui-client.js +7 -1
- package/dist/src/ui/progress-data.js +107 -44
- package/dist/src/ui/run-progress-model.js +20 -4
- package/dist/src/ui/status-model.js +2 -24
- package/dist/src/ui/status-payload.js +11 -30
- package/dist/src/ui/status-render.js +13 -24
- package/dist/src/ui/team-alert-backlog.js +14 -204
- package/dist/src/ui/team-alert-shared.js +6 -29
- package/dist/src/ui/team-alert-status.js +9 -170
- package/dist/src/ui/team-alert-tail.js +19 -215
- package/dist/src/ui/team-alerts.js +8 -15
- package/dist/src/ui/transcript-run.js +27 -16
- package/dist/src/ui/tui/tui-backlog.js +2 -2
- package/dist/src/ui/tui/tui-editor-answer.js +12 -10
- package/dist/src/ui/tui/tui-editor-attach.js +4 -3
- package/dist/src/ui/tui/tui-editor-backends.js +4 -3
- package/dist/src/ui/tui/tui-editor-brief.js +6 -9
- package/dist/src/ui/tui/tui-editor-budget.js +4 -3
- package/dist/src/ui/tui/tui-editor-config.js +80 -68
- package/dist/src/ui/tui/tui-editor-entry.js +12 -20
- package/dist/src/ui/tui/tui-editor-pause.js +51 -57
- package/dist/src/ui/tui/tui-editor-prompt.js +9 -13
- package/dist/src/ui/tui/tui-editor-queued.js +11 -14
- package/dist/src/ui/tui/tui-editor-quiet.js +4 -3
- package/dist/src/ui/tui/tui-editor-release.js +4 -3
- package/dist/src/ui/tui/tui-editor-retire.js +7 -7
- package/dist/src/ui/tui/tui-editor-role-enabled.js +4 -3
- package/dist/src/ui/tui/tui-editor-role-file.js +4 -4
- package/dist/src/ui/tui/tui-editor-role-key.js +4 -3
- package/dist/src/ui/tui/tui-editor-role-model.js +97 -15
- package/dist/src/ui/tui/tui-editor-search.js +4 -3
- package/dist/src/ui/tui/tui-editor-session.js +17 -4
- package/dist/src/ui/tui/tui-editors.js +5 -10
- package/dist/src/ui/tui/tui-frame.js +182 -134
- package/dist/src/ui/tui/tui-guard.js +20 -0
- package/dist/src/ui/tui/tui-input.js +167 -98
- package/dist/src/ui/tui/tui-keymap.js +51 -29
- package/dist/src/ui/tui/tui-keys.js +1 -1
- package/dist/src/ui/tui/tui-pane-activity.js +5 -4
- package/dist/src/ui/tui/tui-pane-backlog.js +74 -36
- package/dist/src/ui/tui/tui-pane-ctx.js +1 -1
- package/dist/src/ui/tui/tui-pane-health.js +252 -230
- package/dist/src/ui/tui/tui-pane-history.js +67 -74
- package/dist/src/ui/tui/tui-pane-pending.js +288 -247
- package/dist/src/ui/tui/tui-pane-queued.js +25 -27
- package/dist/src/ui/tui/tui-pane-report.js +2 -1
- package/dist/src/ui/tui/tui-pane-session.js +15 -10
- package/dist/src/ui/tui/tui-pane-transcript.js +19 -31
- package/dist/src/ui/tui/tui-pane.js +14 -11
- package/dist/src/ui/tui/tui-panes.js +38 -33
- package/dist/src/ui/tui/tui.js +4 -7
- package/dist/src/verdict/fix-claim.js +107 -56
- package/dist/src/verdict/refusal.js +1 -1
- package/dist/src/verdict/reply-contract.js +3 -4
- package/package.json +5 -5
- package/dist/src/concurrency/provider-lease.js +0 -105
- package/dist/src/review/review-followup.js +0 -87
- package/dist/src/review/review-run.js +0 -395
- package/dist/src/runner/model-fallback.js +0 -76
- package/dist/src/runner/runner-fallback.js +0 -66
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +0 -24
- package/dist/src/ui/tui/tui-editor-provider-caps.js +0 -27
- /package/dist/src/cli/{brief-command.js → cli-brief-command.js} +0 -0
- /package/dist/src/doctor/{probe.js → doctor-probe.js} +0 -0
- /package/dist/src/gates/{disk-gate.js → disk-gates.js} +0 -0
- /package/dist/src/operator/{retire.js → operator-retire.js} +0 -0
- /package/dist/src/operator/{revert.js → operator-revert.js} +0 -0
|
@@ -31,30 +31,41 @@ export function runDetailStat(root, d) {
|
|
|
31
31
|
export function runDetailPatch(root, d) {
|
|
32
32
|
return runCommitShow(root, runCommitSha(d), "--patch");
|
|
33
33
|
}
|
|
34
|
-
/** The
|
|
35
|
-
* marker
|
|
36
|
-
|
|
37
|
-
* `merge_queued`/`merge_done` event carries one — then each event through formatEvent, the
|
|
38
|
-
* shared renderer `logs` and the
|
|
39
|
-
* TUI use, so the trail reads exactly like the feed it came from. A queued run whose merge
|
|
40
|
-
* has finished shows that verdict in the header and ends with the merge's outcome line; a
|
|
41
|
-
* leftover-recovery run's verdict is the failed attempt it re-queued (resolveQueuedResult),
|
|
42
|
-
* logged before the run began, so that outcome line leads the trail instead — the trail stays
|
|
43
|
-
* in time order. */
|
|
44
|
-
export function renderRunDetail(d) {
|
|
45
|
-
const summary = [];
|
|
34
|
+
/** The run's result cell, always present: the outcome label when the run finished, the
|
|
35
|
+
* in-flight/unpaired marker when it has not. Owns the first summary cell. */
|
|
36
|
+
function runResultCell(d) {
|
|
46
37
|
if (d.endTs === null)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
return d.startTs === null ? "unpaired" : "in flight";
|
|
39
|
+
return d.result ? eventTypeLabel(d.result) : "?";
|
|
40
|
+
}
|
|
41
|
+
/** The run's cut-off cell, the ceiling-truncation marker straight after the result cell. It
|
|
42
|
+
* only rides a completed end (cutOff is set from the run_end), so it can never follow in
|
|
43
|
+
* flight/unpaired. */
|
|
44
|
+
function runCutOffCell(d) {
|
|
50
45
|
// The ceiling-truncation marker, straight after the result cell. It only rides a
|
|
51
46
|
// completed end (cutOff is set from the run_end), so it can never follow in flight/unpaired.
|
|
52
|
-
if (d.cutOff
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
if (d.cutOff !== true)
|
|
48
|
+
return null;
|
|
49
|
+
return "cut off at the context ceiling";
|
|
50
|
+
}
|
|
51
|
+
/** The run's duration cell. */
|
|
52
|
+
function runDurationCell(d) {
|
|
53
|
+
if (d.durationMs === null)
|
|
54
|
+
return null;
|
|
55
|
+
return shortSpanPhrase(d.durationMs);
|
|
56
|
+
}
|
|
57
|
+
/** The run's usage cell. */
|
|
58
|
+
function runUsageCell(d) {
|
|
59
|
+
if (d.usage === "")
|
|
60
|
+
return null;
|
|
61
|
+
return d.usage;
|
|
62
|
+
}
|
|
63
|
+
/** The run's prompt cell: the prompt-token total and the share the backend served from cache,
|
|
64
|
+
* the input side a cost-only header hides. The `${n}% cached` wording and rounding are the
|
|
65
|
+
* usage report's `Prompt tokens by role` share; a run with prompt tokens but no cache reads
|
|
66
|
+
* shows no parenthetical, and a run that reported neither keeps today's header byte-identical
|
|
67
|
+
* (the omit-when-zero convention). */
|
|
68
|
+
function runPromptCell(d) {
|
|
58
69
|
// The run's prompt-token total and the share the backend served from cache, the input
|
|
59
70
|
// side a cost-only header hides. The `${n}% cached` wording and rounding are the usage
|
|
60
71
|
// report's `Prompt tokens by role` share; a run with prompt tokens but no cache reads
|
|
@@ -62,37 +73,71 @@ export function renderRunDetail(d) {
|
|
|
62
73
|
// byte-identical (the omit-when-zero convention).
|
|
63
74
|
const prompt = d.promptTokens ?? 0;
|
|
64
75
|
const cached = Math.min(d.cacheReadTokens ?? 0, prompt);
|
|
65
|
-
if (prompt
|
|
66
|
-
|
|
76
|
+
if (prompt <= 0)
|
|
77
|
+
return null;
|
|
78
|
+
return cached > 0 ? `prompt ${compactTokens(prompt)} tok (${Math.round((100 * cached) / prompt)}% cached)` : `prompt ${compactTokens(prompt)} tok`;
|
|
79
|
+
}
|
|
80
|
+
/** The run's pre-edit prompt-token share, the `… before first edit` signal a cost-only header
|
|
81
|
+
* hides: how much of the prompt budget went out before the run made its first edit. Clamped
|
|
82
|
+
* to the total (run-detail-data.ts), written after the prompt cell and before the
|
|
83
|
+
* peak-context cell; a run that reported no pre-edit reading — and an in-flight run — keeps
|
|
84
|
+
* today's header byte-identical. */
|
|
85
|
+
function runPreEditCell(d) {
|
|
67
86
|
// The run's pre-edit prompt-token share, the `… before first edit` signal a cost-only
|
|
68
87
|
// header hides: how much of the prompt budget went out before the run made its first
|
|
69
88
|
// edit. Clamped to the total (run-detail-data.ts), written after the prompt cell and
|
|
70
89
|
// before the peak-context cell; a run that reported no pre-edit reading — and an
|
|
71
90
|
// in-flight run — keeps today's header byte-identical.
|
|
91
|
+
const prompt = d.promptTokens ?? 0;
|
|
72
92
|
const preEdit = Math.min(d.preEditPromptTokens ?? 0, prompt);
|
|
73
|
-
if (preEdit
|
|
74
|
-
|
|
93
|
+
if (preEdit <= 0)
|
|
94
|
+
return null;
|
|
95
|
+
return `pre-edit ${compactTokens(preEdit)} tok`;
|
|
96
|
+
}
|
|
97
|
+
/** The run's peak-context cell against the seam's declared window, the one header every surface
|
|
98
|
+
* renders. Omitted when the run reported no peak (byte-identical to today's header). */
|
|
99
|
+
function runPeakContextCell(d) {
|
|
75
100
|
// The run's peak context against the seam's declared window, the one header every surface
|
|
76
101
|
// renders. Omitted when the run reported no peak (byte-identical to today's header).
|
|
77
|
-
if ((d.peakContextTokens ?? 0)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
if ((d.peakContextTokens ?? 0) <= 0)
|
|
103
|
+
return null;
|
|
104
|
+
return `peak ctx ${contextShareLabel(d.peakContextTokens ?? 0, d.contextWindow)}`;
|
|
105
|
+
}
|
|
106
|
+
/** The run's model cell, the model the run started on. */
|
|
107
|
+
function runModelCell(d) {
|
|
108
|
+
if (d.model === null)
|
|
109
|
+
return null;
|
|
110
|
+
return d.model;
|
|
111
|
+
}
|
|
112
|
+
/** The summary cells in today's push order — result, cut-off, duration, usage, prompt,
|
|
113
|
+
* pre-edit, peak-context, model — each present only when its guard omits nothing. */
|
|
114
|
+
function runSummaryCells(d) {
|
|
115
|
+
return [runResultCell(d), runCutOffCell(d), runDurationCell(d), runUsageCell(d), runPromptCell(d), runPreEditCell(d), runPeakContextCell(d), runModelCell(d)].filter((cell) => cell !== null);
|
|
116
|
+
}
|
|
117
|
+
/** The header's ` · `-separated suffix cells after the summary: the pinned commit, `merged
|
|
118
|
+
* as`, end-of-run landing latency, and the deliberate-revert verdict. */
|
|
119
|
+
function runHeaderSuffixCells(d) {
|
|
81
120
|
const sha = runCommitSha(d);
|
|
82
|
-
|
|
121
|
+
const cells = [];
|
|
83
122
|
if (sha !== null)
|
|
84
|
-
|
|
123
|
+
cells.push(`commit ${shortSha(sha)}`);
|
|
85
124
|
if (d.mergedSha !== null && d.mergedSha !== sha)
|
|
86
|
-
|
|
125
|
+
cells.push(`merged as ${shortSha(d.mergedSha)}`);
|
|
87
126
|
// The end-of-run → on-main landing latency, the per-change twin of the day report's `Merge
|
|
88
127
|
// wait median`. shortSpanPhrase is the duration cell's renderer, so both spans read alike; a
|
|
89
128
|
// run without the field (rejected/failed merge, in flight, landing rotated out, no-op
|
|
90
129
|
// fast-forward) keeps today's header byte-identical.
|
|
91
130
|
if (d.mergeAfterRunMs !== undefined)
|
|
92
|
-
|
|
131
|
+
cells.push(`merged ${shortSpanPhrase(d.mergeAfterRunMs)} after the run`);
|
|
93
132
|
if (d.reverted !== null) {
|
|
94
|
-
|
|
133
|
+
cells.push(`reverted ${shortSha(d.reverted.sha)} (by operator)`); // vocabulary-ok: the deliberate-revert writer this header names
|
|
95
134
|
}
|
|
135
|
+
return cells;
|
|
136
|
+
}
|
|
137
|
+
/** The trail lines: the run's events through the shared formatEvent, with the merge outcome
|
|
138
|
+
* line placed before the first event when it predates it (a leftover-recovery run) and after
|
|
139
|
+
* the last otherwise, keeping the trail in time order. */
|
|
140
|
+
function runTrailLines(d) {
|
|
96
141
|
const trail = d.events.map(formatEvent);
|
|
97
142
|
if (d.merge !== null) {
|
|
98
143
|
const first = d.events[0];
|
|
@@ -101,7 +146,19 @@ export function renderRunDetail(d) {
|
|
|
101
146
|
else
|
|
102
147
|
trail.push(formatEvent(d.merge));
|
|
103
148
|
}
|
|
104
|
-
return
|
|
149
|
+
return trail;
|
|
150
|
+
}
|
|
151
|
+
/** The human view of a RunDetail: one summary line assembled from the per-cell and
|
|
152
|
+
* per-trail-step helpers — the result (or in-flight/unpaired marker), cut-off, duration,
|
|
153
|
+
* usage, prompt, pre-edit, peak-context and model cells, then the committed sha, `merged as`,
|
|
154
|
+
* merge-latency and reverted suffix cells — and each event through formatEvent. A queued run
|
|
155
|
+
* whose merge has finished shows that verdict in the header and ends with the merge's outcome
|
|
156
|
+
* line; a leftover-recovery run's verdict is the failed attempt it re-queued
|
|
157
|
+
* (resolveQueuedResult), logged before the run began, so that outcome line leads the trail
|
|
158
|
+
* instead — the trail stays in time order. */
|
|
159
|
+
export function renderRunDetail(d) {
|
|
160
|
+
const header = [`${roleLabel(d.role)} run #${d.run} — ${runSummaryCells(d).join(" · ")}`, ...runHeaderSuffixCells(d)].join(" · ");
|
|
161
|
+
return [header, ...runTrailLines(d)].join("\n");
|
|
105
162
|
}
|
|
106
163
|
/** The transcript block of `--transcript`: the rendered lines of the agent runs that started in the
|
|
107
164
|
* run's window, or `found: []` plus the `note` the text view prints in their place. The
|
|
@@ -57,15 +57,11 @@ export function newestRunRow(root, role, classes, models) {
|
|
|
57
57
|
function newestRunNumber(root, role, classes, models) {
|
|
58
58
|
return newestRunRow(root, role, classes, models)?.run ?? null;
|
|
59
59
|
}
|
|
60
|
-
/** The
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
|
|
65
|
-
* the never-throwing cached loader so a transiently broken tumwater.json cannot take a
|
|
66
|
-
* read-only view down). The arity, unknown-role and flag-dependency failures all `fail` with
|
|
67
|
-
* the usage. */
|
|
68
|
-
function parseRunDetailInvocation(root, positionals, { last, transcript, prompt, grep, result, model }) {
|
|
60
|
+
/** The positional and role half of parseRunDetailInvocation's validation: the bare/last arity,
|
|
61
|
+
* the canonical role id, the unknown-role guard (knownRoleIdsCached) and the three arity
|
|
62
|
+
* `fail`s — one name so the whole positional surface is found by this helper. Returns whether
|
|
63
|
+
* the call is bare (`--last` with no role) and the resolved role. */
|
|
64
|
+
function runDetailPositionals(root, positionals, last) {
|
|
69
65
|
// Positional arity by form: cli.ts has already peeled the flags off and gated them (only
|
|
70
66
|
// --json and --last are admitted), so anything left over that does not fit the chosen form
|
|
71
67
|
// is a mistake. The role is checked first, so a typo is named whatever the count; then
|
|
@@ -91,6 +87,13 @@ function parseRunDetailInvocation(root, positionals, { last, transcript, prompt,
|
|
|
91
87
|
}
|
|
92
88
|
fail(`usage: ${RUN_DETAIL_USAGE}`);
|
|
93
89
|
}
|
|
90
|
+
return { bare, role };
|
|
91
|
+
}
|
|
92
|
+
/** The flag-dependency half of parseRunDetailInvocation's validation: the four `fail` guards —
|
|
93
|
+
* `--prompt`/`--grep` need `--transcript`, `--result`/`--model` need `--last` — one name so the
|
|
94
|
+
* whole dependency surface is found by this helper. */
|
|
95
|
+
function checkRunDetailFlagDeps(flags) {
|
|
96
|
+
const { last, transcript, prompt, grep, result, model } = flags;
|
|
94
97
|
if (prompt && !transcript)
|
|
95
98
|
fail(`history --prompt needs --transcript (usage: ${RUN_DETAIL_USAGE})`);
|
|
96
99
|
if (grep !== null && !transcript)
|
|
@@ -99,10 +102,67 @@ function parseRunDetailInvocation(root, positionals, { last, transcript, prompt,
|
|
|
99
102
|
fail(`history --result needs --last on a one-run trail (usage: ${RUN_DETAIL_USAGE})`);
|
|
100
103
|
if (model !== null && !last)
|
|
101
104
|
fail(`history --model needs --last on a one-run trail (usage: ${RUN_DETAIL_USAGE})`);
|
|
105
|
+
}
|
|
106
|
+
/** The invocation half of cmdRunDetail: rule out the arity and flag mistakes before any run is
|
|
107
|
+
* resolved, so the shared unknown-role wording and the usage string are the whole validation
|
|
108
|
+
* surface, found by this one name. Succeeds only for a well-formed call; returns the parsed
|
|
109
|
+
* bare/role/classes/models for the resolver. Delegates the positional/role arity to
|
|
110
|
+
* runDetailPositionals and the flag-dependency guards to checkRunDetailFlagDeps, then parses
|
|
111
|
+
* the --result class and --model selector lists. */
|
|
112
|
+
function parseRunDetailInvocation(root, positionals, { last, transcript, prompt, grep, result, model }) {
|
|
113
|
+
const { bare, role } = runDetailPositionals(root, positionals, last);
|
|
114
|
+
checkRunDetailFlagDeps({ last, transcript, prompt, grep, result, model });
|
|
102
115
|
const classes = result !== null ? parseHistoryResultList(result) : null;
|
|
103
116
|
const models = model !== null ? parseHistoryModelList(model) : null;
|
|
104
117
|
return { bare, role, classes, models };
|
|
105
118
|
}
|
|
119
|
+
/** The not-found branch of cmdRunDetail for the --last form: the scan came up empty, not found
|
|
120
|
+
* by construction, the last-form wording — `sayJson(null)` under --json, else
|
|
121
|
+
* runNotFoundLastMessage. */
|
|
122
|
+
function runDetailLastMiss(parsed, role, json) {
|
|
123
|
+
// The --last scan came up empty: not found by construction, the last-form wording.
|
|
124
|
+
if (json)
|
|
125
|
+
sayJson(null);
|
|
126
|
+
else
|
|
127
|
+
say(runNotFoundLastMessage(parsed.bare ? null : role, parsed.classes, parsed.models));
|
|
128
|
+
}
|
|
129
|
+
/** The not-found branch of cmdRunDetail for the numbered form: not found stays exit 0 in both
|
|
130
|
+
* renderings, but --json still owes a parseable document in every exit-0 case (`null`), else
|
|
131
|
+
* the runNotFoundMessage prose line. */
|
|
132
|
+
function runDetailNumberMiss(role, runNumber, json) {
|
|
133
|
+
// Not found stays exit 0 in both renderings, but --json still owes a parseable document in
|
|
134
|
+
// every exit-0 case (the report --json precedent, the invariant this command's own doc
|
|
135
|
+
// comment claims): `null` is the JSON answer for a single-record lookup that missed — the
|
|
136
|
+
// prose line would end a jq pipe mid-team-incident.
|
|
137
|
+
if (json)
|
|
138
|
+
sayJson(null);
|
|
139
|
+
else
|
|
140
|
+
say(runNotFoundMessage(role, runNumber));
|
|
141
|
+
}
|
|
142
|
+
/** The render half of cmdRunDetail: build the --stat/--patch footer and the --transcript lines,
|
|
143
|
+
* then emit the --json payload or the human-rendered trail (renderRunDetail plus the footer and
|
|
144
|
+
* transcript text). */
|
|
145
|
+
async function emitRunDetail(root, role, runNumber, detail, json, opts) {
|
|
146
|
+
// --json swaps the renderer for the collector's own payload, exactly as history --json: a
|
|
147
|
+
// JSON document in every exit-0 case, never prose.
|
|
148
|
+
const footer = {};
|
|
149
|
+
if (opts.stat)
|
|
150
|
+
footer.stat = await runDetailStat(root, detail);
|
|
151
|
+
if (opts.patch)
|
|
152
|
+
footer.patch = await runDetailPatch(root, detail);
|
|
153
|
+
const transcriptLines = opts.transcript
|
|
154
|
+
? runTranscriptLines(root, role, runNumber, detail, { includePrompts: opts.prompt, grep: opts.grep ?? undefined })
|
|
155
|
+
: null;
|
|
156
|
+
if (json) {
|
|
157
|
+
sayJson({ ...detail, ...footer, ...(transcriptLines === null ? {} : { transcript: transcriptLines.found }) });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const transcriptText = transcriptLines === null
|
|
161
|
+
? []
|
|
162
|
+
: [transcriptLines.found.length > 0 ? transcriptLines.found.join("\n") : transcriptLines.note];
|
|
163
|
+
say([renderRunDetail(detail), ...Object.values(footer), ...transcriptText].join("\n\n"));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
106
166
|
/** The resolution half of cmdRunDetail: pick the run to open and read its detail. Bare `--last`
|
|
107
167
|
* takes the newest run of any role (its role from the row); `--last` with a role the newest run
|
|
108
168
|
* by number; the numbered path the user's positive integer. An empty or unreadable scan is null
|
|
@@ -150,41 +210,12 @@ export async function cmdRunDetail(root, positionals, json, { last = false, stat
|
|
|
150
210
|
const parsed = parseRunDetailInvocation(root, positionals, { last, transcript, prompt, grep, result, model });
|
|
151
211
|
const { role, runNumber, detail } = resolveRunDetailTarget(root, parsed, positionals, last);
|
|
152
212
|
if (runNumber === null) {
|
|
153
|
-
|
|
154
|
-
if (json)
|
|
155
|
-
sayJson(null);
|
|
156
|
-
else
|
|
157
|
-
say(runNotFoundLastMessage(parsed.bare ? null : role, parsed.classes, parsed.models));
|
|
213
|
+
runDetailLastMiss(parsed, role, json);
|
|
158
214
|
return;
|
|
159
215
|
}
|
|
160
216
|
if (detail === null) {
|
|
161
|
-
|
|
162
|
-
// every exit-0 case (the report --json precedent, the invariant this command's own doc
|
|
163
|
-
// comment claims): `null` is the JSON answer for a single-record lookup that missed — the
|
|
164
|
-
// prose line would end a jq pipe mid-team-incident.
|
|
165
|
-
if (json)
|
|
166
|
-
sayJson(null);
|
|
167
|
-
else
|
|
168
|
-
say(runNotFoundMessage(role, runNumber));
|
|
217
|
+
runDetailNumberMiss(role, runNumber, json);
|
|
169
218
|
return;
|
|
170
219
|
}
|
|
171
|
-
|
|
172
|
-
// JSON document in every exit-0 case, never prose.
|
|
173
|
-
const footer = {};
|
|
174
|
-
if (stat)
|
|
175
|
-
footer.stat = await runDetailStat(root, detail);
|
|
176
|
-
if (patch)
|
|
177
|
-
footer.patch = await runDetailPatch(root, detail);
|
|
178
|
-
const transcriptLines = transcript
|
|
179
|
-
? runTranscriptLines(root, role, runNumber, detail, { includePrompts: prompt, grep: grep ?? undefined })
|
|
180
|
-
: null;
|
|
181
|
-
if (json) {
|
|
182
|
-
sayJson({ ...detail, ...footer, ...(transcriptLines === null ? {} : { transcript: transcriptLines.found }) });
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
const transcriptText = transcriptLines === null
|
|
186
|
-
? []
|
|
187
|
-
: [transcriptLines.found.length > 0 ? transcriptLines.found.join("\n") : transcriptLines.note];
|
|
188
|
-
say([renderRunDetail(detail), ...Object.values(footer), ...transcriptText].join("\n\n"));
|
|
189
|
-
}
|
|
220
|
+
await emitRunDetail(root, role, runNumber, detail, json, { stat, patch, transcript, prompt, grep });
|
|
190
221
|
}
|
|
@@ -23,7 +23,7 @@ import { readFeedbackFilings, renderFilingsBlock } from "./feedback-filings.js";
|
|
|
23
23
|
import { roleNotesPath } from "../paths.js";
|
|
24
24
|
import * as path from "node:path";
|
|
25
25
|
import { pathTokens } from "../text/text.js";
|
|
26
|
-
import { isDirectory, readTextOrNull, statOrNull } from "../files/files.js";
|
|
26
|
+
import { isDirectory, readRegularTextOrNull, readTextOrNull, statOrNull } from "../files/files.js";
|
|
27
27
|
import { dayKey } from "../text/datetime.js";
|
|
28
28
|
import { appendPromptNote, prependPromptNote } from "../text/format.js";
|
|
29
29
|
import { ROLE_NOTES_MAX_BYTES } from "../agent/role-notes-write.js";
|
|
@@ -55,9 +55,11 @@ function missingEntryPaths(root, file, range) {
|
|
|
55
55
|
* brief text reader apply to their hand-editable files. A UTF-8 character is never
|
|
56
56
|
* fewer than one byte, so a note the tool accepted (≤ 4096 bytes) is always ≤ 4096 chars
|
|
57
57
|
* and never trips this bound; only an over-cap file is cut, with truncateWithNote's visible
|
|
58
|
-
* marker naming the loss.
|
|
58
|
+
* marker naming the loss. A symlinked note file reads as absent (readRegularTextOrNull never
|
|
59
|
+
* follows a symlink out of the worktree, INV-G3/G4's lstat policy): a hostile note that is a
|
|
60
|
+
* symlink cannot pull an arbitrary host file's text into this role's prompt. */
|
|
59
61
|
function readRoleNote(root, role) {
|
|
60
|
-
const text =
|
|
62
|
+
const text = readRegularTextOrNull(roleNotesPath(root, role));
|
|
61
63
|
return text === null ? undefined : truncateWithNote(text, ROLE_NOTES_MAX_BYTES, "role notes");
|
|
62
64
|
}
|
|
63
65
|
/** The bugfix run's tally of checks the merge gate excused as flaky in the last day, or
|
|
@@ -199,55 +201,40 @@ function collectRoleRequest(root, role, preview) {
|
|
|
199
201
|
function collectSelfcheckDigest(root, base) {
|
|
200
202
|
return base === "selfcheck" || base === "feedback" ? selfcheckDigest(root) : undefined;
|
|
201
203
|
}
|
|
202
|
-
/**
|
|
203
|
-
* block on a missing or unreadable ledger (
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
204
|
+
/** One observer-ledger block: rendered from disk only for its owning role, degrading to no
|
|
205
|
+
* block on a missing or unreadable ledger (a throw) so the run prompt stays byte-unchanged in
|
|
206
|
+
* the common first-run case. The `qa` (flow coverage), `ci` (parity) and `feedback` (filings)
|
|
207
|
+
* ledgers are runtime state a fresh session must not depend on, and the three collect*Block
|
|
208
|
+
* functions each rendered their ledger through this same try/catch guard before the helper. */
|
|
209
|
+
function runtimeLedgerBlock(base, role, render) {
|
|
210
|
+
if (base !== role)
|
|
211
|
+
return undefined;
|
|
212
|
+
try {
|
|
213
|
+
return render();
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return undefined;
|
|
216
217
|
}
|
|
217
|
-
return coverage;
|
|
218
218
|
}
|
|
219
|
-
/** The `
|
|
220
|
-
*
|
|
221
|
-
*
|
|
219
|
+
/** The `qa` observer's flow-coverage ledger, rerendered from disk each run (the flow rotation
|
|
220
|
+
* needs a memory of what it last exercised — every run is a fresh session, and a passing cheap
|
|
221
|
+
* check leaves nothing in the repo), degrading to no block (plans/observer-roles.md 2/2). */
|
|
222
|
+
function collectQaCoverageBlock(root, base) {
|
|
223
|
+
return runtimeLedgerBlock(base, "qa", () => renderCoverageBlock(readQaCoverage(root)));
|
|
224
|
+
}
|
|
225
|
+
/** The `ci` observer's parity block: what the last run covered (tip and lock hash) so a fresh
|
|
226
|
+
* session can decide nothing-to-do without re-running the whole suite (part 3/3). Degrades to
|
|
227
|
+
* no block exactly like qa's. */
|
|
222
228
|
function collectCiParityBlock(root, config, base) {
|
|
223
|
-
|
|
224
|
-
if (base === "ci") {
|
|
225
|
-
try {
|
|
226
|
-
ciParity = parityBlockFor(root, config);
|
|
227
|
-
}
|
|
228
|
-
catch {
|
|
229
|
-
ciParity = undefined;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return ciParity;
|
|
229
|
+
return runtimeLedgerBlock(base, "ci", () => parityBlockFor(root, config));
|
|
233
230
|
}
|
|
234
231
|
/** The `feedback` observer's per-install filing ledger: what this install already filed as
|
|
235
232
|
* GitHub issues on znation/tumwater, so the fresh session's charter dedupes against a
|
|
236
|
-
* "previously filed" block instead of the network alone.
|
|
237
|
-
*
|
|
233
|
+
* "previously filed" block instead of the network alone. Degrades to no block
|
|
234
|
+
* (plans/feedback-role.md 2/2); the render returns undefined for an empty ledger, so the
|
|
235
|
+
* prompt is unchanged in the common first-run case. */
|
|
238
236
|
function collectFeedbackFilingsBlock(root, base) {
|
|
239
|
-
|
|
240
|
-
// first-run case.
|
|
241
|
-
let filings;
|
|
242
|
-
if (base === "feedback") {
|
|
243
|
-
try {
|
|
244
|
-
filings = renderFilingsBlock(readFeedbackFilings(root));
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
filings = undefined;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return filings;
|
|
237
|
+
return runtimeLedgerBlock(base, "feedback", () => renderFilingsBlock(readFeedbackFilings(root)));
|
|
251
238
|
}
|
|
252
239
|
/** The clean role's deterministic backlog repair: stranded plan headings in the primary
|
|
253
240
|
* checkout's PLANS.md (plans, part 3/4), rendered like the digest and coverage blocks. */
|
|
@@ -258,7 +245,7 @@ function collectBacklogStructureBlock(root, base) {
|
|
|
258
245
|
/** Read the role's own notes plus their saved day and live backlog state (notes-backlog.ts),
|
|
259
246
|
* returning all three in one place. */
|
|
260
247
|
function readPromptNotes(root, role) {
|
|
261
|
-
// The role's notes (
|
|
248
|
+
// The role's own notes (readRoleNote): its earlier runs' note. A missing,
|
|
262
249
|
// empty, or unreadable file yields undefined, so the block is omitted; the write
|
|
263
250
|
// instruction in buildRunPrompt is present either way. The director branch above never
|
|
264
251
|
// reads this path, so it carries no notes.
|
|
@@ -312,15 +299,12 @@ function collectRoleDirectives(root, config, base, check) {
|
|
|
312
299
|
: undefined;
|
|
313
300
|
return { planTargetNote, flakyChecks, noCheck };
|
|
314
301
|
}
|
|
315
|
-
|
|
316
|
-
* in its current order, and return the finished prompt. */
|
|
317
|
-
function appendRunEpilogue(root, role, state, prompt, userPrompt, rejectedReview) {
|
|
302
|
+
function appendAssignmentNotes(prompt, root, role, claim, userPrompt) {
|
|
318
303
|
// A work instance holding a claim is told which entry is its one task (plans/parallel-work-
|
|
319
304
|
// instances.md "Claims", part 4/7) — the harness picked it, so the charter's choosing step
|
|
320
305
|
// is replaced. A run that dequeued a user request runs that request instead and keeps the
|
|
321
306
|
// claim for the next non-request run. The range is looked up by key in the current checkout,
|
|
322
307
|
// so it survives a moved section boundary.
|
|
323
|
-
const claim = role === DIRECTOR_ROLE ? undefined : state.claim;
|
|
324
308
|
if (claim && userPrompt === null) {
|
|
325
309
|
const range = eligibleEntries(root, role).find((e) => e.key === claim.key);
|
|
326
310
|
prompt = appendPromptNote(prompt, buildAssignmentNote(claim, range, range ? missingEntryPaths(root, claim.file, range) : []));
|
|
@@ -328,20 +312,32 @@ function appendRunEpilogue(root, role, state, prompt, userPrompt, rejectedReview
|
|
|
328
312
|
if (merged.length > 0)
|
|
329
313
|
prompt = appendPromptNote(prompt, buildMergedPrerequisitesNote(merged));
|
|
330
314
|
}
|
|
315
|
+
return prompt;
|
|
316
|
+
}
|
|
317
|
+
function appendWaitingPartsNote(prompt, root, claim, userPrompt) {
|
|
331
318
|
if (claim && userPrompt === null && claim.file === "PLANS.md") {
|
|
332
319
|
const waiting = waitingPartRanges(root, claim.title);
|
|
333
320
|
if (waiting.length > 0)
|
|
334
321
|
prompt = appendPromptNote(prompt, buildWaitingPartsNote(waiting));
|
|
335
322
|
}
|
|
323
|
+
return prompt;
|
|
324
|
+
}
|
|
325
|
+
function appendHeldElsewhereNote(prompt, role, claim, userPrompt, state) {
|
|
336
326
|
if (!claim && userPrompt === null && role !== DIRECTOR_ROLE && state.heldElsewhere?.length) {
|
|
337
327
|
prompt = appendPromptNote(prompt, buildHeldEntriesNote(state.heldElsewhere));
|
|
338
328
|
}
|
|
329
|
+
return prompt;
|
|
330
|
+
}
|
|
331
|
+
function prependRejectedReviewNote(prompt, role, rejectedReview) {
|
|
339
332
|
// The director builds its prompt through buildDirectorPrompt, which does not take the rejected
|
|
340
333
|
// note, so the standing rejection leads its prompt here instead (a director-authored change can
|
|
341
334
|
// be rejected too). Kept uniform with the authoring roles: the reasons open the run.
|
|
342
335
|
if (rejectedReview !== undefined && role === DIRECTOR_ROLE) {
|
|
343
336
|
prompt = prependPromptNote(prompt, rejectedReview);
|
|
344
337
|
}
|
|
338
|
+
return prompt;
|
|
339
|
+
}
|
|
340
|
+
function appendRunMemoryNotes(prompt, state) {
|
|
345
341
|
// Likewise a change leftover recovery discarded as unmergeable: named until the role queues
|
|
346
342
|
// its next change (the discarding run itself appends it after recovery — see runOnce).
|
|
347
343
|
const discard = state.conflictDiscard;
|
|
@@ -355,6 +351,23 @@ function appendRunEpilogue(root, role, state, prompt, userPrompt, rejectedReview
|
|
|
355
351
|
}
|
|
356
352
|
return prompt;
|
|
357
353
|
}
|
|
354
|
+
/** Append the shared claim/held/discard/cut-off tail — identical for a director and a role —
|
|
355
|
+
* in its current order, and return the finished prompt. It delegates each note group to a
|
|
356
|
+
* named module-private helper: appendAssignmentNotes (which folds in the merged-prerequisite
|
|
357
|
+
* follow-up), appendWaitingPartsNote, appendHeldElsewhereNote, prependRejectedReviewNote and
|
|
358
|
+
* appendRunMemoryNotes. */
|
|
359
|
+
function appendRunEpilogue(root, role, state, prompt, userPrompt, rejectedReview) {
|
|
360
|
+
// The shared cross-run tail every role prompt carries, ordinally: the claim assignment (with
|
|
361
|
+
// its merged-prerequisite and waiting-part follow-ups), the held-elsewhere note, the
|
|
362
|
+
// director's leading rejection, and the discard and cut-off run memory.
|
|
363
|
+
const claim = role === DIRECTOR_ROLE ? undefined : state.claim;
|
|
364
|
+
prompt = appendAssignmentNotes(prompt, root, role, claim, userPrompt);
|
|
365
|
+
prompt = appendWaitingPartsNote(prompt, root, claim, userPrompt);
|
|
366
|
+
prompt = appendHeldElsewhereNote(prompt, role, claim, userPrompt, state);
|
|
367
|
+
prompt = prependRejectedReviewNote(prompt, role, rejectedReview);
|
|
368
|
+
prompt = appendRunMemoryNotes(prompt, state);
|
|
369
|
+
return prompt;
|
|
370
|
+
}
|
|
358
371
|
/** Assemble the prompt a role's next run operates on — the whole "what should this run see"
|
|
359
372
|
* concern, split out of runner.ts so the runner owns only lifecycle and the prompt owns only
|
|
360
373
|
* content. Returns null when the role has nothing to run this run (a director with an empty
|