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,7 +1,6 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Local date/time formatting and calendar-day arithmetic — the zero-padded clock and
|
|
3
2
|
* calendar parts, local-midnight day math, and the report-window header every display and
|
|
4
|
-
* report surface (transcript run separators, the status table's last-
|
|
3
|
+
* report surface (transcript run separators, the status table's last-run cell, daily-budget
|
|
5
4
|
* day stamps, the usage report's and failure digest's per-day buckets and headers) render
|
|
6
5
|
* through, so what counts as one day and how a timestamp prints cannot drift per consumer.
|
|
7
6
|
* Split out of text.ts — which keeps the one-line text shaping — because calendar
|
|
@@ -9,14 +8,28 @@
|
|
|
9
8
|
* string cutting, with its own tests. Presentation only: depends on node built-ins alone. */
|
|
10
9
|
import { plural } from "./phrases.js";
|
|
11
10
|
import { EVENTS_LOG_BASENAME } from "../paths.js";
|
|
11
|
+
/** Milliseconds in an hour — the shared unit for this repo's window and timeout
|
|
12
|
+
* constants (reclaim's idle threshold, the doctor's merge/stale-pin/wait checks, the
|
|
13
|
+
* claim/review/queue expiry, the scheduling defer cap, redeploy's cooldowns, the
|
|
14
|
+
* provider-hold window), so no two of them can spell the hour multiplier differently
|
|
15
|
+
* (`60 * 60 * 1000` vs `60 * 60_000` vs `3600_000`). Day-sized spans use `DAY_MS`
|
|
16
|
+
* (or `N * DAY_MS`) below. */
|
|
17
|
+
export const HOUR_MS = 60 * 60 * 1000;
|
|
18
|
+
/** Milliseconds in a day — the sibling of `HOUR_MS`: the shared day unit for the
|
|
19
|
+
* day-sized retention and lookback constants (the opencode-catalog and image-probe TTLs,
|
|
20
|
+
* the doctor's stale-pin/merge/prompt/wait checks, the known-flake and selfcheck
|
|
21
|
+
* windows, the dashboard-history since bound, the retention prune, the claude-window
|
|
22
|
+
* lookback) so one day cannot mean slightly different spans per consumer. */
|
|
23
|
+
export const DAY_MS = 24 * HOUR_MS;
|
|
12
24
|
/** Zero-pad an integer to two digits — the clock and calendar components every local-time
|
|
13
25
|
* display in the harness renders through (transcript run separators, the status table's last-
|
|
14
|
-
*
|
|
26
|
+
* run cell, the daily-budget day stamp), so zero-padding cannot drift per consumer. */
|
|
15
27
|
export function pad2(n) {
|
|
16
28
|
return String(n).padStart(2, "0");
|
|
17
29
|
}
|
|
18
30
|
/** The local wall-clock `HH:MM` of an instant, the hours/minutes-only shape the burn-rate
|
|
19
|
-
* forecast, the window badge,
|
|
31
|
+
* forecast, the window badge, the role view's fallback line, and the failure digest's
|
|
32
|
+
* transition stamps (failure-render.ts's stateChangeStamp) share. */
|
|
20
33
|
export function clockHm(ms) {
|
|
21
34
|
const d = new Date(ms);
|
|
22
35
|
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
@@ -25,7 +38,7 @@ export function clockHm(ms) {
|
|
|
25
38
|
* clamps at zero (an age never goes negative when the clock skews), `secondsUntil` clamps at
|
|
26
39
|
* zero the same way for the future direction (a countdown never reads negative once its
|
|
27
40
|
* deadline has passed). The one home of the clamp + rounding behind every elapsed age and
|
|
28
|
-
* countdown — status-render.ts's
|
|
41
|
+
* countdown — status-render.ts's lastRunCell and nextRunCell, the queued-prompt age and
|
|
29
42
|
* deliver-in suffix, the team pause's auto-resume countdown, and status-model.ts's sleeping
|
|
30
43
|
* phase label (which re-floors at 1s) all render through. The GUI page's browser
|
|
31
44
|
* script keeps its own one-line twins (gui-client.ts's ageSec and its inline countdown
|
|
@@ -39,12 +52,6 @@ export function secondsSince(sinceMs, now) {
|
|
|
39
52
|
export function secondsUntil(atMs, now) {
|
|
40
53
|
return Math.max(0, Math.round((atMs - now) / 1000));
|
|
41
54
|
}
|
|
42
|
-
/** Whole elapsed seconds since an epoch-ms instant, clamped at zero and rounded to the
|
|
43
|
-
* nearest second — the age rule status-render.ts's lastTickCell ages its `HH:MM:SS · Ns ago`
|
|
44
|
-
* stamp through (secondsSince against the real clock). */
|
|
45
|
-
export function elapsedSeconds(sinceMs) {
|
|
46
|
-
return secondsSince(sinceMs, Date.now());
|
|
47
|
-
}
|
|
48
55
|
/** Calendar date as `YYYY-MM-DD` in local time — shared by the transcript run separators,
|
|
49
56
|
* the daily-budget day stamp (todayStamp), and the usage report's per-day buckets, which must
|
|
50
57
|
* all agree on what counts as one day. */
|
|
@@ -52,13 +59,23 @@ export function formatDate(d) {
|
|
|
52
59
|
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
|
53
60
|
}
|
|
54
61
|
/** Wall-clock time as zero-padded `HH:MM:SS` in local time — the clock half formatTimestamp
|
|
55
|
-
* builds, and the direct rendering of the status table's last-
|
|
56
|
-
*
|
|
62
|
+
* builds, and the direct rendering of the status table's last-run cell (status-render.ts's
|
|
63
|
+
* lastRunCell), doctor-project-checks's probe-at stamp, and
|
|
57
64
|
* operator-intent's pause/deadline wording, so a local time of day reads the same shape at
|
|
58
65
|
* every surface. */
|
|
59
66
|
export function formatTime(d) {
|
|
60
67
|
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`;
|
|
61
68
|
}
|
|
69
|
+
/** Epoch ms as a local `HH:MM:SS` wall-clock string — the epoch-ms form of formatTime, the
|
|
70
|
+
* dayKey-to-formatDate sibling. It shares the clock-instant rendering every event renderer's
|
|
71
|
+
* pause/reset/resume suffix needs (event-format.ts's pauseSuffix and windowResetPhrase,
|
|
72
|
+
* failure-state-change.ts's team/role pause untils, doctor-model-checks.ts's probe time), so no
|
|
73
|
+
* site re-derives `formatTime(new Date(ms))`. A non-finite or absent `ms` renders the same NaN
|
|
74
|
+
* clock formatTime's Date would — callers guard with finiteNumber first, exactly as they did
|
|
75
|
+
* before. */
|
|
76
|
+
export function formatClock(ms) {
|
|
77
|
+
return formatTime(new Date(ms));
|
|
78
|
+
}
|
|
62
79
|
/** Epoch ms as a local calendar-day key (`YYYY-MM-DD`) — the epoch-ms form of formatDate:
|
|
63
80
|
* the day-bucketing rule the event log's day key (eventDayKey), the windowed readers' window
|
|
64
81
|
* keys, the daily-budget stamp, and the failure digest's cluster dates all render through, so
|
|
@@ -89,7 +106,7 @@ export function monthDay(dayKey) {
|
|
|
89
106
|
* the transcript's run separators, the history table's time cell, and the review-gate prompt's
|
|
90
107
|
* rejection context, so a timestamp reads identically at every surface. A non-finite `ms` (a
|
|
91
108
|
* corrupt event `ts`, a Date.parse of a malformed ISO match) renders as the em dash — the same
|
|
92
|
-
* "no value" marker the history table uses for a
|
|
109
|
+
* "no value" marker the history table uses for a run with no reported duration, so a corrupt
|
|
93
110
|
* stamp reads as unknowable instead of printing `new Date(NaN)`'s `NaN-NaN-NaN NaN:NaN:NaN`
|
|
94
111
|
* through every surface that renders events or rows. */
|
|
95
112
|
export function formatTimestamp(ms) {
|
|
@@ -144,8 +161,33 @@ export function humanSeconds(s) {
|
|
|
144
161
|
export function humanUntil(atMs, now) {
|
|
145
162
|
return humanSeconds(secondsUntil(atMs, now));
|
|
146
163
|
}
|
|
147
|
-
/**
|
|
148
|
-
*
|
|
164
|
+
/** `humanUntil`'s past-direction twin: how long since an epoch-ms instant, as `NS ago` —
|
|
165
|
+
* the past-direction phrase five renderers each built as `{humanSeconds(secondsSince(...))} ago`
|
|
166
|
+
* (status-render.ts's ago against the real clock, role-render.ts's last-run and
|
|
167
|
+
* merge-queue-render.ts's enqueue ages, inbox.ts's queued-age suffix, and doctor-notify.ts's
|
|
168
|
+
* latest-failed-page age, which had inlined the clamp itself), so the clamp, the rounding,
|
|
169
|
+
* and the " ago" wording cannot drift per consumer. Lives here beside the other time
|
|
170
|
+
* phrasing so core modules (which may not import src/ui) share the same form. */
|
|
171
|
+
export function humanAgo(sinceMs, now) {
|
|
172
|
+
return `${humanSeconds(secondsSince(sinceMs, now))} ago`;
|
|
173
|
+
}
|
|
174
|
+
/** A compact age clamped at zero and floored to whole units — `12m`, `4h`, `6d` — the bare
|
|
175
|
+
* (no `ago`) parenthetical the `qa` coverage block and the `feedback` "previously filed" block
|
|
176
|
+
* render for each ledger entry, which each defined as their own local `formatAge`. Kept
|
|
177
|
+
* distinct from humanSeconds on purpose: this floors (a sub-minute age reads `0m`, never
|
|
178
|
+
* `Ns`) and skips the seconds bucket, so the two units/rounding rules cannot drift per
|
|
179
|
+
* consumer. Lives here beside the other time phrasing. */
|
|
180
|
+
export function formatAge(ms) {
|
|
181
|
+
const minutes = Math.max(0, Math.floor(ms / 60_000));
|
|
182
|
+
if (minutes < 60)
|
|
183
|
+
return `${minutes}m`;
|
|
184
|
+
const hours = Math.floor(minutes / 60);
|
|
185
|
+
if (hours < 24)
|
|
186
|
+
return `${hours}h`;
|
|
187
|
+
return `${Math.floor(hours / 24)}d`;
|
|
188
|
+
}
|
|
189
|
+
/** The shared "when may this role next act" phrase — the `next run` cell (status-render.ts's
|
|
190
|
+
* nextRunCell) and the `Next run` line (role-render.ts's scheduleLine) render their schedule
|
|
149
191
|
* through it, so the two surfaces cannot drift on the backoff prefix or the humanSeconds
|
|
150
192
|
* bucketing. `remainSeconds` is the seconds until the next run (non-positive = due); `backoff`
|
|
151
193
|
* adds the `backoff ` prefix the wake action clears; `dueWord` names the due case and `withIn`
|
|
@@ -166,7 +208,7 @@ export function dayLabel(days) {
|
|
|
166
208
|
return plural(days, "day");
|
|
167
209
|
}
|
|
168
210
|
/** The report header both renderers print: the window's day-key bounds, its length in days
|
|
169
|
-
* (singular at 1), and the event log it was read from. The failure digest appends its own
|
|
211
|
+
* (singular at 1), and the event log it was read from. The failure digest appends its own run
|
|
170
212
|
* count. The rotation phrase is a required argument — eventsRotationLabel() supplies it from
|
|
171
213
|
* events.ts's EVENTS_MAX_BYTES, so this header cannot keep claiming "16 MB" after the actual
|
|
172
214
|
* threshold moves (this module stays presentation-only, owning no log facts of its own). The
|
|
@@ -180,7 +222,12 @@ export function reportWindow(from, to, days, rotation) {
|
|
|
180
222
|
* with the window's start instant in local time. `duration` is the window length already phrased
|
|
181
223
|
* by cli-args.ts's durationLabel (this helper supplies the leading `last `) — taken as a
|
|
182
224
|
* string so this presentation-only module avoids importing the CLI layer; the failure digest
|
|
183
|
-
* appends its own
|
|
225
|
+
* appends its own run count. One home so the two reports' window wording cannot drift. */
|
|
184
226
|
export function sinceWindowLine(duration, fromIso) {
|
|
185
227
|
return `window: last ${duration} (since ${formatTimestamp(new Date(fromIso).getTime())})`;
|
|
186
228
|
}
|
|
229
|
+
/** The bounded sibling of `sinceWindowLine`: the window line for a `--since`/`--until` span that
|
|
230
|
+
* ends before now. */
|
|
231
|
+
export function boundedWindowLine(since, until, fromIso, toIso) {
|
|
232
|
+
return `window: ${since} to ${until} ago (since ${formatTimestamp(new Date(fromIso).getTime())}, until ${formatTimestamp(new Date(toIso).getTime())})`;
|
|
233
|
+
}
|
package/dist/src/text/format.js
CHANGED
|
@@ -6,20 +6,31 @@ import { textOr } from "./text.js";
|
|
|
6
6
|
* (wording fragments). Presentation only: depends on node built-ins alone, so any layer
|
|
7
7
|
* (harness or observer) can import it — and each format lives in exactly one place so the
|
|
8
8
|
* abbreviation length, decimal width, and compaction thresholds cannot drift per consumer. */
|
|
9
|
+
/** Append a section note to a running prompt, separated from what precedes it by a blank line.
|
|
10
|
+
* The run and authoring-run prompt assemblers (run-prompt.ts, runner-run.ts) build a prompt by
|
|
11
|
+
* stacking nameless sections — assignment, held-entry, conflict-discard, conflict-handback and
|
|
12
|
+
* cut-off notes appended this way. The rejected-review and revision notes deliberately LEAD the
|
|
13
|
+
* run instead (prependPromptNote, plans/reviewer-as-role.md part 4/4) so the author cannot miss
|
|
14
|
+
* them. This is the single append so the `\n\n` section separator stays in one place. The note
|
|
15
|
+
* is appended unconditionally, exactly as the call sites appended the literal, so behavior is
|
|
16
|
+
* unchanged for any note. */
|
|
17
|
+
export function appendPromptNote(prompt, note) {
|
|
18
|
+
return `${prompt}\n\n${note}`;
|
|
19
|
+
}
|
|
20
|
+
/** Prepend a section note to a running prompt, separated from what follows by a blank line — the
|
|
21
|
+
* mirror of appendPromptNote, used where a note must LEAD the charter rather than trail it: the
|
|
22
|
+
* rejected-review note (run-prompt.ts) and the revision note (runner-run.ts) of
|
|
23
|
+
* plans/reviewer-as-role.md part 4/4, which the author must not miss. This is the single prepend
|
|
24
|
+
* so the `\n\n` section separator stays in one place, the same way appendPromptNote owns the
|
|
25
|
+
* append side. */
|
|
26
|
+
export function prependPromptNote(prompt, note) {
|
|
27
|
+
return `${note}\n\n${prompt}`;
|
|
28
|
+
}
|
|
9
29
|
/** Compact token count for tight table cells and commit trailers — bare integers below
|
|
10
30
|
* 10,000, one-decimal k at and above 10,000, one-decimal M at and above 1,000,000. The single
|
|
11
31
|
* home of the token display format shared by the status table's gen/peak-ctx columns and the
|
|
12
32
|
* commit trailer's ctx field — pinned here so those surfaces cannot drift even though they
|
|
13
33
|
* live in different modules. */
|
|
14
|
-
/** Append a section note to a running prompt, separated from what precedes it by a blank line.
|
|
15
|
-
* The tick and authoring-tick prompt assemblers (tick-prompt.ts, loop-tick.ts) build a prompt by
|
|
16
|
-
* stacking nameless sections — assignment, held-entry, rejected-review, conflict-discard,
|
|
17
|
-
* conflict-handback, revision and cut-off notes — each appended the same way. This is the single
|
|
18
|
-
* append so the `\n\n` section separator stays in one place. The note is appended unconditionally,
|
|
19
|
-
* exactly as the call sites appended the literal, so behavior is unchanged for any note. */
|
|
20
|
-
export function appendPromptNote(prompt, note) {
|
|
21
|
-
return `${prompt}\n\n${note}`;
|
|
22
|
-
}
|
|
23
34
|
export function compactTokens(n) {
|
|
24
35
|
if (n >= 1_000_000)
|
|
25
36
|
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
@@ -58,10 +69,36 @@ export function usdCap(n) {
|
|
|
58
69
|
/** A disk size in GB for display: one decimal and the unit (`12.3 GB`) — the single home of
|
|
59
70
|
* the disk-size format shared by the event feed's disk lines (event-format.ts), the status
|
|
60
71
|
* header's disk badge (badges.ts's `diskBadge`), the team's low-disk alert (team-alerts.ts),
|
|
61
|
-
* the doctor's disk check detail (doctor-checks.ts), and `tumwater reclaim`'s
|
|
62
|
-
* (operator-commands.ts), so the decimal width and unit cannot drift per
|
|
72
|
+
* the doctor's disk check detail (doctor-project-checks.ts), and `tumwater reclaim`'s
|
|
73
|
+
* freed-size line (operator-commands.ts), so the decimal width and unit cannot drift per
|
|
74
|
+
* consumer. A caller
|
|
63
75
|
* reading the value from an untrusted event field applies event-format.ts's `gigabytes`
|
|
64
76
|
* wrapper (finiteNumber's corrupt-field rule) over this. */
|
|
65
77
|
export function formatGB(n) {
|
|
66
78
|
return `${n.toFixed(1)} GB`;
|
|
67
79
|
}
|
|
80
|
+
/** A byte count for display, picking the largest of the B/KB/MB/GB tiers so the unit keeps the
|
|
81
|
+
* number small (`2.0 KB`, `1.5 MB`) — one decimal everywhere. The single home of the tiered
|
|
82
|
+
* byte format shared by the doctor's claude transcript size (doctor-checks.ts's `formatBytes`)
|
|
83
|
+
* and the opencode db/spill sizes (doctor-model-checks.ts's `opencodeBytes`), so the tiers and
|
|
84
|
+
* decimal width cannot drift per consumer. Distinct from `formatGB` above, which always renders
|
|
85
|
+
* a disk size in GB regardless of magnitude. The GUI's file-size label still formats from its
|
|
86
|
+
* own inline JS in gui-client-composer.ts: a separate runtime that cannot import TypeScript. */
|
|
87
|
+
export function formatBytes(n) {
|
|
88
|
+
if (n >= 1024 ** 3)
|
|
89
|
+
return `${(n / 1024 ** 3).toFixed(1)} GB`;
|
|
90
|
+
if (n >= 1024 ** 2)
|
|
91
|
+
return `${(n / 1024 ** 2).toFixed(1)} MB`;
|
|
92
|
+
if (n >= 1024)
|
|
93
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
94
|
+
return `${n} B`;
|
|
95
|
+
}
|
|
96
|
+
/** A token-count context window with its unit, thousands-separated (`128,000-token window`) —
|
|
97
|
+
* the single home of this format shared by the doctor's codex and opencode model checks
|
|
98
|
+
* (doctor-codex-checks.ts, doctor-opencode-checks.ts), each of which renders a cataloged
|
|
99
|
+
* model's window this way, so the separator and the "-token window" unit cannot drift per
|
|
100
|
+
* consumer. The separating comma is the caller's to add when the label follows a price
|
|
101
|
+
* (opencode's `, ${tokenWindowLabel(…)}`). */
|
|
102
|
+
export function tokenWindowLabel(n) {
|
|
103
|
+
return `${n.toLocaleString("en-US")}-token window`;
|
|
104
|
+
}
|
|
@@ -18,13 +18,16 @@ export function markdownTable(header, rows, align = []) {
|
|
|
18
18
|
...rows.map((cells) => `| ${cells.join(" | ")} |`),
|
|
19
19
|
];
|
|
20
20
|
}
|
|
21
|
-
/** `items` as a `1. …` ordered list, one line each, joined with newlines — the
|
|
21
|
+
/** `items` as a `1. …` ordered list, one line each, joined with newlines — the home of
|
|
22
22
|
* the `map((item, i) => `${i + 1}. ${item}`).join("\n")` step, shared by the review prompt's
|
|
23
23
|
* prior objections, its stage-fix findings, and the rejected/revision notes
|
|
24
|
-
* (prompt/gate-
|
|
25
|
-
* (backlog/question-answer.ts)
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* (prompt/gate-notes.ts), `tumwater questions`' open-question list
|
|
25
|
+
* (backlog/question-answer.ts) and `tumwater wake --list`'s wake lines
|
|
26
|
+
* (operator/operator-intent.ts `renderWakeList`), so the numbering shape cannot drift between
|
|
27
|
+
* those surfaces (the TUI queued-prompt rows and the merge queue rows number their own
|
|
28
|
+
* lines). `empty` is returned verbatim when `items` is empty
|
|
29
|
+
* (the reasons sites
|
|
30
|
+
* pass `(no reasons recorded)`; the others keep the default empty string). */
|
|
28
31
|
export function numberedList(items, empty = "") {
|
|
29
32
|
return items.length > 0 ? items.map((item, i) => `${i + 1}. ${item}`).join("\n") : empty;
|
|
30
33
|
}
|
package/dist/src/text/phrases.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { finiteNumber, isJsonObject, stringList } from "../files/json-object.js";
|
|
4
3
|
import { squash } from "./text.js";
|
|
@@ -8,38 +7,40 @@ import { shortSha, usd } from "./format.js";
|
|
|
8
7
|
* of $y", main's red-tip naming, a tool call's one-line label, the plural helper) shared by the
|
|
9
8
|
* event feed (event-format.ts), the failure digest (src/failure/failure-render.ts and
|
|
10
9
|
* src/failure/failure-state-change.ts), the status surfaces (ui/), and the CLI messages
|
|
11
|
-
* (operator/operator-commands.ts, cli/cli-
|
|
10
|
+
* (operator/operator-commands.ts, cli/cli-start-summary.ts), so their phrasing
|
|
11
|
+
* cannot drift per consumer.
|
|
12
12
|
* Pure presentation: every phrase composes the shared formats format.ts pins (shortSha, usd,
|
|
13
13
|
* squash) into words. Pure value formats — the token a number or hash renders as (compactTokens,
|
|
14
14
|
* shortSha, usd, usdCap) — stay in format.ts; this module is where those tokens become words. */
|
|
15
15
|
const NO_REASONS_GIVEN = "no reasons given";
|
|
16
|
-
/** The reason an over-long prompt or config field carries: the text rides into a
|
|
17
|
-
* prefill, so a longer value bloats every
|
|
16
|
+
/** The reason an over-long prompt or config field carries: the text rides into a run's
|
|
17
|
+
* prefill, so a longer value bloats every run's context. The single home of that tail,
|
|
18
18
|
* shared by init's seed check (init/init.ts) and config-validation's customRoles task and
|
|
19
19
|
* roles-instructions caps (config/config-validation.ts), so the three cannot drift on the
|
|
20
20
|
* wording. inbox-submit's promptLengthProblem renders a role-scoped variant ("it rides into
|
|
21
|
-
* the <role>
|
|
21
|
+
* the <role> run's prefill") and keeps its own wording. */
|
|
22
22
|
export const PREFILL_REASON = "it rides into every run's prefill";
|
|
23
23
|
/** The reason a review rejection leads with — its first listed reason, or `no reasons given`
|
|
24
24
|
* when the list is empty or its first entry is not a string. One home so the fallback cannot
|
|
25
25
|
* drift across the four surfaces that show just that first reason: the review gate's returned
|
|
26
26
|
* detail (review.ts), the event feed's one-line reject (event-format.ts), the failure digest's
|
|
27
|
-
* rejection clusters (failure-data.ts), and the error a
|
|
27
|
+
* rejection clusters (failure-data.ts), and the error a role's next run records (run-apply.ts).
|
|
28
28
|
* Sites that render the whole reason list, or intentionally omit the fallback (time-spend.ts's
|
|
29
29
|
* first-reason example, review.ts's rejection event `reason`), keep their own handling. */
|
|
30
30
|
export function firstReason(reasons) {
|
|
31
31
|
const first = reasons?.[0];
|
|
32
32
|
return typeof first === "string" ? first : NO_REASONS_GIVEN;
|
|
33
33
|
}
|
|
34
|
-
/** A count and its noun as one phrase (`plural(3, "
|
|
35
|
-
*
|
|
34
|
+
/** A count and its noun as one phrase (`plural(3, "run")` → `3 runs`) — the single home of the
|
|
35
|
+
* singular/plural selection the CLI's once summary (cli/cli-start-summary.ts), the
|
|
36
|
+
* day window's day label
|
|
36
37
|
* (datetime.ts), the failure digest's loss-cause lines (src/failure/failure-render.ts), and the
|
|
37
38
|
* team alerts' banner titles (ui/team-alerts.ts, whose local copy this replaces), and the
|
|
38
39
|
* build_stale lines' "N commit(s) ahead" (event-format.ts, src/failure/failure-state-change.ts —
|
|
39
40
|
* the singular/plural wording their tests pin, once "N commit(s)" with the old literal, now "N
|
|
40
41
|
* commits"/"1 commit"), and the stage self-check and dropped-attachment notes
|
|
41
|
-
* (src/
|
|
42
|
-
* whole replacement form (`plural(n, "
|
|
42
|
+
* (src/run/run-stage.ts, inbox/inbox-attachments.ts) all rendered inline before. `many` accepts a
|
|
43
|
+
* whole replacement form (`plural(n, "role is", "roles are")`) so verb-agreement titles share the
|
|
43
44
|
* helper; the plural-by-`s` default covers regular nouns. (The GUI keeps its own JS copy in
|
|
44
45
|
* gui-client.ts: a separate runtime that cannot import TypeScript.) */
|
|
45
46
|
export function plural(n, one, many = `${one}s`) {
|
|
@@ -86,16 +87,16 @@ export function mainRedNotMine(sha) {
|
|
|
86
87
|
export function pauseReasonSuffix(reason) {
|
|
87
88
|
return reason ? ` — "${reason}"` : "";
|
|
88
89
|
}
|
|
89
|
-
/** The harness warning a
|
|
90
|
-
*
|
|
90
|
+
/** The harness warning a role crossing the error-streak threshold raises — `3 consecutive
|
|
91
|
+
* run failures: <reason>` — shared by the run-side crossing (run-finalize.ts, an error or
|
|
91
92
|
* recovery failure) and the merge-side crossing a review rejection resolves
|
|
92
93
|
* (merge-slot.ts), the two sites that build the message, so the operator-facing wording
|
|
93
94
|
* their tests pin cannot drift between them. */
|
|
94
95
|
export function consecutiveFailuresWarning(count, reason) {
|
|
95
96
|
return `${count} runs failed in a row: ${reason}`;
|
|
96
97
|
}
|
|
97
|
-
/** The base line for an operator team pause — `team paused —
|
|
98
|
-
*
|
|
98
|
+
/** The base line for an operator team pause — `team paused — roles stop starting new
|
|
99
|
+
* runs` — built here so the event feed (event-format.ts, which appends its own `(director
|
|
99
100
|
* keeps running)` consequence) and the failure digest's Team state changes lines
|
|
100
101
|
* (src/failure/failure-state-change.ts, which keeps the short form) cannot drift on the base
|
|
101
102
|
* wording. `tumwater pause`'s confirmation (operator/operator-commands.ts) interleaves its
|
|
@@ -112,6 +113,10 @@ export function teamPausePhrase() {
|
|
|
112
113
|
export function teamResumePhrase() {
|
|
113
114
|
return "team resumed — roles run again";
|
|
114
115
|
}
|
|
116
|
+
/** Appended to a resume line whose `expired: true` event says the pause's deadline lifted it
|
|
117
|
+
* rather than `tumwater resume` — read by the event feed (event-format.ts) and the failure
|
|
118
|
+
* digest (src/failure/failure-state-change.ts). */
|
|
119
|
+
export const PAUSE_EXPIRED_SUFFIX = " (its timed pause ran out)";
|
|
115
120
|
/** The base line for a per-role pause — `role <id> paused — it starts no new runs` —
|
|
116
121
|
* shared by the event feed (event-format.ts, which appends `(the rest of the team keeps running)`)
|
|
117
122
|
* and the failure digest's Team state changes lines (src/failure/failure-state-change.ts, which
|
|
@@ -129,7 +134,25 @@ export function roleResumePhrase(role) {
|
|
|
129
134
|
}
|
|
130
135
|
/** The line for an orchestrator shutdown — the event feed (event-format.ts) and the failure
|
|
131
136
|
* digest's Team state changes lines (src/failure/failure-state-change.ts) both render it. */
|
|
132
|
-
|
|
137
|
+
const ORCHESTRATOR_STOPPED = "tumwater stopped";
|
|
138
|
+
/** The orchestrator shutdown line with its `cause` (restart, once, signal, error): the event feed
|
|
139
|
+
* (event-format.ts) and the failure digest (src/failure/failure-state-change.ts) both render it.
|
|
140
|
+
* A missing or unknown cause — every event logged before the field existed — renders the bare
|
|
141
|
+
* ORCHESTRATOR_STOPPED. */
|
|
142
|
+
export function orchestratorStopPhrase(cause) {
|
|
143
|
+
switch (cause) {
|
|
144
|
+
case "restart":
|
|
145
|
+
return `${ORCHESTRATOR_STOPPED} to restart onto the new build`;
|
|
146
|
+
case "once":
|
|
147
|
+
return `${ORCHESTRATOR_STOPPED} — the --once round settled`;
|
|
148
|
+
case "signal":
|
|
149
|
+
return `${ORCHESTRATOR_STOPPED} on a stop signal`;
|
|
150
|
+
case "error":
|
|
151
|
+
return `${ORCHESTRATOR_STOPPED} — its polling failed`;
|
|
152
|
+
default:
|
|
153
|
+
return ORCHESTRATOR_STOPPED;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
133
156
|
/** A HarnessEvent's loosely typed `roles` list as a `A, B, C` phrase — the single home of the
|
|
134
157
|
* array coercion and join, shared by the event feed (event-format.ts: counters_reset's scope,
|
|
135
158
|
* budget_handback's handed-back list, the rate_limit_hold line) and the failure digest's state-
|
|
@@ -197,17 +220,30 @@ export function backendKindPhrase(kind) {
|
|
|
197
220
|
return "backend failure";
|
|
198
221
|
}
|
|
199
222
|
}
|
|
223
|
+
const LEADING_CD = /^\s*cd\s+(?:"[^"]*"|'[^']*'|\S+)\s*(?:&&|;)\s*/;
|
|
224
|
+
function withoutLeadingCd(command) {
|
|
225
|
+
let rest = command;
|
|
226
|
+
while (LEADING_CD.test(rest))
|
|
227
|
+
rest = rest.replace(LEADING_CD, "");
|
|
228
|
+
return rest.trim() ? rest : command;
|
|
229
|
+
}
|
|
200
230
|
/** One-line description of a tool call from its name and args — shared by live progress data
|
|
201
231
|
* collection (LiveProgress.lastTool), transcript rendering, and the harness's stalled-tool-call
|
|
202
232
|
* warning (src/pi/pi-stream.ts builds the label src/pi/pi-watchdogs.ts renders). Path-like keys
|
|
203
|
-
* reduce to the file name; the other candidate keys are shown verbatim.
|
|
233
|
+
* reduce to the file name; the other candidate keys are shown verbatim. A leading `cd <dir> &&`
|
|
234
|
+
* is dropped from a command, because the run's cwd is implied and the path would use up the
|
|
235
|
+
* 32-character budget. */
|
|
204
236
|
export function describeToolCall(toolName, args) {
|
|
205
237
|
let detail = "";
|
|
206
238
|
if (isJsonObject(args)) {
|
|
207
239
|
const candidate = args.path ?? args.file_path ?? args.command ?? args.cmd ?? args.pattern ?? args.url;
|
|
208
240
|
if (typeof candidate === "string") {
|
|
209
241
|
detail =
|
|
210
|
-
candidate === args.path || candidate === args.file_path
|
|
242
|
+
candidate === args.path || candidate === args.file_path
|
|
243
|
+
? path.basename(candidate)
|
|
244
|
+
: candidate === args.command || candidate === args.cmd
|
|
245
|
+
? withoutLeadingCd(candidate)
|
|
246
|
+
: candidate;
|
|
211
247
|
}
|
|
212
248
|
}
|
|
213
249
|
detail = squash(detail, 32);
|
|
@@ -218,12 +254,13 @@ export function describeToolCall(toolName, args) {
|
|
|
218
254
|
/** The ` (+N more)` remainder suffix a capped list appends when `count` entries were omitted —
|
|
219
255
|
* empty when none were, so the item fits an already-built line either way. The single home of that
|
|
220
256
|
* parenthesized remainder, shared by the reviewer suite-rerun warning (review/suite-rerun.ts) and
|
|
221
|
-
* the stage self-check's missing-path and lost-final-newline findings (
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
257
|
+
* the stage self-check's missing-path and lost-final-newline findings (run/stage-path-checks.ts
|
|
258
|
+
* and run/stage-prose-checks.ts),
|
|
259
|
+
* so the three cannot drift on the spacing or the parenthesized form. The other remainder
|
|
260
|
+
* phrasings keep their own wording: the failure digest's bare `+N more` role list and its `_+N
|
|
261
|
+
* more …_` lines (failure/failure-render.ts), doctor's `and N more` (doctor/doctor-orphans.ts),
|
|
262
|
+
* the TUI alert pointer (ui/tui/tui-frame.ts), and the review-reject reasons, whose extra clause
|
|
263
|
+
* sits inside the parentheses (events/event-format.ts). */
|
|
227
264
|
export function moreSuffix(count) {
|
|
228
265
|
return count > 0 ? ` (+${count} more)` : "";
|
|
229
266
|
}
|
package/dist/src/text/suggest.js
CHANGED
|
@@ -55,7 +55,7 @@ export function didYouMean(suggestion) {
|
|
|
55
55
|
* `input` against `candidates`, the empty string when nothing is close enough to suggest. The
|
|
56
56
|
* unknown-X error sites (roles.ts's unknownRoleMessage, config-write.ts's
|
|
57
57
|
* unknownConfigKeyError and its role-field error, config-field-checks.ts's checkKnownKeys,
|
|
58
|
-
* checkKnownRoleId and its thinking-level problem, config-validation.ts's backend problem,
|
|
58
|
+
* checkKnownRoleId and its thinking-level problem, config-validation-agents.ts's backend problem,
|
|
59
59
|
* gui/gui-args.ts's rejectBadRole, init-templates.ts's
|
|
60
60
|
* unknownTemplateError) render the hint
|
|
61
61
|
* through this one composition so the two-step pairing cannot drift; callers still print the
|
package/dist/src/text/text.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Shared text-shaping helpers for human-facing one-line text — the observability layer's
|
|
2
|
-
* display labels (live progress, transcripts),
|
|
2
|
+
* display labels (live progress, transcripts), run commit subjects and body fields, and
|
|
3
3
|
* build-check reason lines: whitespace collapsing, ellipsis truncation, and plain-decimal
|
|
4
4
|
* integer parsing. (Number, money, and hash formats — compactTokens, shortSha, usd, usdCap —
|
|
5
5
|
* live in format.ts; local date/time formatting and calendar-day arithmetic live in
|
|
@@ -34,7 +34,7 @@ export function stripTerminalControls(s) {
|
|
|
34
34
|
* The one home of the "a torn or hand-edited field reads as a visible placeholder, never
|
|
35
35
|
* String(undefined)'s literal 'undefined'" coercion the event feed's free-text fields and
|
|
36
36
|
* shortSha apply. Numbers stay admitted because events legitimately carry numeric fields
|
|
37
|
-
* (a
|
|
37
|
+
* (a run number, a pid) that a display line renders as text. */
|
|
38
38
|
export function textOr(value, fallback = "?") {
|
|
39
39
|
if (typeof value === "string")
|
|
40
40
|
return value;
|
|
@@ -49,6 +49,28 @@ export function textOr(value, fallback = "?") {
|
|
|
49
49
|
export function errorMessage(err) {
|
|
50
50
|
return err instanceof Error ? err.message : String(err);
|
|
51
51
|
}
|
|
52
|
+
/** The first line of `errorMessage(err)`, trimmed: the one-line form a status reason carries
|
|
53
|
+
* when git's multi-line stderr would swamp it. Used by the fast-forward and archive-commit
|
|
54
|
+
* failure reasons. */
|
|
55
|
+
export function errorFirstLine(err) {
|
|
56
|
+
return errorMessage(err).trim().split("\n")[0];
|
|
57
|
+
}
|
|
58
|
+
/** `s` with every regex metacharacter escaped, so it can be dropped into a `RegExp` and match
|
|
59
|
+
* only its literal text — the one spelling of the standard `replace(/[.*+?^${}()|[\]\\]/g,
|
|
60
|
+
* "\\$&")` escape, previously repeated at every site that turned an untrusted string (a
|
|
61
|
+
* provider id, a series/held-tag prefix, a role-note token, a config fragment) into a
|
|
62
|
+
* word-bounded or anchored match. Careful callers build `new RegExp(escapeRegExp(s))` and then
|
|
63
|
+
* append the boundaries (`\\b`, `^`, `)`) they want on top; this helper escapes only, never
|
|
64
|
+
* anchors, so the caller keeps control of the surrounding pattern. The presentation-only
|
|
65
|
+
* contract is inherited from the module: node built-ins alone, so any layer can import it. */
|
|
66
|
+
export function escapeRegExp(s) {
|
|
67
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
68
|
+
}
|
|
69
|
+
/** The first line of `body` that begins with `prefix` once trimmed, trimmed; undefined when no
|
|
70
|
+
* line does. Used by the backlog's hold-note text and the answered-question preview. */
|
|
71
|
+
export function firstTrimmedLineStartingWith(body, prefix) {
|
|
72
|
+
return body.split("\n").map((l) => l.trim()).find((l) => l.startsWith(prefix));
|
|
73
|
+
}
|
|
52
74
|
/** The error message's " (got …)" value suffix, spelled one way everywhere: JSON.stringify for
|
|
53
75
|
* the value's debug form, wrapped in the established parenthetical. The human-facing
|
|
54
76
|
* validation errors that echo back a rejected value with this suffix — the CLI flag
|
|
@@ -57,12 +79,11 @@ export function errorMessage(err) {
|
|
|
57
79
|
* this one helper, so the "got" wording and its quoting cannot drift between surfaces.
|
|
58
80
|
* (Deliberately different suffixes: config-field-checks's show() truncates long config values
|
|
59
81
|
* before the parenthetical, and cli/cli-args.ts's duration cap renders the value through
|
|
60
|
-
* durationLabel — neither fits a plain stringify.)
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* request simply did not carry. */
|
|
82
|
+
* durationLabel — neither fits a plain stringify.) A missing value
|
|
83
|
+
* (undefined) appends nothing, since ` (got undefined)` would name a field the request never
|
|
84
|
+
* carried; null still prints ` (got null)`, a value the request did carry. */
|
|
64
85
|
export function gotSuffix(v) {
|
|
65
|
-
return ` (got ${JSON.stringify(v)})`;
|
|
86
|
+
return v === undefined ? "" : ` (got ${JSON.stringify(v)})`;
|
|
66
87
|
}
|
|
67
88
|
/** Is `v` a string with non-whitespace content — the "field carries something usable" guard every
|
|
68
89
|
* structural read of an unknown-typed JSON field applies (a blank or whitespace-only string reads
|
|
@@ -70,7 +91,7 @@ export function gotSuffix(v) {
|
|
|
70
91
|
* narrows `v` to `string` for the code that consumes it — the one spelling shared by
|
|
71
92
|
* build/build-check-detect.ts's check-script/command/cwd/gateCommand reads, config validation's
|
|
72
93
|
* thinking-level check and model-field guards (tier-map values, the legacy model/ fallback selector
|
|
73
|
-
* and its legacy provider, exempt paths, custom-
|
|
94
|
+
* and its legacy provider, exempt paths, custom-role tasks), pi-event-line.ts's tool-result content
|
|
74
95
|
* test, quiet-hours.ts's per-role window lookup, and inbox-attachments.ts's image-name check, so
|
|
75
96
|
* the blank-means-unset rule cannot drift per call site. Callers where a bare empty string means
|
|
76
97
|
* unset rather than blank text (notify.ts, version.ts, inbox-cancel.ts) keep their own `=== ""`
|
|
@@ -79,6 +100,27 @@ export function gotSuffix(v) {
|
|
|
79
100
|
export function isNonBlankString(v) {
|
|
80
101
|
return typeof v === "string" && v.trim() !== "";
|
|
81
102
|
}
|
|
103
|
+
/** Split a comma list into its trimmed, non-empty pieces, in order — the one spelling of the
|
|
104
|
+
* split-trim-drop-blanks step shared by the `--role` list flags (cli-args.ts and
|
|
105
|
+
* operator-commands.ts), `logs --type`, the history `--result` and `--model` filters, and the
|
|
106
|
+
* GUI's `role` and `model` query parameters. Deduplication and the no-piece-left error stay
|
|
107
|
+
* with each caller. */
|
|
108
|
+
export function splitCommaList(raw) {
|
|
109
|
+
return raw.split(",").map((p) => p.trim()).filter((p) => p !== "");
|
|
110
|
+
}
|
|
111
|
+
/** splitCommaList with repeated pieces dropped (first occurrence kept) — the `--model` history
|
|
112
|
+
* filter and the GUI's `role` and `model` query parameters, each of which treats a repeat as
|
|
113
|
+
* the same selector. */
|
|
114
|
+
export function splitCommaListUnique(raw) {
|
|
115
|
+
return [...new Set(splitCommaList(raw))];
|
|
116
|
+
}
|
|
117
|
+
/** A value or list of `T` as a list: a bare `T` is one item, an array stays itself. The
|
|
118
|
+
* single home of the string-or-list normalization (a `--role` selector is either one id or a
|
|
119
|
+
* comma-split list): report-fold.ts's scopeBases/roleSum/narrowToRole and history-data.ts's
|
|
120
|
+
* role filter each spelled the `typeof x === "string" ? [x] : x` wrap by hand before. */
|
|
121
|
+
export function asList(value) {
|
|
122
|
+
return typeof value === "string" ? [value] : value;
|
|
123
|
+
}
|
|
82
124
|
/** Drop the blank lines at the start of `lines`, in place — the one home of the
|
|
83
125
|
* leading-blank trim loop shared by the backlog writer's section-content rebuild and
|
|
84
126
|
* `questions answer`'s tail slice (the lines after the moved answer). Blank means
|
|
@@ -112,6 +154,20 @@ function isLowSurrogate(code) {
|
|
|
112
154
|
export function cutSplitsSurrogatePair(s, i) {
|
|
113
155
|
return i > 0 && i < s.length && isHighSurrogate(s.charCodeAt(i - 1)) && isLowSurrogate(s.charCodeAt(i));
|
|
114
156
|
}
|
|
157
|
+
/** Join the first `max` of `items` with `sep`, then `<sep>+N more` when others were left out. */
|
|
158
|
+
export function joinWithMore(items, max, sep = ", ") {
|
|
159
|
+
const shown = items.slice(0, max).join(sep);
|
|
160
|
+
return items.length > max ? `${shown}${sep}+${items.length - max} more` : shown;
|
|
161
|
+
}
|
|
162
|
+
/** Join the non-empty entries of `parts` with `sep`, dropping empty strings and nullish or
|
|
163
|
+
* falsy entries — the shape of a message assembled from optional fragments (a doctor verdict
|
|
164
|
+
* line, a commit body, a provider/model token, an error note). Each call site previously
|
|
165
|
+
* wrote `[a, ...b].filter(Boolean).join(sep)` by hand; feeding a fragment that is unset (an
|
|
166
|
+
* `undefined`/`false` from a guard) is fine, no `cond ? x : ""` placeholder needed. Returns
|
|
167
|
+
* the empty string when nothing is non-empty. */
|
|
168
|
+
export function joinParts(parts, sep = "; ") {
|
|
169
|
+
return parts.filter((p) => Boolean(p)).join(sep);
|
|
170
|
+
}
|
|
115
171
|
/** Shorten `s` to at most `max` characters: unchanged when it fits, otherwise cut to
|
|
116
172
|
* `max - 1`, drop any trailing space the cut may have left behind, and append an ellipsis.
|
|
117
173
|
* The result is never longer than `max`. A cut that would split a surrogate pair (an astral
|
|
@@ -140,8 +196,8 @@ export function squash(s, max) {
|
|
|
140
196
|
/** Text capped for injection into a prompt: past `max` characters it is cut and given a visible
|
|
141
197
|
* `…[<label> truncated at <max> chars]` note naming what was capped and how much survived, so
|
|
142
198
|
* the loss is never silent. The single home of that marker format — the PRINCIPLES.md cap
|
|
143
|
-
* (principles.ts's readPrinciples), the
|
|
144
|
-
* the role-
|
|
199
|
+
* (principles.ts's readPrinciples), the brief text backstop (brief.ts's extractPrompt), and
|
|
200
|
+
* the role-notes read (run-prompt.ts) all render through it, so the defensive caps cannot
|
|
145
201
|
* drift apart in wording. A plain slice at `max` (not truncate's ellipsis-and-trim cut): the
|
|
146
202
|
* marker carries the ellipsis, and the cut boundary must stay a stable, predictable prefix of
|
|
147
203
|
* the original text. A cut that would split a surrogate pair (an astral character such as
|
|
@@ -189,11 +245,20 @@ export function parseNonNegativeInt(raw) {
|
|
|
189
245
|
}
|
|
190
246
|
/** The shared over-long-text message: `<subject> is <n> chars — shorten it to at most <max>`,
|
|
191
247
|
* with `tail` naming where the text rides once accepted. The one home of that phrasing, used
|
|
192
|
-
* by init's seed check (init.ts, "the
|
|
193
|
-
* promptLengthProblem ("the prompt … the <role>
|
|
194
|
-
* customRoles task and roles instructions caps (both "every
|
|
248
|
+
* by init's seed check (init.ts, "the brief text … every run's prefill"), inbox-submit's
|
|
249
|
+
* promptLengthProblem ("the prompt … the <role> run's prefill"), and config-validation's
|
|
250
|
+
* customRoles task and roles instructions caps (both "every run's prefill"), so the four
|
|
195
251
|
* too-long messages cannot drift apart in shape. Callers keep their own subject, cap, and
|
|
196
252
|
* tail; this owns only the sentence around them. */
|
|
197
253
|
export function tooLongMessage(subject, n, max, tail) {
|
|
198
254
|
return `${subject} is ${n} chars — shorten it to at most ${max}: ${tail}`;
|
|
199
255
|
}
|
|
256
|
+
/** Each distinct path-shaped token in `text`, in first-appearance order: at least one slash and
|
|
257
|
+
* a final `.<ext>` segment. Scanned inside the text (not whitespace-split) so surrounding
|
|
258
|
+
* backticks, brackets, and sentence punctuation fall away with the match. Shared by the staging
|
|
259
|
+
* self-check's added-nonexistent-path finding (run/stage-path-checks.ts) and run-prompt's
|
|
260
|
+
* role-note missing-path scan (run/run-prompt.ts), so the two agree on what reads as a path. */
|
|
261
|
+
export function pathTokens(text) {
|
|
262
|
+
const tokenRe = /[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+\.[A-Za-z0-9]+/g;
|
|
263
|
+
return [...new Set([...text.matchAll(tokenRe)].map((m) => m[0]))];
|
|
264
|
+
}
|