tumwater 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +42 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +4 -3
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +402 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +246 -55
- package/dist/src/backlog/backlog-cli-view.js +280 -0
- package/dist/src/backlog/backlog-cli.js +85 -274
- package/dist/src/backlog/backlog-commit.js +4 -5
- package/dist/src/backlog/backlog-eligibility.js +175 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +254 -0
- package/dist/src/backlog/backlog-release.js +117 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-culprit.js +94 -0
- package/dist/src/baseline/main-guardrails.js +209 -0
- package/dist/src/baseline/main-red.js +139 -32
- package/dist/src/baseline/main-revert.js +133 -0
- package/dist/src/baseline/main-watch.js +184 -0
- package/dist/src/brief/brief-edit.js +9 -11
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget.js +30 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +1 -2
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +118 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +150 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +308 -590
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-role-command.js +420 -0
- package/dist/src/cli/cli-start-summary.js +160 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
- package/dist/src/cli/completion.js +149 -22
- package/dist/src/cli/config-commands.js +41 -18
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +189 -73
- package/dist/src/cli/log-commands.js +148 -82
- package/dist/src/cli/question-commands.js +205 -10
- package/dist/src/cli.js +106 -43
- package/dist/src/collections.js +26 -10
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +13 -1
- package/dist/src/config/config-fallbacks.js +93 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +141 -199
- package/dist/src/config/config-views.js +127 -53
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +131 -264
- package/dist/src/config/config.js +48 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
- package/dist/src/doctor/doctor-backlog-plans.js +263 -0
- package/dist/src/doctor/doctor-backlog.js +100 -496
- package/dist/src/doctor/doctor-check-names.js +81 -0
- package/dist/src/doctor/doctor-checks.js +52 -579
- package/dist/src/doctor/doctor-claude-checks.js +145 -0
- package/dist/src/doctor/doctor-codex-checks.js +279 -0
- package/dist/src/doctor/doctor-contention-checks.js +380 -0
- package/dist/src/doctor/doctor-holds.js +82 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +236 -402
- package/dist/src/doctor/doctor-notify.js +3 -4
- package/dist/src/doctor/doctor-opencode-checks.js +162 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-project-checks.js +303 -0
- package/dist/src/doctor/doctor.js +121 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +7 -11
- package/dist/src/events/event-format.js +181 -86
- package/dist/src/events/event-labels.js +12 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +39 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +60 -24
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +56 -56
- package/dist/src/failure/failure-render.js +31 -23
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +99 -35
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +177 -84
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +108 -58
- package/dist/src/gates/maintenance-quota.js +10 -13
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +77 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +36 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +42 -18
- package/dist/src/gui/gui-backlog-endpoints.js +155 -0
- package/dist/src/gui/gui-command.js +8 -13
- package/dist/src/gui/gui-config-commands.js +94 -72
- package/dist/src/gui/gui-endpoint-commands.js +4 -3
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +108 -13
- package/dist/src/gui/gui-prompt-commands.js +11 -14
- package/dist/src/gui/gui-report-endpoints.js +90 -0
- package/dist/src/gui/gui-server.js +11 -4
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +147 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +193 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +25 -9
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +81 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +150 -11
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +90 -0
- package/dist/src/merge/merge-queue-render.js +49 -11
- package/dist/src/merge/merge-queue.js +31 -15
- package/dist/src/merge/merge-requeue.js +102 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +33 -11
- package/dist/src/merge/merge-to-main.js +86 -27
- package/dist/src/merge/merge-top.js +69 -0
- package/dist/src/merge/merge-verify.js +12 -10
- package/dist/src/notes-cli.js +30 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +320 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
- package/dist/src/orchestrator/orchestrator.js +128 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +201 -0
- package/dist/src/orchestrator/scheduling-skip.js +185 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +116 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +18 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +121 -211
- package/dist/src/prompt/notes-backlog.js +181 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +129 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +161 -77
- package/dist/src/report/report-fold.js +129 -52
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +133 -64
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +26 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/known-flakes.js +100 -1
- package/dist/src/review/post-merge-review.js +106 -0
- package/dist/src/review/protected-edits.js +4 -5
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +155 -360
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +69 -12
- package/dist/src/roles/role-guidance.js +55 -20
- package/dist/src/roles/role-labels.js +1 -2
- package/dist/src/roles/role-render.js +67 -50
- package/dist/src/roles/role-view.js +59 -47
- package/dist/src/roles/roles.js +31 -31
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/{tick → run}/qa-coverage.js +9 -27
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +179 -0
- package/dist/src/run/run-detail-render.js +98 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +108 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +108 -50
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +91 -56
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +172 -0
- package/dist/src/run/stage-path-checks.js +730 -0
- package/dist/src/{loop → runner}/leftover.js +80 -25
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +202 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +107 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +21 -15
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +102 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +43 -16
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +28 -28
- package/dist/src/status/status-roles.js +39 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +5 -6
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +63 -17
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +57 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +67 -13
- package/dist/src/ui/badges.js +65 -37
- package/dist/src/ui/gui/gui-client-backlog.js +292 -0
- package/dist/src/ui/gui/gui-client-boot.js +32 -26
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
- package/dist/src/ui/gui/gui-client-drawer.js +126 -285
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +434 -67
- package/dist/src/ui/gui/gui-client-labels.js +1 -2
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +55 -51
- package/dist/src/ui/gui/gui-client-pending.js +227 -23
- package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
- package/dist/src/ui/gui/gui-client-report.js +87 -427
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +56 -4
- package/dist/src/ui/gui/gui-client-team.js +25 -465
- package/dist/src/ui/gui/gui-client.js +27 -25
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +9 -7
- package/dist/src/ui/gui/gui-styles.js +34 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +136 -49
- package/dist/src/ui/status-render.js +101 -82
- package/dist/src/ui/team-alerts.js +248 -57
- package/dist/src/ui/tone.js +5 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +51 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +3 -5
- package/dist/src/ui/tui/tui-editor-backends.js +132 -0
- package/dist/src/ui/tui/tui-editor-brief.js +10 -12
- package/dist/src/ui/tui/tui-editor-budget.js +35 -31
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
- package/dist/src/ui/tui/tui-editor-config.js +86 -0
- package/dist/src/ui/tui/tui-editor-entry.js +36 -47
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +37 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
- package/dist/src/ui/tui/tui-editor-interval.js +11 -9
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +3 -5
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +99 -35
- package/dist/src/ui/tui/tui-editor-retire.js +4 -6
- package/dist/src/ui/tui/tui-editor-role-key.js +76 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +60 -34
- package/dist/src/ui/tui/tui-editor-slots.js +23 -0
- package/dist/src/ui/tui/tui-editors.js +35 -2
- package/dist/src/ui/tui/tui-frame.js +56 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +24 -9
- package/dist/src/ui/tui/tui-pane-activity.js +14 -11
- package/dist/src/ui/tui/tui-pane-backlog.js +171 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +58 -8
- package/dist/src/ui/tui/tui-pane-history.js +402 -82
- package/dist/src/ui/tui/tui-pane-pending.js +308 -13
- package/dist/src/ui/tui/tui-pane-queued.js +71 -55
- package/dist/src/ui/tui/tui-pane-report.js +46 -14
- package/dist/src/ui/tui/tui-pane-session.js +25 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +80 -23
- package/dist/src/ui/tui/tui-panes.js +100 -30
- package/dist/src/ui/tui/tui.js +14 -14
- package/dist/src/verdict/fix-claim.js +82 -32
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +42 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -3,11 +3,21 @@
|
|
|
3
3
|
* `## Open` to `## Answered` with a dated operator answer. The markdown surgery itself — the
|
|
4
4
|
* fence-aware `### ` block cut and the `## Answered` skeleton — lives in src/backlog/
|
|
5
5
|
* question-answer.ts (the shared QUESTIONS.md core the TUI and dashboard also call); this module
|
|
6
|
-
* is
|
|
7
|
-
* cli
|
|
6
|
+
* is the command's argument scan, say/fail/editor jacket and commit-and-wake tail over that core,
|
|
7
|
+
* routed to by src/cli.ts.
|
|
8
8
|
*/
|
|
9
|
-
import { fail, say, sayJson } from "./cli-output.js";
|
|
10
|
-
import {
|
|
9
|
+
import { fail, say, sayJson, warnIfUncommitted } from "./cli-output.js";
|
|
10
|
+
import { parseCountFlag, parsePositionFlag, rejectRepeatFlag } from "./cli-args.js";
|
|
11
|
+
import { JSON_FLAG, rejectEqualsForm } from "./cli-flag-specs.js";
|
|
12
|
+
import { refuseTeamWorkspace } from "./cli-repo-gate.js";
|
|
13
|
+
import { promptFileValue, readPromptFileArg } from "./cli-command-args.js";
|
|
14
|
+
import { editInEditor } from "./cli-editor.js";
|
|
15
|
+
import { gotSuffix, parsePositiveInt } from "../text/text.js";
|
|
16
|
+
import { typoSuffix } from "../text/suggest.js";
|
|
17
|
+
import { commitOperatorBacklogEdit } from "../backlog/backlog-commit.js";
|
|
18
|
+
import { stampedSubject } from "../git/commit-message.js";
|
|
19
|
+
import { wakeQuestionAsker } from "../operator/operator-intent.js";
|
|
20
|
+
import { answeredQuestionAt, answeredQuestionCount, answeredQuestionList, answeredQuestionPayload, openQuestionAt, openQuestionList, questionListPayload, renderShownQuestion, UNCLOSED_FENCE_MESSAGE, tryAnswerQuestion } from "../backlog/question-answer.js";
|
|
11
21
|
import { bodyStructureProblem, normalizeEntryBody } from "../backlog/backlog-write.js";
|
|
12
22
|
/** The `tumwater questions answer` entry point: `tryAnswerQuestion` without a title check, its
|
|
13
23
|
* refusals mapped to `fail` (exit 1) with the CLI's wording. Returns the answered question's
|
|
@@ -32,7 +42,7 @@ function answeredOrFail(n, outcome) {
|
|
|
32
42
|
/** `tumwater questions answer <n> --file <path>`: the decision's lines kept (normalizeEntryBody),
|
|
33
43
|
* behind the same structural guard `plan --file` uses, so a stray `## ` line cannot grow a
|
|
34
44
|
* phantom section. Refusals exit 1 through `fail`. */
|
|
35
|
-
|
|
45
|
+
function answerQuestionFromText(root, n, text, expectedTitle) {
|
|
36
46
|
const body = normalizeEntryBody(text);
|
|
37
47
|
if (body === "")
|
|
38
48
|
fail("questions answer needs a decision: the file is blank");
|
|
@@ -45,12 +55,12 @@ export function answerQuestionFromText(root, n, text, expectedTitle) {
|
|
|
45
55
|
export const ANSWER_EDITOR_CUT = "<!-- tumwater: write your decision above this line; this line and everything below it are dropped -->";
|
|
46
56
|
/** The editor buffer for bare `questions answer <n>`: an empty decision area, the cut line, then
|
|
47
57
|
* the question's heading and body for reference. */
|
|
48
|
-
|
|
58
|
+
function answerEditorBuffer(title, body) {
|
|
49
59
|
return ["", "", ANSWER_EDITOR_CUT, `### ${title}`, body].join("\n");
|
|
50
60
|
}
|
|
51
61
|
/** The decision an edited `answerEditorBuffer` holds: the text before the first cut line (all of
|
|
52
62
|
* it when the operator deleted the line). */
|
|
53
|
-
|
|
63
|
+
function decisionFromEditorBuffer(text) {
|
|
54
64
|
const lines = text.split("\n");
|
|
55
65
|
const cut = lines.findIndex((l) => l.trim() === ANSWER_EDITOR_CUT);
|
|
56
66
|
return (cut === -1 ? lines : lines.slice(0, cut)).join("\n");
|
|
@@ -66,9 +76,194 @@ export function sayAnswered(position, title, json, decision) {
|
|
|
66
76
|
/** One entry point for the list modes so cli.ts stays a dispatcher: --json prints the payload
|
|
67
77
|
* document (an empty outbox still prints it), prose prints the numbered lines or the empty
|
|
68
78
|
* line. */
|
|
69
|
-
|
|
79
|
+
function sayQuestionList(root, json, pattern) {
|
|
70
80
|
if (json)
|
|
71
|
-
sayJson(questionListPayload(root));
|
|
81
|
+
sayJson(questionListPayload(root, pattern));
|
|
72
82
|
else
|
|
73
|
-
say(openQuestionList(root));
|
|
83
|
+
say(openQuestionList(root, pattern));
|
|
84
|
+
}
|
|
85
|
+
/** `questions answer`'s `--file <path>` flag: the decision comes from the file, lines kept. */
|
|
86
|
+
const FILE_SPEC = { names: ["--file"], value: true, valueName: "<path>" };
|
|
87
|
+
/** `tumwater questions`: list open questions, or answer one with `answer <n> <decision>`. */
|
|
88
|
+
export async function cmdQuestions(root, args) {
|
|
89
|
+
// No requireReadyRepo gate, like backlog: the reader degrades to an empty list on a
|
|
90
|
+
// missing QUESTIONS.md, so the command inspects any directory instead of refusing (a team
|
|
91
|
+
// workspace still refuses).
|
|
92
|
+
// The answer form's decision is free-form prose, so peelPositionals cannot route the
|
|
93
|
+
// tokens: a decision word may begin with a single dash (`questions answer 1 "-50% spend
|
|
94
|
+
// cap"`), and peelPositionals would hand it to the flag gate as an unknown flag — the
|
|
95
|
+
// same masking parsePromptArgs avoids for prompt text by owning only `--`-prefixed
|
|
96
|
+
// tokens. So the questions parse scans args itself: a `--json` token before the
|
|
97
|
+
// question's number positional is the one flag (repeats refused, equals form named by
|
|
98
|
+
// rejectEqualsForm), any other `--`-prefixed token before it is refused as unknown, and
|
|
99
|
+
// every remaining token in order is prose — subcommand, position number, then the
|
|
100
|
+
// decision words. Past the number positional, tokens are decision words even when one
|
|
101
|
+
// is spelled `--json`: unquoted decision prose (`questions answer 1 keep --json output`)
|
|
102
|
+
// reaches the command as separate argv tokens, and a flag scan that matched `--json`
|
|
103
|
+
// anywhere silently ate the token out of the recorded decision and flipped the command
|
|
104
|
+
// into JSON mode. Unknown `--`-prefixed tokens stay refused even there, so a misspelled
|
|
105
|
+
// flag is still an error rather than silent decision text.
|
|
106
|
+
const words = [];
|
|
107
|
+
let jsonFlag = false;
|
|
108
|
+
let numbered = false;
|
|
109
|
+
let file;
|
|
110
|
+
let answeredFlag = false;
|
|
111
|
+
let limit;
|
|
112
|
+
let grep;
|
|
113
|
+
let show;
|
|
114
|
+
for (let i = 0; i < args.length; i++) {
|
|
115
|
+
const arg = args[i];
|
|
116
|
+
if (!numbered && arg === "--show") {
|
|
117
|
+
rejectRepeatFlag(show !== undefined, "--show");
|
|
118
|
+
show = parsePositionFlag("--show", args[++i], "--show 2");
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (!numbered && arg === "--answered") {
|
|
122
|
+
rejectRepeatFlag(answeredFlag, "--answered");
|
|
123
|
+
answeredFlag = true;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (!numbered && arg === "-n") {
|
|
127
|
+
rejectRepeatFlag(limit !== undefined, "-n");
|
|
128
|
+
limit = parseCountFlag("-n", args[++i]);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (!numbered && arg === "--grep") {
|
|
132
|
+
rejectRepeatFlag(grep !== undefined, "--grep");
|
|
133
|
+
const text = args[++i];
|
|
134
|
+
if (text === undefined || text === "")
|
|
135
|
+
fail("--grep needs text (usage: tumwater questions [--answered] --grep <text>)");
|
|
136
|
+
grep = text;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (arg === "--file") {
|
|
140
|
+
rejectRepeatFlag(file !== undefined, "--file");
|
|
141
|
+
file = promptFileValue(args[++i]);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!numbered && arg === "--json") {
|
|
145
|
+
rejectRepeatFlag(jsonFlag, "--json");
|
|
146
|
+
jsonFlag = true;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (arg.startsWith("--") && arg !== "--json") {
|
|
150
|
+
rejectEqualsForm(arg, [JSON_FLAG, FILE_SPEC, { names: ["--show"], value: true, valueName: "<n>" }, { names: ["--grep"], value: true, valueName: "<text>" }]);
|
|
151
|
+
fail(`unknown argument: ${arg} (valid flags for tumwater questions: --json, --file, --answered, --show, --grep)`);
|
|
152
|
+
}
|
|
153
|
+
if (!numbered) {
|
|
154
|
+
// The position is a plain-decimal positive integer (parsePositiveInt's rule, the same
|
|
155
|
+
// one --cancel's position honors): bare Number() admitted hex ("0x2"), exponent
|
|
156
|
+
// ("1e2"), and whitespace-padded spellings as a valid question number, answering a
|
|
157
|
+
// question the operator never named.
|
|
158
|
+
if (parsePositiveInt(arg) !== null)
|
|
159
|
+
numbered = true;
|
|
160
|
+
}
|
|
161
|
+
words.push(arg);
|
|
162
|
+
}
|
|
163
|
+
if (limit !== undefined && !answeredFlag)
|
|
164
|
+
fail("-n needs --answered (it limits the answered questions listed)");
|
|
165
|
+
refuseTeamWorkspace(root);
|
|
166
|
+
if (show !== undefined) {
|
|
167
|
+
if (grep !== undefined)
|
|
168
|
+
fail("--grep does not apply to --show");
|
|
169
|
+
if (words.length > 0)
|
|
170
|
+
fail("--show prints one open question; it takes no subcommand");
|
|
171
|
+
if (file !== undefined)
|
|
172
|
+
fail("--file only applies to questions answer <n>");
|
|
173
|
+
if (answeredFlag) {
|
|
174
|
+
if (limit !== undefined)
|
|
175
|
+
fail("-n does not apply to --show");
|
|
176
|
+
const a = answeredQuestionAt(root, show);
|
|
177
|
+
if (a === null) {
|
|
178
|
+
const count = answeredQuestionCount(root);
|
|
179
|
+
const range = count > 0 ? ` — valid: 1-${count}` : "";
|
|
180
|
+
fail(`no answered question at position ${show} (${count} in QUESTIONS.md)${range}`);
|
|
181
|
+
}
|
|
182
|
+
if (jsonFlag)
|
|
183
|
+
sayJson(a);
|
|
184
|
+
else
|
|
185
|
+
say(renderShownQuestion(a));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const q = openQuestionAt(root, show);
|
|
189
|
+
if (q === null) {
|
|
190
|
+
const count = questionListPayload(root).questions.length;
|
|
191
|
+
const range = count > 0 ? ` — valid: 1-${count}` : "";
|
|
192
|
+
fail(`no open question at position ${show} (${count} in QUESTIONS.md)${range}`);
|
|
193
|
+
}
|
|
194
|
+
if (jsonFlag)
|
|
195
|
+
sayJson(q);
|
|
196
|
+
else
|
|
197
|
+
say(renderShownQuestion(q));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (answeredFlag) {
|
|
201
|
+
if (words.length > 0)
|
|
202
|
+
fail("--answered lists answered questions; it takes no subcommand");
|
|
203
|
+
if (file !== undefined)
|
|
204
|
+
fail("--file only applies to questions answer <n>");
|
|
205
|
+
if (jsonFlag)
|
|
206
|
+
sayJson(answeredQuestionPayload(root, limit ?? 10, grep));
|
|
207
|
+
else
|
|
208
|
+
say(answeredQuestionList(root, limit ?? 10, grep));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (words.length === 0 && file !== undefined)
|
|
212
|
+
fail("--file only applies to questions answer <n>");
|
|
213
|
+
if (words.length === 0) {
|
|
214
|
+
sayQuestionList(root, jsonFlag, grep);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (grep !== undefined)
|
|
218
|
+
fail("--grep only applies to listing questions");
|
|
219
|
+
if (words[0] !== "answer")
|
|
220
|
+
fail(`unknown questions subcommand: ${words[0]} (use "answer <n> <decision>", or run \`tumwater questions\` with no subcommand to list them)${typoSuffix(words[0], ["answer"])}`);
|
|
221
|
+
// The offending token carries the same ` (got "...")` suffix every sibling number parser
|
|
222
|
+
// adds (parsePositiveInt's flag callers, --cancel); the bare `answer` form names none.
|
|
223
|
+
const raw = words.length > 1 ? words[1] : undefined;
|
|
224
|
+
const n = raw === undefined ? null : parsePositiveInt(raw);
|
|
225
|
+
if (n === null)
|
|
226
|
+
fail(`questions answer needs a positive question number: questions answer <n> "<decision>"${gotSuffix(raw)}`);
|
|
227
|
+
if (file !== undefined) {
|
|
228
|
+
if (words.length > 2)
|
|
229
|
+
fail(`unexpected argument ${JSON.stringify(words[2])} — with --file the decision comes from the file`);
|
|
230
|
+
const answered = answerQuestionFromText(root, n, readPromptFileArg(file));
|
|
231
|
+
await commitAndReportAnswer(root, n, jsonFlag, answered.title, answered.decision);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const decision = words.slice(2).join(" ").trim();
|
|
235
|
+
if (words.length === 2) {
|
|
236
|
+
const open = questionListPayload(root).questions;
|
|
237
|
+
const question = open[n - 1];
|
|
238
|
+
if (question === undefined) {
|
|
239
|
+
const range = open.length > 0 ? ` — valid: 1-${open.length}` : "";
|
|
240
|
+
fail(`no question at position ${n} (${open.length} open)${range}`);
|
|
241
|
+
}
|
|
242
|
+
const edited = decisionFromEditorBuffer(editInEditor(answerEditorBuffer(question.title, question.body), `answer-${n}.md`, "pass a decision or --file <path>"));
|
|
243
|
+
if (edited.trim() === "")
|
|
244
|
+
fail("questions answer needs a decision: the editor left it blank; nothing changed");
|
|
245
|
+
const answered = answerQuestionFromText(root, n, edited, question.title);
|
|
246
|
+
await commitAndReportAnswer(root, n, jsonFlag, answered.title, answered.decision);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (decision === "")
|
|
250
|
+
fail('questions answer needs a decision: questions answer <n> "<decision>"');
|
|
251
|
+
// answerQuestion collapses the free-form decision to one line before writing it; report
|
|
252
|
+
// that written text in the --json payload so it matches the file, not the caller's spacing.
|
|
253
|
+
const { title, decision: writtenDecision } = answerQuestion(root, n, decision);
|
|
254
|
+
await commitAndReportAnswer(root, n, jsonFlag, title, writtenDecision);
|
|
255
|
+
}
|
|
256
|
+
/** Commit the answered question, report it in the requested output mode, and wake the
|
|
257
|
+
* asking role in prose mode — the tail every `questions answer` branch ends with. */
|
|
258
|
+
async function commitAndReportAnswer(root, n, jsonFlag, title, decision) {
|
|
259
|
+
warnIfUncommitted(await commitOperatorBacklogEdit(root, "QUESTIONS.md", stampedSubject("operator", `Answer question: ${title}`)), "QUESTIONS.md"); // vocabulary-ok: commit prefix stays
|
|
260
|
+
sayAnswered(n, title, jsonFlag, decision);
|
|
261
|
+
if (!jsonFlag)
|
|
262
|
+
sayAskerWake(root, title);
|
|
263
|
+
}
|
|
264
|
+
/** Prose-mode follow-up to `questions answer`: wake the asking role and print the confirmation. */
|
|
265
|
+
function sayAskerWake(root, title) {
|
|
266
|
+
const wake = wakeQuestionAsker(root, title);
|
|
267
|
+
if (wake !== null)
|
|
268
|
+
say(wake);
|
|
74
269
|
}
|
package/dist/src/cli.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// vocabulary: plain
|
|
3
2
|
/** The CLI's entry point and command dispatcher — the `bin` target package.json points at
|
|
4
3
|
* (dist/src/cli.js). main() runs the Node-floor gate from package.json's `engines.node`, answers a
|
|
5
4
|
* `--help` topic before any command parses arguments or gates on a ready repo, resolves the repo
|
|
@@ -13,33 +12,48 @@
|
|
|
13
12
|
* modules; this file owns the shared sequence, including each case's flag rejection and its
|
|
14
13
|
* ready-repo gate. An error escaping main() funnels through its catch to fail(errorMessage(err)),
|
|
15
14
|
* the CLI's one error path. */
|
|
16
|
-
import { parseCountFlag, } from "./cli/cli-args.js";
|
|
17
|
-
import { grepFlagSpec, GUI_FLAG_SPECS, JSON_FLAG, LAST_FLAG, N_FLAG, rejectUnknownArgs, resultFlagSpec, ROLE_FLAG,
|
|
15
|
+
import { parseCountFlag, parseGrepFlag, parseModelFlag, parseResultFlag } from "./cli/cli-args.js";
|
|
16
|
+
import { grepFlagSpec, GUI_FLAG_SPECS, JSON_FLAG, LAST_FLAG, N_FLAG, rejectUnknownArgs, resultFlagSpec, modelFlagSpec, byFlagSpec, LOGS_TRANSCRIPT_FLAG, ROLE_FLAG, START_FLAG_SPECS, sinceFlagSpec, untilFlagSpec, STAT_FLAG, PATCH_FLAG, PROMPT_FLAG, TRANSCRIPT_FLAG, SUMMARY_FLAG, COUNT_FLAG, typeFlagSpec, DRY_RUN_FLAG, FORCE_FLAG, FOLLOW_FLAG, STOP_CANCEL_FLAG, STOP_IN_FLAG, REPROBE_FLAG, PROBLEMS_FLAG, KILL_ORPHANS_FLAG, } from "./cli/cli-flag-specs.js";
|
|
18
17
|
import { fail, say, sayJsonOrRender } from "./cli/cli-output.js";
|
|
19
|
-
import { historyTrailForm, parsePromptArgs, peelPositionals } from "./cli/cli-command-args.js";
|
|
20
|
-
import { requireReadyRepo } from "./cli/cli-repo-gate.js";
|
|
18
|
+
import { historyTrailForm, parseDoctorChecks, parsePromptArgs, peelPositionals } from "./cli/cli-command-args.js";
|
|
19
|
+
import { refuseTeamWorkspace, requireReadyRepo } from "./cli/cli-repo-gate.js";
|
|
21
20
|
import { repoToplevel } from "./git/git.js";
|
|
22
21
|
import { didYouMean } from "./text/suggest.js";
|
|
23
22
|
import { errorMessage, gotSuffix, stripTerminalControls } from "./text/text.js";
|
|
24
23
|
import { typoSuffix } from "./text/suggest.js";
|
|
25
|
-
import { completionConfigKeys, completionRoleIds, completionScript, SUPPORTED_SHELLS } from "./cli/completion.js";
|
|
24
|
+
import { completionConfigKeys, completionModels, completionRoleIds, completionScript, configValueWords, SUPPORTED_SHELLS } from "./cli/completion.js";
|
|
26
25
|
import { HELP, helpTopic, helpTopicForArgs, suggestCommand } from "./cli/help.js";
|
|
27
26
|
import { PACKAGE_JSON, nodeFloorProblem, packageEnginesNode, packageVersion } from "./version.js";
|
|
28
27
|
// The CLI's help text and its per-command topic parser live in help.ts — importing cli.ts
|
|
29
28
|
// would run main(), so tests pin the topics against help.ts directly.
|
|
30
29
|
/** One run's trail, shared by `history <role> <n>` and its hidden alias `tick` so the two cannot
|
|
31
30
|
* drift. Positional-first: the <role> <n> tokens peel off and the remaining flags go through
|
|
32
|
-
* rejectUnknownArgs (only --json, --last, --stat
|
|
31
|
+
* rejectUnknownArgs (only --json, --last, --stat, --patch, --transcript, --prompt, --grep,
|
|
32
|
+
* --result, --model), so a listing flag such as --role is refused.
|
|
33
33
|
* Arity is gated before the ready-repo check so a malformed call fails with its usage in any
|
|
34
|
-
* directory;
|
|
34
|
+
* directory; cmdRunDetail owns the value validation and the --last/numbered rivals. */
|
|
35
35
|
async function runTrailCommand(root, args) {
|
|
36
|
-
const {
|
|
37
|
-
const {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
const { cmdRunDetail, RUN_DETAIL_USAGE } = await import("./run/run-detail.js");
|
|
37
|
+
const { HISTORY_GREP_VALUE_ERROR, HISTORY_RESULT_VALUE_ERROR, HISTORY_MODEL_VALUE_ERROR } = await import("./history/history.js");
|
|
38
|
+
// parseGrepFlag removes the pattern token, so `--grep two` cannot read "two" as a positional.
|
|
39
|
+
const { rest: ungrepped, pattern: grep } = parseGrepFlag(args, HISTORY_GREP_VALUE_ERROR);
|
|
40
|
+
const { rest: unresulted, raw: result } = parseResultFlag(ungrepped, HISTORY_RESULT_VALUE_ERROR);
|
|
41
|
+
const { rest: unmodeled, raw: model } = parseModelFlag(unresulted, HISTORY_MODEL_VALUE_ERROR);
|
|
42
|
+
const { positionals, rest } = peelPositionals(unmodeled);
|
|
43
|
+
rejectUnknownArgs("history", rest, [JSON_FLAG, LAST_FLAG, STAT_FLAG, PATCH_FLAG, TRANSCRIPT_FLAG, PROMPT_FLAG, { names: ["--grep"] }, { names: ["--result"] }, { names: ["--model"] }]);
|
|
44
|
+
if ((positionals.length < 1 && !rest.includes("--last")) || positionals.length > 2)
|
|
45
|
+
fail(`usage: ${RUN_DETAIL_USAGE}`);
|
|
41
46
|
await requireReadyRepo(root);
|
|
42
|
-
await
|
|
47
|
+
await cmdRunDetail(root, positionals, rest.includes("--json"), {
|
|
48
|
+
last: rest.includes("--last"),
|
|
49
|
+
stat: rest.includes("--stat"),
|
|
50
|
+
patch: rest.includes("--patch"),
|
|
51
|
+
transcript: rest.includes("--transcript"),
|
|
52
|
+
prompt: rest.includes("--prompt"),
|
|
53
|
+
grep,
|
|
54
|
+
result,
|
|
55
|
+
model,
|
|
56
|
+
});
|
|
43
57
|
}
|
|
44
58
|
async function main() {
|
|
45
59
|
const [, , command, ...args] = process.argv;
|
|
@@ -72,16 +86,16 @@ async function main() {
|
|
|
72
86
|
const root = (await repoToplevel(process.cwd())) ?? process.cwd();
|
|
73
87
|
switch (command) {
|
|
74
88
|
case "init":
|
|
75
|
-
// Imported lazily: cli/cli-
|
|
89
|
+
// Imported lazily: cli/cli-start.ts pulls the whole team-booting subgraph (orchestrator,
|
|
76
90
|
// supervisor, redeploy, launch-services — the run path's machinery), and every other
|
|
77
91
|
// command's spawn pays module compilation for it unless the dispatch defers that load
|
|
78
|
-
// to the commands that actually boot or serve a team.
|
|
79
|
-
await (await import("./cli/cli-
|
|
92
|
+
// to the commands that actually boot or serve a team. cli-init.ts stays light for init.
|
|
93
|
+
await (await import("./cli/cli-init.js")).cmdInit(root, args);
|
|
80
94
|
break;
|
|
81
95
|
case "start":
|
|
82
96
|
case "run":
|
|
83
|
-
rejectUnknownArgs("start", args,
|
|
84
|
-
await (await import("./cli/cli-
|
|
97
|
+
rejectUnknownArgs("start", args, START_FLAG_SPECS);
|
|
98
|
+
await (await import("./cli/cli-start.js")).cmdStart(root, args);
|
|
85
99
|
break;
|
|
86
100
|
case "tui":
|
|
87
101
|
rejectUnknownArgs("tui", args, []);
|
|
@@ -108,7 +122,10 @@ async function main() {
|
|
|
108
122
|
// args.
|
|
109
123
|
if (args.length > 0) {
|
|
110
124
|
if (args[0] !== "get" && args[0] !== "set" && args[0] !== "unset")
|
|
111
|
-
|
|
125
|
+
// A near-miss subcommand word gets the same typoSuffix `completion <shell>` and
|
|
126
|
+
// `logs --type` give, so `config gte` reads "did you mean `get`?" while a far-off
|
|
127
|
+
// word (`show`) and a flag (`--anything`) stay hint-free.
|
|
128
|
+
fail(`${CONFIG_USAGE}${typoSuffix(args[0] ?? "", ["get", "set", "unset"])}`);
|
|
112
129
|
if (args[0] === "get" && args.length !== 2)
|
|
113
130
|
fail("usage: tumwater config get <key>");
|
|
114
131
|
if (args[0] === "set" && args.length !== 3)
|
|
@@ -124,7 +141,8 @@ async function main() {
|
|
|
124
141
|
}
|
|
125
142
|
case "report": {
|
|
126
143
|
// No requireReadyRepo gate: the report aggregates files that degrade to zeros when
|
|
127
|
-
// missing, so it runs (and prints an all-zero window) in any directory
|
|
144
|
+
// missing, so it runs (and prints an all-zero window) in any directory; the team-workspace
|
|
145
|
+
// refusal still applies.
|
|
128
146
|
rejectUnknownArgs("report", args, [
|
|
129
147
|
{
|
|
130
148
|
names: ["--days"],
|
|
@@ -138,9 +156,12 @@ async function main() {
|
|
|
138
156
|
},
|
|
139
157
|
{ names: ["--failures"] },
|
|
140
158
|
sinceFlagSpec("report --since"),
|
|
159
|
+
untilFlagSpec("report --until"),
|
|
141
160
|
JSON_FLAG,
|
|
142
161
|
ROLE_FLAG,
|
|
162
|
+
FOLLOW_FLAG,
|
|
143
163
|
]);
|
|
164
|
+
refuseTeamWorkspace(root);
|
|
144
165
|
// --since is handled before the day-shape reads: it is a rival shape (totals over a
|
|
145
166
|
// trailing window vs a series over whole days), not a modifier of either.
|
|
146
167
|
await (await import("./report/report.js")).cmdReport(root, args);
|
|
@@ -149,23 +170,38 @@ async function main() {
|
|
|
149
170
|
case "doctor": {
|
|
150
171
|
// No requireReadyRepo gate: doctor's job is to report WHY the environment isn't ready,
|
|
151
172
|
// so it must run outside a git repo and print fail lines rather than throwing.
|
|
152
|
-
|
|
173
|
+
const { positionals: checkNames, rest: doctorFlags } = peelPositionals(args);
|
|
174
|
+
rejectUnknownArgs("doctor", doctorFlags, [JSON_FLAG, REPROBE_FLAG, PROBLEMS_FLAG, KILL_ORPHANS_FLAG]);
|
|
175
|
+
const only = parseDoctorChecks(checkNames);
|
|
153
176
|
const { runDoctor } = await import("./doctor/doctor.js");
|
|
177
|
+
let orphanKill;
|
|
178
|
+
if (args.includes("--kill-orphans")) {
|
|
179
|
+
const { killOrphans, orphanKillLines } = await import("./doctor/doctor-orphans.js");
|
|
180
|
+
orphanKill = await killOrphans(root);
|
|
181
|
+
// The text form prints the kill before the report; --json keeps stdout one document.
|
|
182
|
+
if (!args.includes("--json")) {
|
|
183
|
+
for (const line of orphanKillLines(orphanKill))
|
|
184
|
+
say(line);
|
|
185
|
+
say("");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
154
188
|
const { renderDoctor, renderDoctorProblems, problemsOnly } = await import("./doctor/doctor-render.js");
|
|
155
189
|
// The terminal probes unclaimed-verified models by default (7-day cache); --reprobe
|
|
156
190
|
// forces every claimed model. The TUI/GUI call runDoctor with the default "never", so a
|
|
157
191
|
// refresh never spends a model call.
|
|
158
192
|
const probeImages = args.includes("--reprobe") ? "all" : "missing";
|
|
159
|
-
const report = await runDoctor(root, undefined, undefined, probeImages);
|
|
193
|
+
const report = await runDoctor(root, undefined, undefined, probeImages, only);
|
|
160
194
|
// --json prints the collector's own payload (the DoctorReport object), not a re-parse of
|
|
161
195
|
// the render — the `report --json` precedent. The exit-code contract below holds in both
|
|
162
196
|
// forms: 1 when any check fails, 0 otherwise; warnings never fail the exit.
|
|
163
197
|
// --problems keeps the full report for the render (it counts the hidden ok rows) and
|
|
164
198
|
// hands --json the filtered one; the exit code below reads the full report either way.
|
|
199
|
+
// --kill-orphans adds the kill result to the JSON object as `orphanKill`.
|
|
200
|
+
const withKill = (payload) => (orphanKill === undefined ? payload : { ...payload, orphanKill });
|
|
165
201
|
if (args.includes("--problems"))
|
|
166
|
-
sayJsonOrRender(args, args.includes("--json") ? problemsOnly(report) : report, renderDoctorProblems);
|
|
202
|
+
sayJsonOrRender(args, args.includes("--json") ? withKill(problemsOnly(report)) : report, renderDoctorProblems);
|
|
167
203
|
else
|
|
168
|
-
sayJsonOrRender(args, report, renderDoctor);
|
|
204
|
+
sayJsonOrRender(args, args.includes("--json") ? withKill(report) : report, renderDoctor);
|
|
169
205
|
if (report.checks.some((c) => c.level === "fail"))
|
|
170
206
|
process.exitCode = 1; // Warnings never fail the exit.
|
|
171
207
|
break;
|
|
@@ -173,15 +209,17 @@ async function main() {
|
|
|
173
209
|
case "logs": {
|
|
174
210
|
const { cmdLogs, GREP_VALUE_ERROR, TYPE_VALUE_ERROR } = await import("./cli/log-commands.js");
|
|
175
211
|
rejectUnknownArgs("logs", args, [
|
|
176
|
-
|
|
212
|
+
FOLLOW_FLAG,
|
|
177
213
|
N_FLAG,
|
|
178
214
|
sinceFlagSpec("logs --since"),
|
|
215
|
+
untilFlagSpec("logs --until"),
|
|
179
216
|
grepFlagSpec(GREP_VALUE_ERROR),
|
|
180
217
|
typeFlagSpec(TYPE_VALUE_ERROR),
|
|
181
218
|
JSON_FLAG,
|
|
182
219
|
COUNT_FLAG,
|
|
183
220
|
ROLE_FLAG,
|
|
184
|
-
|
|
221
|
+
LOGS_TRANSCRIPT_FLAG,
|
|
222
|
+
PROMPT_FLAG,
|
|
185
223
|
]);
|
|
186
224
|
await requireReadyRepo(root);
|
|
187
225
|
await cmdLogs(root, args);
|
|
@@ -193,16 +231,20 @@ async function main() {
|
|
|
193
231
|
await (await import("./cli/notify-command.js")).cmdNotify(root, args);
|
|
194
232
|
break;
|
|
195
233
|
case "history": {
|
|
196
|
-
const { cmdHistory, HISTORY_GREP_VALUE_ERROR, HISTORY_RESULT_VALUE_ERROR } = await import("./history/history.js");
|
|
234
|
+
const { cmdHistory, HISTORY_GREP_VALUE_ERROR, HISTORY_RESULT_VALUE_ERROR, HISTORY_MODEL_VALUE_ERROR, HISTORY_BY_VALUE_ERROR } = await import("./history/history.js");
|
|
197
235
|
if (historyTrailForm(args)) {
|
|
198
236
|
await runTrailCommand(root, args);
|
|
199
237
|
break;
|
|
200
238
|
}
|
|
201
239
|
rejectUnknownArgs("history", args, [
|
|
202
240
|
N_FLAG,
|
|
241
|
+
FOLLOW_FLAG,
|
|
203
242
|
sinceFlagSpec("history --since"),
|
|
243
|
+
untilFlagSpec("history --until"),
|
|
204
244
|
grepFlagSpec(HISTORY_GREP_VALUE_ERROR),
|
|
205
245
|
resultFlagSpec(HISTORY_RESULT_VALUE_ERROR),
|
|
246
|
+
modelFlagSpec(HISTORY_MODEL_VALUE_ERROR),
|
|
247
|
+
byFlagSpec(HISTORY_BY_VALUE_ERROR),
|
|
206
248
|
JSON_FLAG,
|
|
207
249
|
ROLE_FLAG,
|
|
208
250
|
SUMMARY_FLAG,
|
|
@@ -224,13 +266,15 @@ async function main() {
|
|
|
224
266
|
await (await import("./cli/cli-query-commands.js")).cmdBacklog(root, args);
|
|
225
267
|
break;
|
|
226
268
|
case "archive":
|
|
227
|
-
rejectUnknownArgs("archive", args, []);
|
|
269
|
+
rejectUnknownArgs("archive", args, [JSON_FLAG]);
|
|
228
270
|
await requireReadyRepo(root);
|
|
229
|
-
await (await import("./backlog/backlog-cli.js")).cmdArchive(root);
|
|
271
|
+
await (await import("./backlog/backlog-cli.js")).cmdArchive(root, args);
|
|
230
272
|
break;
|
|
231
273
|
case "bug": {
|
|
232
|
-
const { OPERATOR_FILE_KINDS, bugWakeText, cancelBug,
|
|
233
|
-
const {
|
|
274
|
+
const { OPERATOR_FILE_KINDS, bugWakeText, cancelBug, editBug, editBugFromText, fileBug, fileBugFromText } = await import("./backlog/backlog-write.js");
|
|
275
|
+
const { moveEntryToTop, releaseEntry } = await import("./backlog/backlog-release.js");
|
|
276
|
+
const { bugTitleOf, cancelAndAnnounce, releaseAndAnnounce, topAndAnnounce, editAndAnnounce, fileAndAnnounce } = await import("./backlog/backlog-cli.js");
|
|
277
|
+
const { listAndAnnounce, showAndAnnounce } = await import("./backlog/backlog-cli-view.js");
|
|
234
278
|
const usage = 'tumwater bug "<symptom>"';
|
|
235
279
|
if (args.includes("--show")) {
|
|
236
280
|
showAndAnnounce(root, args, "bug");
|
|
@@ -260,8 +304,10 @@ async function main() {
|
|
|
260
304
|
break;
|
|
261
305
|
}
|
|
262
306
|
case "plan": {
|
|
263
|
-
const { OPERATOR_FILE_KINDS, cancelPlan,
|
|
264
|
-
const {
|
|
307
|
+
const { OPERATOR_FILE_KINDS, cancelPlan, editPlan, editPlanFromText, filePlan, filePlanFromText, planWakeText } = await import("./backlog/backlog-write.js");
|
|
308
|
+
const { moveEntryToTop, releaseEntry } = await import("./backlog/backlog-release.js");
|
|
309
|
+
const { cancelAndAnnounce, releaseAndAnnounce, topAndAnnounce, editAndAnnounce, fileAndAnnounce, planTitleOf } = await import("./backlog/backlog-cli.js");
|
|
310
|
+
const { listAndAnnounce, showAndAnnounce } = await import("./backlog/backlog-cli-view.js");
|
|
265
311
|
const usage = 'tumwater plan "<title>" [body...]';
|
|
266
312
|
if (args.includes("--show")) {
|
|
267
313
|
showAndAnnounce(root, args, "plan");
|
|
@@ -291,13 +337,13 @@ async function main() {
|
|
|
291
337
|
break;
|
|
292
338
|
}
|
|
293
339
|
case "questions":
|
|
294
|
-
await (await import("./cli/
|
|
340
|
+
await (await import("./cli/question-commands.js")).cmdQuestions(root, args);
|
|
295
341
|
break;
|
|
296
342
|
case "brief":
|
|
297
343
|
await (await import("./cli/brief-command.js")).cmdBrief(root, args);
|
|
298
344
|
break;
|
|
299
345
|
case "role":
|
|
300
|
-
await (await import("./cli/cli-
|
|
346
|
+
await (await import("./cli/cli-role-command.js")).cmdRole(root, args);
|
|
301
347
|
break;
|
|
302
348
|
case "prompt":
|
|
303
349
|
// Parse before the gate: prompt's positionals are free-form, so rejectUnknownArgs
|
|
@@ -336,8 +382,8 @@ async function main() {
|
|
|
336
382
|
break;
|
|
337
383
|
}
|
|
338
384
|
case "revert": {
|
|
339
|
-
// Acts immediately on the primary checkout under the primary-worktree lock; the
|
|
340
|
-
//
|
|
385
|
+
// Acts immediately on the primary checkout under the primary-worktree lock; the
|
|
386
|
+
// positionals (a sha, or a run) are validated inside cmdRevert.
|
|
341
387
|
await requireReadyRepo(root);
|
|
342
388
|
await (await import("./operator/operator-commands.js")).cmdRevert(root, args);
|
|
343
389
|
break;
|
|
@@ -362,12 +408,29 @@ async function main() {
|
|
|
362
408
|
say(key);
|
|
363
409
|
break;
|
|
364
410
|
}
|
|
411
|
+
if (args.length === 2 && args[0] === "--config-value") {
|
|
412
|
+
// The vocabulary `config set <key> <value>` completes for a discrete-valued key
|
|
413
|
+
// (boolean/backend/model/thinking); free-form keys print nothing, so a `set` on one
|
|
414
|
+
// completes nothing instead of offering a wrong vocabulary.
|
|
415
|
+
for (const word of configValueWords(args[1]))
|
|
416
|
+
say(word);
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
if (args.length === 1 && args[0] === "--models") {
|
|
420
|
+
for (const m of completionModels(root))
|
|
421
|
+
say(m);
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
365
424
|
const shell = args[0];
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
fail(
|
|
425
|
+
// A wrong word count names the count, not a bad shell. A single near-miss shell word gets
|
|
426
|
+
// the same typoSuffix `logs --type`/`history --result` give, so `completion zs` reads
|
|
427
|
+
// "did you mean `zsh`?" while a far-off value (`tcsh`) stays hint-free.
|
|
428
|
+
if (args.length === 0)
|
|
429
|
+
fail("completion needs a shell: bash, zsh, or fish");
|
|
430
|
+
if (args.length > 1)
|
|
431
|
+
fail(`completion takes one shell: bash, zsh, or fish (got ${args.length} words: ${args.join(" ")})`);
|
|
432
|
+
if (!SUPPORTED_SHELLS.includes(shell))
|
|
433
|
+
fail(`completion takes one shell: bash, zsh, or fish${gotSuffix(shell)}${typoSuffix(shell ?? "", SUPPORTED_SHELLS)}`);
|
|
371
434
|
say(completionScript(shell));
|
|
372
435
|
break;
|
|
373
436
|
}
|