tumwater 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +55 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +6 -4
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +404 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +281 -55
- package/dist/src/backlog/backlog-cli-view.js +255 -0
- package/dist/src/backlog/backlog-cli.js +91 -335
- package/dist/src/backlog/backlog-commit.js +20 -13
- package/dist/src/backlog/backlog-eligibility.js +193 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +264 -0
- package/dist/src/backlog/backlog-release.js +134 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-guardrails.js +136 -0
- package/dist/src/baseline/main-red.js +153 -36
- package/dist/src/baseline/main-watch.js +232 -0
- package/dist/src/brief/brief-edit.js +12 -12
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget-fallback-view.js +288 -0
- package/dist/src/budget/budget-wiring.js +158 -0
- package/dist/src/budget/budget.js +31 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +65 -3
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +181 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +183 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +291 -598
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-review-commands.js +113 -0
- package/dist/src/cli/cli-role-command.js +525 -0
- package/dist/src/cli/cli-start-summary.js +167 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +193 -237
- package/dist/src/cli/completion.js +169 -22
- package/dist/src/cli/config-commands.js +58 -26
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +258 -82
- package/dist/src/cli/log-commands.js +164 -85
- package/dist/src/cli/question-commands.js +211 -10
- package/dist/src/cli.js +173 -45
- package/dist/src/collections.js +56 -13
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +16 -1
- package/dist/src/config/config-fallbacks.js +94 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +169 -222
- package/dist/src/config/config-views.js +136 -54
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +164 -265
- package/dist/src/config/config.js +53 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +330 -0
- package/dist/src/doctor/doctor-backlog-plans.js +398 -0
- package/dist/src/doctor/doctor-backlog.js +249 -512
- package/dist/src/doctor/doctor-check-names.js +85 -0
- package/dist/src/doctor/doctor-checks.js +61 -593
- package/dist/src/doctor/doctor-claude-checks.js +142 -0
- package/dist/src/doctor/doctor-codex-checks.js +276 -0
- package/dist/src/doctor/doctor-contention-checks.js +506 -0
- package/dist/src/doctor/doctor-fallback-checks.js +130 -0
- package/dist/src/doctor/doctor-holds.js +80 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +216 -537
- package/dist/src/doctor/doctor-notify.js +9 -5
- package/dist/src/doctor/doctor-opencode-checks.js +164 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-pi-checks.js +62 -0
- package/dist/src/doctor/doctor-project-checks.js +397 -0
- package/dist/src/doctor/doctor.js +126 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +21 -12
- package/dist/src/events/event-format.js +185 -89
- package/dist/src/events/event-labels.js +11 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +52 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +80 -26
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +65 -60
- package/dist/src/failure/failure-render.js +29 -21
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +35 -35
- package/dist/src/files/file-queue.js +17 -0
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +88 -225
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +101 -143
- package/dist/src/gates/maintenance-quota.js +37 -30
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +89 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +54 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +43 -19
- package/dist/src/gui/gui-backlog-endpoints.js +156 -0
- package/dist/src/gui/gui-command.js +26 -13
- package/dist/src/gui/gui-config-commands.js +168 -80
- package/dist/src/gui/gui-endpoint-commands.js +5 -4
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +235 -13
- package/dist/src/gui/gui-prompt-commands.js +26 -20
- package/dist/src/gui/gui-report-endpoints.js +97 -0
- package/dist/src/gui/gui-server.js +26 -5
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +155 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +190 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +28 -17
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +58 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +45 -19
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +214 -0
- package/dist/src/merge/merge-queue-render.js +48 -11
- package/dist/src/merge/merge-queue.js +52 -15
- package/dist/src/merge/merge-requeue.js +103 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +27 -11
- package/dist/src/merge/merge-to-main.js +77 -26
- package/dist/src/merge/merge-top.js +83 -0
- package/dist/src/merge/merge-verify.js +75 -18
- package/dist/src/notes-cli.js +35 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +352 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +71 -370
- package/dist/src/orchestrator/orchestrator.js +129 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +245 -0
- package/dist/src/orchestrator/scheduling-skip.js +195 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +126 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +26 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +150 -217
- package/dist/src/prompt/notes-backlog.js +184 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +131 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +188 -124
- package/dist/src/report/report-fold.js +130 -54
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +136 -65
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +23 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/diff-rules.js +53 -0
- package/dist/src/review/known-flakes.js +112 -1
- package/dist/src/review/post-merge-review-accept.js +51 -0
- package/dist/src/review/post-merge-review-render.js +112 -0
- package/dist/src/review/post-merge-review.js +239 -0
- package/dist/src/review/protected-edits.js +24 -10
- package/dist/src/review/quarantine-render.js +65 -0
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +180 -401
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +127 -12
- package/dist/src/roles/role-guidance.js +65 -20
- package/dist/src/roles/role-labels.js +7 -5
- package/dist/src/roles/role-render.js +108 -56
- package/dist/src/roles/role-view.js +95 -56
- package/dist/src/roles/roles.js +33 -33
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/ci-parity.js +121 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/run/qa-coverage.js +125 -0
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +175 -0
- package/dist/src/run/run-detail-render.js +91 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +73 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +122 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +170 -83
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +105 -57
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +178 -0
- package/dist/src/run/stage-checks-shared.js +65 -0
- package/dist/src/run/stage-name-checks.js +204 -0
- package/dist/src/run/stage-path-checks.js +231 -0
- package/dist/src/run/stage-prose-checks.js +261 -0
- package/dist/src/runner/leftover.js +216 -0
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +191 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +109 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +39 -18
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +236 -245
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +103 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claim-entries.js +49 -0
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +49 -17
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +43 -28
- package/dist/src/status/status-roles.js +50 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +7 -8
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +65 -18
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +60 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +78 -13
- package/dist/src/ui/badges.js +99 -38
- package/dist/src/ui/gui/gui-client-backlog.js +314 -0
- package/dist/src/ui/gui/gui-client-boot.js +89 -61
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +254 -0
- package/dist/src/ui/gui/gui-client-drawer.js +155 -289
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +437 -68
- package/dist/src/ui/gui/gui-client-labels.js +6 -3
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +60 -52
- package/dist/src/ui/gui/gui-client-pending.js +405 -24
- package/dist/src/ui/gui/gui-client-report-chart.js +492 -0
- package/dist/src/ui/gui/gui-client-report.js +105 -430
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +163 -5
- package/dist/src/ui/gui/gui-client-team.js +36 -465
- package/dist/src/ui/gui/gui-client.js +38 -26
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +10 -7
- package/dist/src/ui/gui/gui-styles.js +38 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +33 -32
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +364 -49
- package/dist/src/ui/status-render.js +109 -82
- package/dist/src/ui/team-alerts.js +728 -62
- package/dist/src/ui/tone.js +12 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +53 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +4 -12
- package/dist/src/ui/tui/tui-editor-backends.js +127 -0
- package/dist/src/ui/tui/tui-editor-brief.js +14 -36
- package/dist/src/ui/tui/tui-editor-budget.js +36 -39
- package/dist/src/ui/tui/tui-editor-check.js +29 -0
- package/dist/src/ui/tui/tui-editor-checks.js +28 -0
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +25 -0
- package/dist/src/ui/tui/tui-editor-config.js +99 -0
- package/dist/src/ui/tui/tui-editor-entry.js +39 -64
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +46 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +117 -0
- package/dist/src/ui/tui/tui-editor-interval.js +29 -16
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +9 -29
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +95 -41
- package/dist/src/ui/tui/tui-editor-retire.js +5 -13
- package/dist/src/ui/tui/tui-editor-role-enabled.js +126 -0
- package/dist/src/ui/tui/tui-editor-role-key.js +71 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +101 -34
- package/dist/src/ui/tui/tui-editor-slots.js +24 -0
- package/dist/src/ui/tui/tui-editors.js +44 -2
- package/dist/src/ui/tui/tui-frame.js +68 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +33 -9
- package/dist/src/ui/tui/tui-pane-activity.js +35 -19
- package/dist/src/ui/tui/tui-pane-backlog.js +198 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +168 -8
- package/dist/src/ui/tui/tui-pane-history.js +446 -82
- package/dist/src/ui/tui/tui-pane-pending.js +539 -15
- package/dist/src/ui/tui/tui-pane-queued.js +78 -57
- package/dist/src/ui/tui/tui-pane-report.js +54 -16
- package/dist/src/ui/tui/tui-pane-session.js +34 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +91 -28
- package/dist/src/ui/tui/tui-panes.js +153 -34
- package/dist/src/ui/tui/tui.js +18 -15
- package/dist/src/verdict/fix-claim.js +129 -33
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +77 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/leftover.js +0 -130
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/qa-coverage.js +0 -108
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,21 +1,26 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { fail, say, sayJsonLine } from "./cli-output.js";
|
|
3
|
-
import {
|
|
2
|
+
import { hasFollowFlag, LOGS_TRANSCRIPT_VALUE_ERROR } from "./cli-flag-specs.js";
|
|
3
|
+
import { durationLabel, failRivalShapes, failUntilShorterThanSince, flagValue, parseCountFlag, parseGrepFlag, parseRoleListScope, parseRoleScope, parseSinceFlag, parseTypeFlag } from "./cli-args.js";
|
|
4
4
|
import { LOGS_SINCE_MAX_MS, readEventsSince, SPARSE_WINDOW_NOTE, } from "../events/event-window.js";
|
|
5
|
-
import { compareCodeUnits, increment
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { compareCodeUnits, increment } from "../collections.js";
|
|
6
|
+
import { eventTypeTally } from "../events/event-tally.js";
|
|
7
|
+
import { eventRole, parseEventLine, readEventsTailWithEnd } from "../events/event-read.js";
|
|
8
|
+
import { eventMatchesGrep, eventResult, formatEvent } from "../events/event-format.js";
|
|
8
9
|
import { canonicalEventType } from "../events/event-legacy.js";
|
|
9
10
|
import { EVENT_TYPE_LABELS, eventTypeLabel } from "../events/event-labels.js";
|
|
10
11
|
import { followFile } from "../files/tail.js";
|
|
12
|
+
import { roleInScope } from "../roles/runner-ids.js";
|
|
13
|
+
import { startParentDeathWatch } from "../process/supervisor.js";
|
|
11
14
|
import { typoSuffix } from "../text/suggest.js";
|
|
12
|
-
import {
|
|
15
|
+
import { splitCommaList } from "../text/text.js";
|
|
16
|
+
import { createTranscriptFilter, createTranscriptRenderer } from "../ui/transcript.js";
|
|
13
17
|
import { readTranscriptTail } from "../ui/transcript-tail.js";
|
|
18
|
+
import { isNotableEvent } from "../ui/tone.js";
|
|
14
19
|
import { eventsLogPath, piLogPath } from "../paths.js";
|
|
15
20
|
/** The read-only observing half of the CLI's non-dispatch commands: `tumwater logs` and its
|
|
16
|
-
* `--
|
|
21
|
+
* `--transcript` view, split out of cli.ts so the entry point stays a dispatch table. Unlike
|
|
17
22
|
* operator/operator-commands.ts these write nothing but stdout — they only read the event log and
|
|
18
|
-
* each
|
|
23
|
+
* each role's agent transcript. It lives beside the other CLI command bodies (history.ts,
|
|
19
24
|
* cli/cli-query-commands.ts, operator/operator-commands.ts), which may import the ui/ rendering
|
|
20
25
|
* layer they drive — here the event formatter and the transcript renderer — while src/ui/
|
|
21
26
|
* itself stays off src/ module boundaries it does not own. */
|
|
@@ -36,28 +41,30 @@ function sayEventLine(e, json) {
|
|
|
36
41
|
* In `--json` mode it emits one compact object mapping `type → count` with keys sorted, the
|
|
37
42
|
* machine-readable twin of the prose tally. */
|
|
38
43
|
function sayTally(events, json) {
|
|
39
|
-
const counts = new Map();
|
|
40
|
-
for (const e of events)
|
|
41
|
-
increment(counts, e.type);
|
|
42
44
|
if (json) {
|
|
45
|
+
// The machine-readable twin keeps its own alphabetical key sort; the prose tally uses the
|
|
46
|
+
// shared eventTypeTally ordering.
|
|
47
|
+
const counts = new Map();
|
|
48
|
+
for (const e of events)
|
|
49
|
+
increment(counts, e.type);
|
|
43
50
|
const obj = {};
|
|
44
51
|
for (const [type] of [...counts.entries()].sort((a, b) => compareCodeUnits(a[0], b[0])))
|
|
45
52
|
obj[type] = counts.get(type);
|
|
46
53
|
sayJsonLine(obj);
|
|
47
54
|
return;
|
|
48
55
|
}
|
|
49
|
-
for (const [type, n] of
|
|
56
|
+
for (const [type, n] of eventTypeTally(events))
|
|
50
57
|
say(`${n} × ${eventTypeLabel(type)} (${type})`);
|
|
51
58
|
}
|
|
52
59
|
/** The shared rival-shape guard for logs flags that only apply to the event-log feed:
|
|
53
|
-
* `--
|
|
54
|
-
* it is excluded with it), so each such flag fails naming both. One wording
|
|
55
|
-
* the --json, --
|
|
56
|
-
* is the flag's own presence
|
|
57
|
-
*
|
|
58
|
-
function
|
|
59
|
-
if (active && (rest.includes("--
|
|
60
|
-
failRivalShapes(`logs ${flag}`, "--
|
|
60
|
+
* `--transcript` swaps in a transcript rather than the event log (--prompt requires
|
|
61
|
+
* --transcript, so it is excluded with it), so each such flag fails naming both. One wording
|
|
62
|
+
* for all of them — the --json, --count, --type and --since checks cannot drift apart in what
|
|
63
|
+
* they say or why. `active` is the flag's own presence. --grep is not one of them: it also
|
|
64
|
+
* filters the transcript view. */
|
|
65
|
+
function rejectTranscriptViewRival(rest, flag, active) {
|
|
66
|
+
if (active && (rest.includes("--transcript") || rest.includes("--prompt")))
|
|
67
|
+
failRivalShapes(`logs ${flag}`, "--transcript", "the --transcript view is the role's agent transcript, not the event log; --prompt requires --transcript");
|
|
61
68
|
}
|
|
62
69
|
/** The missing-pattern error cmdLogs prints for a valueless `--grep`, exported so cli.ts's
|
|
63
70
|
* rejectUnknownArgs spec for --grep can fail a trailing `logs --grep` with the same wording
|
|
@@ -73,97 +80,148 @@ export const TYPE_VALUE_ERROR = "logs --type needs an event type";
|
|
|
73
80
|
* completion already offers the valid codes, so a bare no-match for a near-miss reads as a silent
|
|
74
81
|
* mystery) — while a VALID type that merely has no matching events stays hint-free, a legitimate
|
|
75
82
|
* empty result rather than a typo. A valid type or a legacy alias (canonicalEventType maps the
|
|
76
|
-
* alias onto the current code, which is a label key) never hints.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
: typoSuffix(type, Object.keys(EVENT_TYPE_LABELS));
|
|
83
|
+
* alias onto the current code, which is a label key) never hints. For a comma list the hint
|
|
84
|
+
* is for the first piece that is not a valid type; the prose names the value as typed. */
|
|
85
|
+
function typeEmpty(type, pieces) {
|
|
86
|
+
const bad = pieces.find((p) => !Object.hasOwn(EVENT_TYPE_LABELS, canonicalEventType(p)));
|
|
87
|
+
const hint = bad === undefined ? "" : typoSuffix(bad, Object.keys(EVENT_TYPE_LABELS));
|
|
82
88
|
return `no events matching "${type}"${hint}`;
|
|
83
89
|
}
|
|
84
|
-
/** `
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
/** Follow `file` until Ctrl+C or until the process that started this one is gone (the shape of
|
|
91
|
+
* a `logs -f` leaked to PPID 1 that polled for days). Resolves once the parent is gone. */
|
|
92
|
+
export function followUntilParentGone(file, offset, onLines, seams) {
|
|
93
|
+
const stop = followFile(file, offset, onLines);
|
|
94
|
+
return new Promise((resolve) => {
|
|
95
|
+
startParentDeathWatch(() => {
|
|
96
|
+
stop();
|
|
97
|
+
resolve();
|
|
98
|
+
}, {
|
|
99
|
+
...(seams.ppid ? { ppid: seams.ppid } : {}),
|
|
100
|
+
...(seams.intervalMs !== undefined ? { intervalMs: seams.intervalMs } : {}),
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/** `tumwater logs [-f] [-n <count>] [--since <duration>] [--until <duration>]
|
|
105
|
+
* [--role <id>[,<id>...]] [--transcript <id>] [--prompt]
|
|
106
|
+
* [--grep <text>]`: follow or dump the harness event log, with `--since` a bounded
|
|
107
|
+
* past window of it and `--role` keeping only the listed roles' events (a base role id takes its
|
|
108
|
+
* instances too),
|
|
109
|
+
* or with `--transcript` one role's agent transcript (see cmdLogsTranscript). `-f` follows until
|
|
110
|
+
* Ctrl+C or until its parent process exits. */
|
|
111
|
+
export async function cmdLogs(root, args, seams = {}) {
|
|
112
|
+
// `--grep <text>` filters the event feed (the -n view and its follow) and, with --transcript,
|
|
113
|
+
// the transcript's entries (see cmdLogsTranscript): case-insensitive
|
|
89
114
|
// substring against `${e.type} ${formatEvent(e)}` — the rendered line is what the operator
|
|
90
115
|
// would otherwise read (WYSIWYG), and prefixing the raw type id lets stable ids
|
|
91
116
|
// (review_rejected, merge_failed) be filtered even where the rendering paraphrases them.
|
|
92
|
-
//
|
|
93
|
-
// (--prompt requires --role, so it is excluded with it), and --since is a filter of its own
|
|
94
|
-
// rather than a window to filter — and each failure names both flags. The flag scan itself
|
|
117
|
+
// --grep filters the --since window like --type and --role do. The flag scan itself
|
|
95
118
|
// (the value lookup, the `rest` construction that keeps a flag-shaped pattern from
|
|
96
119
|
// impersonating a rival flag, and the empty-value fail) is cli/cli-args.ts's parseGrepFlag,
|
|
97
120
|
// the one home shared with history's identical preamble.
|
|
98
121
|
const { rest: grepped, pattern: grepPattern } = parseGrepFlag(args, GREP_VALUE_ERROR);
|
|
99
122
|
// `--type <eventType>` filters the event feed by EXACT event type (e.type === value):
|
|
100
123
|
// deterministic where --grep substrings — a merge_failed whose rendered line quotes
|
|
101
|
-
// "merge_failed" matches --grep but not --type.
|
|
102
|
-
// (the window
|
|
103
|
-
// it is a rival only of the --
|
|
124
|
+
// "merge_failed" matches --grep but not --type. It composes with --since
|
|
125
|
+
// (the window it filters) as well as -n, -f, --json, and --grep; like --json
|
|
126
|
+
// it is a rival only of the --transcript/--prompt transcript view. A comma list matches any
|
|
127
|
+
// of its types. The value scan (keeping a
|
|
104
128
|
// flag-shaped value like --since as text, the empty-value fail) mirrors parseGrepFlag via
|
|
105
129
|
// parseTypeFlag, so the two cannot drift; `rest` here has both flags' value tokens removed.
|
|
106
130
|
const { rest, type } = parseTypeFlag(grepped, TYPE_VALUE_ERROR);
|
|
107
131
|
const grepLower = grepPattern === null ? null : grepPattern.toLowerCase();
|
|
108
132
|
// An older event name matches its current one; the empty-match prose still names what was typed.
|
|
109
|
-
const
|
|
110
|
-
|
|
133
|
+
const typePieces = type === null ? [] : splitCommaList(type);
|
|
134
|
+
if (type !== null && typePieces.length === 0)
|
|
135
|
+
fail(TYPE_VALUE_ERROR);
|
|
136
|
+
const wantedTypes = new Set(typePieces.map(canonicalEventType));
|
|
137
|
+
const typeFilter = type === null ? null : (e) => wantedTypes.has(e.type);
|
|
111
138
|
// The composed feed rule every emit site threads today's grep-only predicate through:
|
|
112
139
|
// an event passes when it is absent-or-matches the --grep substring AND absent-or-equals
|
|
113
140
|
// the --type id, held in one place so the --since window, the -n tally, and the follow
|
|
114
141
|
// cannot drift on what an event must satisfy.
|
|
142
|
+
// `--role <id>[,<id>...]` joins them: an event passes when the role it was filed under, or
|
|
143
|
+
// that role's base id (so `--role feature` takes `feature-2` too), is listed. It
|
|
144
|
+
// composes with --since. The value scan reads `rest`, which holds no --grep/--type value tokens.
|
|
145
|
+
const roles = parseRoleListScope(root, rest);
|
|
146
|
+
const roleFilter = roles === null
|
|
147
|
+
? null
|
|
148
|
+
: (e) => roleInScope(eventRole(e), roles);
|
|
149
|
+
if (roles !== null)
|
|
150
|
+
rejectTranscriptViewRival(rest, "--role", true);
|
|
151
|
+
// `--notable` culls routine bookkeeping events the way the dashboard Activity feed's Notable
|
|
152
|
+
// choice does (src/ui/tone.ts eventKind): only non-routine rows pass the feed. One harness-side
|
|
153
|
+
// rule (isNotableEvent) shared with the TUI Activity pane, so the CLI feed and the pane cannot
|
|
154
|
+
// disagree about what a notable filter hides. It composes with --since, --grep, --type, --role,
|
|
155
|
+
// -n, -f, --count and --json, and — like --json/--count/--type/--since — is a rival only of the
|
|
156
|
+
// --transcript transcript view.
|
|
157
|
+
const notable = rest.includes("--notable");
|
|
158
|
+
rejectTranscriptViewRival(rest, "--notable", notable);
|
|
115
159
|
const feedFilter = (e) => (grepLower === null || eventMatchesGrep(e, grepLower)) &&
|
|
116
|
-
(typeFilter === null || typeFilter(e))
|
|
117
|
-
|
|
160
|
+
(typeFilter === null || typeFilter(e)) &&
|
|
161
|
+
(roleFilter === null || roleFilter(e)) &&
|
|
162
|
+
(!notable || isNotableEvent(e.type, eventResult(e)));
|
|
163
|
+
// Empty-match prose: grep/type keep their wording when given; a role-only filter names the roles.
|
|
164
|
+
const roleEmpty = roles === null ? "" : `no events from ${roles.join(", ")}`;
|
|
165
|
+
const filtersGrepOrType = grepPattern !== null || type !== null;
|
|
166
|
+
const follow = hasFollowFlag(rest);
|
|
118
167
|
// `--json` switches the feed from formatEvent rendering to one JSON.stringify(e) per line —
|
|
119
168
|
// the raw HarnessEvent objects exactly as stored in the log — so scripts read the canonical
|
|
120
169
|
// schema instead of parsing a rendering that changes shape whenever the formatter evolves.
|
|
121
170
|
// It composes with -n, --grep, --since and -f (the grep filter applies before serialization,
|
|
122
|
-
// the follow streams JSON lines as events land), but not with --
|
|
123
|
-
// transcript of human-oriented prose, not the event log (--prompt requires --
|
|
171
|
+
// the follow streams JSON lines as events land), but not with --transcript: that view is a pi
|
|
172
|
+
// transcript of human-oriented prose, not the event log (--prompt requires --transcript, so it is
|
|
124
173
|
// excluded with it).
|
|
125
174
|
const json = rest.includes("--json");
|
|
126
|
-
|
|
175
|
+
rejectTranscriptViewRival(rest, "--json", json);
|
|
127
176
|
// `--count` tallies the window's present event types instead of printing the rows. Rival
|
|
128
177
|
// shapes stay exclusive: counting implies a bounded window (so -f/--follow is rejected)
|
|
129
|
-
// and the --
|
|
178
|
+
// and the --transcript view is the role's agent transcript rather than the event log.
|
|
130
179
|
const count = rest.includes("--count");
|
|
131
|
-
|
|
180
|
+
rejectTranscriptViewRival(rest, "--count", count);
|
|
132
181
|
if (count && follow)
|
|
133
182
|
failRivalShapes("logs --count", "-f/--follow", "counting implies a bounded window; -f follows from now on");
|
|
134
183
|
if (type !== null)
|
|
135
|
-
|
|
136
|
-
if (grepPattern !== null) {
|
|
137
|
-
rejectRoleViewRival(rest, "--grep", true);
|
|
138
|
-
if (rest.includes("--since"))
|
|
139
|
-
failRivalShapes("logs --grep", "--since", "--since is a filter of its own; --grep filters the -n view and its follow");
|
|
140
|
-
}
|
|
184
|
+
rejectTranscriptViewRival(rest, "--type", true);
|
|
141
185
|
// `--since <duration>` is the window-shaped view over the same event log the -n view dumps:
|
|
142
186
|
// it reads a bounded past window (event-window.ts's day-keyed backwards scan) and prints the
|
|
143
187
|
// survivors oldest-first, so an operator can ask for "the hour around that 429 storm" without
|
|
144
188
|
// guessing a count. Rival shapes stay exclusive — follow means "from now on", -n means "last
|
|
145
|
-
// N", and --
|
|
146
|
-
// both flags. (--prompt requires --
|
|
189
|
+
// N", and --transcript swaps in a transcript rather than this log — and each failure names
|
|
190
|
+
// both flags. (--prompt requires --transcript, so it is excluded with it.)
|
|
147
191
|
const ms = parseSinceFlag(rest, "logs --since", LOGS_SINCE_MAX_MS);
|
|
192
|
+
const untilMs = parseSinceFlag(rest, "logs --until", LOGS_SINCE_MAX_MS, "--until");
|
|
193
|
+
failUntilShorterThanSince("logs", untilMs, ms);
|
|
148
194
|
if (ms !== null) {
|
|
149
195
|
if (follow)
|
|
150
196
|
failRivalShapes("logs --since", "-f/--follow", 'follow means "from now on"; --since shows a bounded past window');
|
|
151
197
|
if (rest.includes("-n"))
|
|
152
198
|
failRivalShapes("logs --since", "-n", "a count and a window are rival shapes");
|
|
153
|
-
|
|
199
|
+
rejectTranscriptViewRival(rest, "--since", true);
|
|
154
200
|
// covered is only consulted below when the window has rows (an empty window returns
|
|
155
201
|
// earlier), so the helper's vacuous empty-log branch never reaches the note here.
|
|
156
|
-
const { events, covered } = readEventsSince(root, ms);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
//
|
|
202
|
+
const { cutoff, events: windowEvents, covered } = readEventsSince(root, ms);
|
|
203
|
+
const events = untilMs === null ? windowEvents : windowEvents.filter((e) => e.ts < cutoff + ms - untilMs);
|
|
204
|
+
const windowPhrase = untilMs === null ? `in ${durationLabel(ms)}` : `between ${durationLabel(ms)} and ${durationLabel(untilMs)} ago`;
|
|
205
|
+
// `--grep`, `--type` and `--role` all filter the window through feedFilter: only the
|
|
206
|
+
// window events that pass are printed, and an all-filtered window answers with the
|
|
207
|
+
// no-match prose (the filter's own line) instead of the generic empty-window one —
|
|
160
208
|
// "which merge_failed in the last hour" filters the same as it would the -n view.
|
|
161
|
-
const filtered =
|
|
209
|
+
const filtered = events.filter(feedFilter);
|
|
162
210
|
if (filtered.length === 0) {
|
|
163
211
|
// In JSON mode an empty result answers silently — an empty output IS the machine-readable
|
|
164
212
|
// answer, and prose would corrupt a consumer's NDJSON stream.
|
|
165
|
-
if (!json)
|
|
166
|
-
|
|
213
|
+
if (!json) {
|
|
214
|
+
if (notable && grepPattern === null && type === null && roles === null)
|
|
215
|
+
say(`no notable events ${windowPhrase}`);
|
|
216
|
+
else if (grepPattern !== null && type !== null)
|
|
217
|
+
say(`no events matching "${grepPattern}" or ${typeEmpty(type, typePieces)}`);
|
|
218
|
+
else if (type !== null)
|
|
219
|
+
say(typeEmpty(type, typePieces));
|
|
220
|
+
else if (grepPattern !== null)
|
|
221
|
+
say(`no events matching "${grepPattern}" ${windowPhrase}`);
|
|
222
|
+
else
|
|
223
|
+
say(roles !== null ? `${roleEmpty} ${windowPhrase}` : `no events ${windowPhrase}`);
|
|
224
|
+
}
|
|
167
225
|
return;
|
|
168
226
|
}
|
|
169
227
|
// `--count` composes with the window: the tally covers exactly the filtered window rows
|
|
@@ -187,14 +245,14 @@ export async function cmdLogs(root, args) {
|
|
|
187
245
|
}
|
|
188
246
|
const nRaw = flagValue(rest, "-n");
|
|
189
247
|
const limit = nRaw !== null ? parseCountFlag("-n", nRaw) : 50;
|
|
190
|
-
// The event feed (no --
|
|
248
|
+
// The event feed (no --transcript) never needs the config at all: parseRoleScope reads it only
|
|
191
249
|
// when the flag is present.
|
|
192
|
-
const role = parseRoleScope(root, rest);
|
|
250
|
+
const role = parseRoleScope(root, rest, "--transcript", LOGS_TRANSCRIPT_VALUE_ERROR);
|
|
193
251
|
const showPrompts = rest.includes("--prompt");
|
|
194
252
|
if (showPrompts && role === null)
|
|
195
|
-
fail("logs --prompt needs --
|
|
253
|
+
fail("logs --prompt needs --transcript <id>");
|
|
196
254
|
if (role !== null) {
|
|
197
|
-
await cmdLogsTranscript(root, role, limit, follow, showPrompts);
|
|
255
|
+
await cmdLogsTranscript(root, role, limit, follow, showPrompts, grepLower, grepPattern, seams);
|
|
198
256
|
return;
|
|
199
257
|
}
|
|
200
258
|
// -n bounds the scan, not the print: the matched subset of the last `limit` events is what
|
|
@@ -202,7 +260,7 @@ export async function cmdLogs(root, args) {
|
|
|
202
260
|
// the tail-with-end shape (not the per-poll cached readEvents) so the follow below can seed
|
|
203
261
|
// from the byte end this very read covered instead of a later stat of the file.
|
|
204
262
|
const tail = readEventsTailWithEnd(root, limit);
|
|
205
|
-
const shown = grepLower !== null || type !== null ? tail.events.filter(feedFilter) : tail.events;
|
|
263
|
+
const shown = grepLower !== null || type !== null || roleFilter !== null || notable ? tail.events.filter(feedFilter) : tail.events;
|
|
206
264
|
// `--count` over the -n view answers with the tally of exactly the filtered rows the plain
|
|
207
265
|
// view would print, and carries over the plain view's empty-match prose below (a `--type`
|
|
208
266
|
// or `--grep` that matches nothing names its value; an empty unfiltered -n view prints
|
|
@@ -210,13 +268,17 @@ export async function cmdLogs(root, args) {
|
|
|
210
268
|
if (count) {
|
|
211
269
|
if (shown.length !== 0)
|
|
212
270
|
sayTally(shown, json);
|
|
213
|
-
else if (!json && (
|
|
214
|
-
if (grepPattern
|
|
215
|
-
say(
|
|
271
|
+
else if (!json && (filtersGrepOrType || roles !== null || notable)) {
|
|
272
|
+
if (notable && grepPattern === null && type === null && roles === null)
|
|
273
|
+
say("no notable events");
|
|
274
|
+
else if (grepPattern !== null && type !== null)
|
|
275
|
+
say(`no events matching "${grepPattern}" or ${typeEmpty(type, typePieces)}`);
|
|
216
276
|
// Type-empty gets the hint (only the type branch); a grep-only empty stays the bare
|
|
217
277
|
// no-match line, because a free-text pattern is not an event type to suggest against.
|
|
278
|
+
else if (!filtersGrepOrType)
|
|
279
|
+
say(roleEmpty);
|
|
218
280
|
else
|
|
219
|
-
say(type !== null ? typeEmpty(type) : `no events matching "${grepPattern ?? ""}"`);
|
|
281
|
+
say(type !== null ? typeEmpty(type, typePieces) : `no events matching "${grepPattern ?? ""}"`);
|
|
220
282
|
}
|
|
221
283
|
return;
|
|
222
284
|
}
|
|
@@ -226,13 +288,17 @@ export async function cmdLogs(root, args) {
|
|
|
226
288
|
// The empty-match line is prose: in JSON mode the empty output is the answer. It fires
|
|
227
289
|
// for either filter, naming the flag's value(s) whose match came up empty so the operator
|
|
228
290
|
// knows what to loosen.
|
|
229
|
-
if (shown.length === 0 && !json && (
|
|
230
|
-
if (grepPattern
|
|
231
|
-
say(
|
|
291
|
+
if (shown.length === 0 && !json && (filtersGrepOrType || roles !== null || notable)) {
|
|
292
|
+
if (notable && grepPattern === null && type === null && roles === null)
|
|
293
|
+
say("no notable events");
|
|
294
|
+
else if (grepPattern !== null && type !== null)
|
|
295
|
+
say(`no events matching "${grepPattern}" or ${typeEmpty(type, typePieces)}`);
|
|
232
296
|
// Type-empty gets the hint (only the type branch); a grep-only empty stays the bare
|
|
233
297
|
// no-match line, because a free-text pattern is not an event type to suggest against.
|
|
298
|
+
else if (!filtersGrepOrType)
|
|
299
|
+
say(roleEmpty);
|
|
234
300
|
else
|
|
235
|
-
say(type !== null ? typeEmpty(type) : `no events matching "${grepPattern ?? ""}"`);
|
|
301
|
+
say(type !== null ? typeEmpty(type, typePieces) : `no events matching "${grepPattern ?? ""}"`);
|
|
236
302
|
}
|
|
237
303
|
return;
|
|
238
304
|
}
|
|
@@ -245,7 +311,7 @@ export async function cmdLogs(root, args) {
|
|
|
245
311
|
// log scans to coveredEnd 0, and followFile tolerates a missing file (its poll re-stats
|
|
246
312
|
// every interval), so a read-only command never leaves a harness state file behind — the
|
|
247
313
|
// module contract above promises writes to stdout only.
|
|
248
|
-
|
|
314
|
+
await followUntilParentGone(file, tail.coveredEnd, (lines) => {
|
|
249
315
|
for (const line of lines.filter(Boolean)) {
|
|
250
316
|
const e = parseEventLine(line);
|
|
251
317
|
// The filter holds across rotation: every event the follow callback sees goes through
|
|
@@ -253,19 +319,31 @@ export async function cmdLogs(root, args) {
|
|
|
253
319
|
if (e && feedFilter(e))
|
|
254
320
|
sayEventLine(e, json);
|
|
255
321
|
}
|
|
256
|
-
});
|
|
257
|
-
await new Promise(() => { }); // Follow until Ctrl+C.
|
|
322
|
+
}, seams);
|
|
258
323
|
}
|
|
259
|
-
/** `tumwater logs --
|
|
324
|
+
/** `tumwater logs --transcript <id>`: print (and optionally follow) one role's agent transcript —
|
|
260
325
|
* run separators, abbreviated thinking, assistant text, and tool calls; with `--prompt` also
|
|
261
326
|
* each run's exact prompt text. Read-only; the raw log is pi's streaming event stream, so only
|
|
262
|
-
* complete renderable events are shown.
|
|
263
|
-
|
|
327
|
+
* complete renderable events are shown. With `--grep`, only entries with a rendered line
|
|
328
|
+
* containing the text (case-insensitively) print, each under its run's separator; `-n` still
|
|
329
|
+
* bounds the entries scanned, not printed. */
|
|
330
|
+
async function cmdLogsTranscript(root, role, limit, follow, showPrompts, needle, pattern, seams) {
|
|
264
331
|
const file = piLogPath(root, role);
|
|
265
332
|
const opts = { includePrompts: showPrompts };
|
|
333
|
+
const filter = needle === null ? null : createTranscriptFilter(needle);
|
|
334
|
+
let matched = 0;
|
|
266
335
|
const printEntry = (lines) => {
|
|
267
|
-
if (lines.length
|
|
336
|
+
if (lines.length === 0)
|
|
337
|
+
return;
|
|
338
|
+
if (filter === null) {
|
|
268
339
|
say(lines.join("\n"));
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const out = filter(lines);
|
|
343
|
+
if (out === null)
|
|
344
|
+
return;
|
|
345
|
+
matched++;
|
|
346
|
+
say(out.join("\n"));
|
|
269
347
|
};
|
|
270
348
|
// Initial window: the last `limit` entries of what is on disk. readTranscriptTail scans back
|
|
271
349
|
// from EOF only as far as needed instead of re-reading the whole (up to logMaxBytes) file,
|
|
@@ -280,6 +358,8 @@ async function cmdLogsTranscript(root, role, limit, follow, showPrompts) {
|
|
|
280
358
|
for (const entry of tail.entries)
|
|
281
359
|
printEntry(entry);
|
|
282
360
|
offset = tail.end;
|
|
361
|
+
if (needle !== null && matched === 0)
|
|
362
|
+
say(`no transcript entries matching "${pattern ?? ""}" for ${role}`);
|
|
283
363
|
}
|
|
284
364
|
if (!follow)
|
|
285
365
|
return;
|
|
@@ -288,9 +368,8 @@ async function cmdLogsTranscript(root, role, limit, follow, showPrompts) {
|
|
|
288
368
|
// readTranscriptTail's formatTranscript already flushed any pending separator for what
|
|
289
369
|
// was on disk.
|
|
290
370
|
const renderer = createTranscriptRenderer(opts);
|
|
291
|
-
|
|
371
|
+
await followUntilParentGone(file, offset, (lines) => {
|
|
292
372
|
for (const line of lines)
|
|
293
373
|
printEntry(renderer.feed(line));
|
|
294
|
-
});
|
|
295
|
-
await new Promise(() => { }); // Follow until Ctrl+C.
|
|
374
|
+
}, seams);
|
|
296
375
|
}
|