tumwater 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +42 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +4 -3
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +402 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +246 -55
- package/dist/src/backlog/backlog-cli-view.js +280 -0
- package/dist/src/backlog/backlog-cli.js +85 -274
- package/dist/src/backlog/backlog-commit.js +4 -5
- package/dist/src/backlog/backlog-eligibility.js +175 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +254 -0
- package/dist/src/backlog/backlog-release.js +117 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-culprit.js +94 -0
- package/dist/src/baseline/main-guardrails.js +209 -0
- package/dist/src/baseline/main-red.js +139 -32
- package/dist/src/baseline/main-revert.js +133 -0
- package/dist/src/baseline/main-watch.js +184 -0
- package/dist/src/brief/brief-edit.js +9 -11
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget.js +30 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +1 -2
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +118 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +150 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +308 -590
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-role-command.js +420 -0
- package/dist/src/cli/cli-start-summary.js +160 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
- package/dist/src/cli/completion.js +149 -22
- package/dist/src/cli/config-commands.js +41 -18
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +189 -73
- package/dist/src/cli/log-commands.js +148 -82
- package/dist/src/cli/question-commands.js +205 -10
- package/dist/src/cli.js +106 -43
- package/dist/src/collections.js +26 -10
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +13 -1
- package/dist/src/config/config-fallbacks.js +93 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +141 -199
- package/dist/src/config/config-views.js +127 -53
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +131 -264
- package/dist/src/config/config.js +48 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
- package/dist/src/doctor/doctor-backlog-plans.js +263 -0
- package/dist/src/doctor/doctor-backlog.js +100 -496
- package/dist/src/doctor/doctor-check-names.js +81 -0
- package/dist/src/doctor/doctor-checks.js +52 -579
- package/dist/src/doctor/doctor-claude-checks.js +145 -0
- package/dist/src/doctor/doctor-codex-checks.js +279 -0
- package/dist/src/doctor/doctor-contention-checks.js +380 -0
- package/dist/src/doctor/doctor-holds.js +82 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +236 -402
- package/dist/src/doctor/doctor-notify.js +3 -4
- package/dist/src/doctor/doctor-opencode-checks.js +162 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-project-checks.js +303 -0
- package/dist/src/doctor/doctor.js +121 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +7 -11
- package/dist/src/events/event-format.js +181 -86
- package/dist/src/events/event-labels.js +12 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +39 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +60 -24
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +56 -56
- package/dist/src/failure/failure-render.js +31 -23
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +99 -35
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +177 -84
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +108 -58
- package/dist/src/gates/maintenance-quota.js +10 -13
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +77 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +36 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +42 -18
- package/dist/src/gui/gui-backlog-endpoints.js +155 -0
- package/dist/src/gui/gui-command.js +8 -13
- package/dist/src/gui/gui-config-commands.js +94 -72
- package/dist/src/gui/gui-endpoint-commands.js +4 -3
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +108 -13
- package/dist/src/gui/gui-prompt-commands.js +11 -14
- package/dist/src/gui/gui-report-endpoints.js +90 -0
- package/dist/src/gui/gui-server.js +11 -4
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +147 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +193 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +25 -9
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +81 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +150 -11
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +90 -0
- package/dist/src/merge/merge-queue-render.js +49 -11
- package/dist/src/merge/merge-queue.js +31 -15
- package/dist/src/merge/merge-requeue.js +102 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +33 -11
- package/dist/src/merge/merge-to-main.js +86 -27
- package/dist/src/merge/merge-top.js +69 -0
- package/dist/src/merge/merge-verify.js +12 -10
- package/dist/src/notes-cli.js +30 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +320 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
- package/dist/src/orchestrator/orchestrator.js +128 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +201 -0
- package/dist/src/orchestrator/scheduling-skip.js +185 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +116 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +18 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +121 -211
- package/dist/src/prompt/notes-backlog.js +181 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +129 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +161 -77
- package/dist/src/report/report-fold.js +129 -52
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +133 -64
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +26 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/known-flakes.js +100 -1
- package/dist/src/review/post-merge-review.js +106 -0
- package/dist/src/review/protected-edits.js +4 -5
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +155 -360
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +69 -12
- package/dist/src/roles/role-guidance.js +55 -20
- package/dist/src/roles/role-labels.js +1 -2
- package/dist/src/roles/role-render.js +67 -50
- package/dist/src/roles/role-view.js +59 -47
- package/dist/src/roles/roles.js +31 -31
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/{tick → run}/qa-coverage.js +9 -27
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +179 -0
- package/dist/src/run/run-detail-render.js +98 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +108 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +108 -50
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +91 -56
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +172 -0
- package/dist/src/run/stage-path-checks.js +730 -0
- package/dist/src/{loop → runner}/leftover.js +80 -25
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +202 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +107 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +21 -15
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +102 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +43 -16
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +28 -28
- package/dist/src/status/status-roles.js +39 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +5 -6
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +63 -17
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +57 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +67 -13
- package/dist/src/ui/badges.js +65 -37
- package/dist/src/ui/gui/gui-client-backlog.js +292 -0
- package/dist/src/ui/gui/gui-client-boot.js +32 -26
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
- package/dist/src/ui/gui/gui-client-drawer.js +126 -285
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +434 -67
- package/dist/src/ui/gui/gui-client-labels.js +1 -2
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +55 -51
- package/dist/src/ui/gui/gui-client-pending.js +227 -23
- package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
- package/dist/src/ui/gui/gui-client-report.js +87 -427
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +56 -4
- package/dist/src/ui/gui/gui-client-team.js +25 -465
- package/dist/src/ui/gui/gui-client.js +27 -25
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +9 -7
- package/dist/src/ui/gui/gui-styles.js +34 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +136 -49
- package/dist/src/ui/status-render.js +101 -82
- package/dist/src/ui/team-alerts.js +248 -57
- package/dist/src/ui/tone.js +5 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +51 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +3 -5
- package/dist/src/ui/tui/tui-editor-backends.js +132 -0
- package/dist/src/ui/tui/tui-editor-brief.js +10 -12
- package/dist/src/ui/tui/tui-editor-budget.js +35 -31
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
- package/dist/src/ui/tui/tui-editor-config.js +86 -0
- package/dist/src/ui/tui/tui-editor-entry.js +36 -47
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +37 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
- package/dist/src/ui/tui/tui-editor-interval.js +11 -9
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +3 -5
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +99 -35
- package/dist/src/ui/tui/tui-editor-retire.js +4 -6
- package/dist/src/ui/tui/tui-editor-role-key.js +76 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +60 -34
- package/dist/src/ui/tui/tui-editor-slots.js +23 -0
- package/dist/src/ui/tui/tui-editors.js +35 -2
- package/dist/src/ui/tui/tui-frame.js +56 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +24 -9
- package/dist/src/ui/tui/tui-pane-activity.js +14 -11
- package/dist/src/ui/tui/tui-pane-backlog.js +171 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +58 -8
- package/dist/src/ui/tui/tui-pane-history.js +402 -82
- package/dist/src/ui/tui/tui-pane-pending.js +308 -13
- package/dist/src/ui/tui/tui-pane-queued.js +71 -55
- package/dist/src/ui/tui/tui-pane-report.js +46 -14
- package/dist/src/ui/tui/tui-pane-session.js +25 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +80 -23
- package/dist/src/ui/tui/tui-panes.js +100 -30
- package/dist/src/ui/tui/tui.js +14 -14
- package/dist/src/verdict/fix-claim.js +82 -32
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +42 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** Shell completion derived from the help text. The spec is parsed from the same HELP stanzas
|
|
3
2
|
* `tumwater help <command>` and the unknown-command suggestion use, so a new command or flag
|
|
4
3
|
* completes the moment it gains a help stanza and can never drift from the listing. */
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { DOTTED_MAP_KEYS } from "../config/config-keys.js";
|
|
8
|
-
import {
|
|
4
|
+
import { customRoleNames, knownRoleIds, loadConfig } from "../config/config.js";
|
|
5
|
+
import { BACKEND_IDS, BACKEND_KEYS, CLAUDE_AGENT_KEYS, CODEX_BACKEND_KEYS, MODEL_TIERS, ROLE_ENTRY_KEYS, THINKING_LEVELS, TOP_LEVEL_KEYS } from "../config/config-schema.js";
|
|
6
|
+
import { DOTTED_MAP_KEYS, DOTTED_SECTION_FIELDS } from "../config/config-keys.js";
|
|
7
|
+
import { compareCodeUnits } from "../collections.js";
|
|
8
|
+
import { HISTORY_MAX_RUNS, HISTORY_RESULT_FLAG_NAMES, HISTORY_SUMMARY_GROUPS, readRunRows } from "../history/history-data.js";
|
|
9
9
|
import { templateIds } from "../init/init-templates.js";
|
|
10
|
+
import { DOCTOR_CHECK_NAMES } from "../doctor/doctor-check-names.js";
|
|
10
11
|
import { allRoleIds } from "../roles/roles.js";
|
|
11
12
|
import { EVENT_TYPE_LABELS } from "../events/event-labels.js";
|
|
12
13
|
import { HELP, helpStanzas } from "./help.js";
|
|
@@ -14,7 +15,7 @@ export const SUPPORTED_SHELLS = ["bash", "zsh", "fish"];
|
|
|
14
15
|
/** The completable words of a stanza's usage part: the text after `tumwater <command>` up to the
|
|
15
16
|
* description column (two or more spaces). Bare lowercase words count inside `[...]` and as the
|
|
16
17
|
* leading run directly after the command; outside brackets the first other token ends the run, so
|
|
17
|
-
* a single-space description (`role <id> --clear-notes Clear that
|
|
18
|
+
* a single-space description (`role <id> --clear-notes Clear that notes`) adds nothing. */
|
|
18
19
|
function usageWords(firstLine, command) {
|
|
19
20
|
const rest = firstLine.replace(new RegExp(`^ {2}tumwater ${command}`), "");
|
|
20
21
|
// Usage arguments follow the command after a single space; two or more spaces start the
|
|
@@ -66,7 +67,7 @@ export function completionSpec(help = HELP) {
|
|
|
66
67
|
}
|
|
67
68
|
return { commands, subcommands, flags };
|
|
68
69
|
}
|
|
69
|
-
/** The ids `--role` completes: this repo's
|
|
70
|
+
/** The ids `--role` completes: this repo's role ids, or the built-in catalog when tumwater.json is
|
|
70
71
|
* unreadable (a broken config must not write errors into the operator's prompt). */
|
|
71
72
|
export function completionRoleIds(root) {
|
|
72
73
|
try {
|
|
@@ -76,14 +77,29 @@ export function completionRoleIds(root) {
|
|
|
76
77
|
return allRoleIds();
|
|
77
78
|
}
|
|
78
79
|
}
|
|
80
|
+
/** The selectors `history --model` completes: the distinct models recent runs started on, in the
|
|
81
|
+
* order `history --summary --by model` lists them. An unreadable or absent log must not write
|
|
82
|
+
* errors into the operator's prompt, and outside a repo it prints nothing. */
|
|
83
|
+
export function completionModels(root) {
|
|
84
|
+
try {
|
|
85
|
+
const models = new Set();
|
|
86
|
+
for (const row of readRunRows(root, HISTORY_MAX_RUNS, null))
|
|
87
|
+
if (row.model !== null)
|
|
88
|
+
models.add(row.model);
|
|
89
|
+
return [...models].sort(compareCodeUnits);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
79
95
|
/** The keys `config get|set|unset` complete: every form parseConfigKey accepts, with the
|
|
80
|
-
* role-scoped keys of this repo's base roles and custom
|
|
96
|
+
* role-scoped keys of this repo's base roles and custom roles (not instance ids like
|
|
81
97
|
* `feature-2`). A broken tumwater.json falls back to the built-in catalog rather than writing
|
|
82
98
|
* errors into the prompt. */
|
|
83
99
|
export function completionConfigKeys(root) {
|
|
84
100
|
let roleIds;
|
|
85
101
|
try {
|
|
86
|
-
roleIds = [...allRoleIds(), ...
|
|
102
|
+
roleIds = [...allRoleIds(), ...customRoleNames(loadConfig(root))];
|
|
87
103
|
}
|
|
88
104
|
catch {
|
|
89
105
|
roleIds = allRoleIds();
|
|
@@ -91,19 +107,64 @@ export function completionConfigKeys(root) {
|
|
|
91
107
|
const keys = [
|
|
92
108
|
...TOP_LEVEL_KEYS,
|
|
93
109
|
...MODEL_TIERS.map((tier) => `model.${tier}`),
|
|
94
|
-
...
|
|
110
|
+
...BACKEND_IDS.flatMap((id) => (id === "claude" ? CLAUDE_AGENT_KEYS : id === "codex" ? CODEX_BACKEND_KEYS : BACKEND_KEYS).map((field) => `backends.${id}.${field}`)),
|
|
95
111
|
...DOTTED_MAP_KEYS.flatMap((map) => roleIds.map((id) => `${map}.${id}`)),
|
|
112
|
+
...Object.entries(DOTTED_SECTION_FIELDS).flatMap(([section, fields]) => fields.map((field) => `${section}.${field}`)),
|
|
96
113
|
...roleIds.flatMap((id) => ROLE_ENTRY_KEYS.map((field) => `roles.${id}.${field}`)),
|
|
97
114
|
];
|
|
98
115
|
return [...new Set(keys)];
|
|
99
116
|
}
|
|
117
|
+
/** The value vocabulary `config set <key> <value>` completes for one key, or [] when the
|
|
118
|
+
* field is free-form. The discrete-valued keys source the SAME closed constants the config
|
|
119
|
+
* validation accepts — BACKEND_IDS for a `.backend` field or the top-level `backend`,
|
|
120
|
+
* MODEL_TIERS for a `.model` field (the tier-name shorthand checkModelTripleField/review
|
|
121
|
+
* allow), THINKING_LEVELS for a `.thinking` field or the top-level `thinking`, and
|
|
122
|
+
* `true|false` for the always-boolean `.enabled` — so a domain changes the moment its
|
|
123
|
+
* constant does. `provider` (top-level, `roles.<id>.provider`, `review.provider`) is a
|
|
124
|
+
* free-form pi provider name, NOT a backend id — the ids validation rejects as the retired
|
|
125
|
+
* backend namespace on the default pi backend — so it completes nothing rather than offering
|
|
126
|
+
* ids that `set` would refuse. Number/free-text values (instances, minRunIntervalSeconds,
|
|
127
|
+
* maxDailyCostUsd, backends' bin/args, a full model id) are not worth a TAB either. The
|
|
128
|
+
* `config set` value-position arm in bashScript shells out here, so the vocabulary lives in
|
|
129
|
+
* exactly one place on every shell. */
|
|
130
|
+
export function configValueWords(key) {
|
|
131
|
+
const dot = key.lastIndexOf(".");
|
|
132
|
+
if (dot < 0) {
|
|
133
|
+
// A dot-less key is a whole top-level key (TOP_LEVEL_KEYS); `backend` and `thinking` are
|
|
134
|
+
// the two discrete-valued ones, the rest are free-form numbers/strings/objects.
|
|
135
|
+
switch (key) {
|
|
136
|
+
case "backend": return [...BACKEND_IDS];
|
|
137
|
+
case "thinking": return [...THINKING_LEVELS];
|
|
138
|
+
default: return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
switch (key.slice(dot + 1)) {
|
|
142
|
+
case "enabled": return ["true", "false"];
|
|
143
|
+
case "backend": return [...BACKEND_IDS];
|
|
144
|
+
case "model": return [...MODEL_TIERS];
|
|
145
|
+
case "thinking": return [...THINKING_LEVELS];
|
|
146
|
+
default: return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Commands whose first positional (word 2) is a role id, so completion offers
|
|
150
|
+
* `tumwater completion --roles` there. */
|
|
151
|
+
const ROLE_POSITIONAL_COMMANDS = ["role", "history", "revert"];
|
|
100
152
|
/** Flags whose value is a file path: completion offers file names after them. */
|
|
101
|
-
const PATH_FLAGS = ["--file", "--attach", "--notes-file", "--instructions-file"];
|
|
153
|
+
const PATH_FLAGS = ["--file", "--attach", "--notes-file", "--instructions-file", "--path"];
|
|
102
154
|
/** The event-type codes `logs --type` filters by: the keys of the labels map, so a new event
|
|
103
155
|
* type completes the moment it gains a label. Sorted for a stable, alphabetical offer of a
|
|
104
156
|
* vocabulary too large to recall offhand — the same reason `--role`, `--template`, and
|
|
105
157
|
* `--result` complete their values. */
|
|
106
158
|
const EVENT_TYPE_CODES = Object.keys(EVENT_TYPE_LABELS).sort();
|
|
159
|
+
/** The pi `--thinking` levels `role <id> --thinking <level>` accepts: the canonical
|
|
160
|
+
* THINKING_LEVELS set, Set spread preserving its insertion order (= the order the
|
|
161
|
+
* role-help and config-field-checks message list them), so `--thinking` completes its
|
|
162
|
+
* vocabulary the way `--type` and `--result` complete theirs. One source, so a new level
|
|
163
|
+
* completes the moment THINKING_LEVELS grows. */
|
|
164
|
+
const THINKING_LEVEL_WORDS = [...THINKING_LEVELS];
|
|
165
|
+
/** The doctor check names, each in plain double quotes, for the scripts to loop over. The names
|
|
166
|
+
* hold no `"`, `$`, backtick or `\`, so plain double quotes are exact; a test pins this. */
|
|
167
|
+
const DOCTOR_CHECK_WORDS = DOCTOR_CHECK_NAMES.map((n) => `"${n}"`).join(" ");
|
|
107
168
|
function bashScript(help) {
|
|
108
169
|
const spec = completionSpec(help);
|
|
109
170
|
const arms = spec.commands.map((command) => {
|
|
@@ -125,12 +186,32 @@ function bashScript(help) {
|
|
|
125
186
|
});
|
|
126
187
|
return [
|
|
127
188
|
`# tumwater completion (generated from \`tumwater help\`)`,
|
|
189
|
+
`# Completes the item after the last comma of a comma-list value, keeping the items before it and dropping those already listed.`,
|
|
190
|
+
`_tumwater_list() {`,
|
|
191
|
+
` local head="" word words=""`,
|
|
192
|
+
` [[ "$2" == *,* ]] && head="\${2%,*},"`,
|
|
193
|
+
` for word in $(printf '%s\\n' "$1"); do`,
|
|
194
|
+
` [[ ",$head" == *",$word,"* ]] || words+="$word "`,
|
|
195
|
+
` done`,
|
|
196
|
+
` COMPREPLY=( $(compgen -P "$head" -W "$words" -- "\${2##*,}") )`,
|
|
197
|
+
`}`,
|
|
128
198
|
`_tumwater() {`,
|
|
129
199
|
` local cur="\${COMP_WORDS[COMP_CWORD]}"`,
|
|
130
200
|
` local prev="\${COMP_WORDS[COMP_CWORD-1]}"`,
|
|
131
201
|
` COMPREPLY=()`,
|
|
132
|
-
` if [ "
|
|
133
|
-
`
|
|
202
|
+
` if [ "\${COMP_WORDS[1]}" = doctor ] && [ "$COMP_CWORD" -ge 2 ] && [[ "$cur" != -* ]]; then`,
|
|
203
|
+
` local word="$cur" quote="" name`,
|
|
204
|
+
` case "$word" in \\"*|\\'*) quote="\${word:0:1}"; word="\${word:1}";; esac`,
|
|
205
|
+
` word="\${word//\\\\/}"`,
|
|
206
|
+
` for name in ${DOCTOR_CHECK_WORDS}; do`,
|
|
207
|
+
` if [[ "$name" == "$word"* ]]; then`,
|
|
208
|
+
` if [ -n "$quote" ]; then COMPREPLY+=("$name"); else COMPREPLY+=("$(printf '%q' "$name")"); fi`,
|
|
209
|
+
` fi`,
|
|
210
|
+
` done`,
|
|
211
|
+
` return 0`,
|
|
212
|
+
` fi`,
|
|
213
|
+
` if [ "$prev" = "--role" ] || { [ "$prev" = "--transcript" ] && [ "\${COMP_WORDS[1]}" = logs ]; } || { [ "$COMP_CWORD" -eq 2 ] && [[ ${ROLE_POSITIONAL_COMMANDS.map((c) => `"\${COMP_WORDS[1]}" == ${c}`).join(" || ")} ]] && [[ "$cur" != -* ]]; }; then`,
|
|
214
|
+
` _tumwater_list "$(tumwater completion --roles 2>/dev/null)" "$cur"`,
|
|
134
215
|
` return 0`,
|
|
135
216
|
` fi`,
|
|
136
217
|
` case "$prev" in ${PATH_FLAGS.join("|")})`,
|
|
@@ -143,17 +224,44 @@ function bashScript(help) {
|
|
|
143
224
|
` return 0`,
|
|
144
225
|
` fi`,
|
|
145
226
|
` if [ "$prev" = "--result" ]; then`,
|
|
146
|
-
`
|
|
227
|
+
` _tumwater_list "${Object.values(HISTORY_RESULT_FLAG_NAMES).join(" ")}" "$cur"`,
|
|
147
228
|
` return 0`,
|
|
148
229
|
` fi`,
|
|
149
230
|
` if [ "$prev" = "--type" ]; then`,
|
|
150
|
-
`
|
|
231
|
+
` _tumwater_list "${EVENT_TYPE_CODES.join(" ")}" "$cur"`,
|
|
232
|
+
` return 0`,
|
|
233
|
+
` fi`,
|
|
234
|
+
` if [ "$prev" = "--thinking" ]; then`,
|
|
235
|
+
` COMPREPLY=( $(compgen -W "${THINKING_LEVEL_WORDS.join(" ")}" -- "$cur") )`,
|
|
236
|
+
` return 0`,
|
|
237
|
+
` fi`,
|
|
238
|
+
` if [ "$prev" = "--by" ]; then`,
|
|
239
|
+
` COMPREPLY=( $(compgen -W "${HISTORY_SUMMARY_GROUPS.join(" ")}" -- "$cur") )`,
|
|
240
|
+
` return 0`,
|
|
241
|
+
` fi`,
|
|
242
|
+
` if [ "$prev" = "--model" ] && [ "\${COMP_WORDS[1]}" = role ]; then`,
|
|
243
|
+
` COMPREPLY=( $(compgen -W "${MODEL_TIERS.join(" ")}" -- "$cur") )`,
|
|
244
|
+
` return 0`,
|
|
245
|
+
` fi`,
|
|
246
|
+
// bash splits at `:`; past a selector's colon `prev` is not --model, so nothing completes.
|
|
247
|
+
// A comma list, like --role, so it completes per item.
|
|
248
|
+
` if [ "$prev" = "--model" ] && [ "\${COMP_WORDS[1]}" = history ]; then`,
|
|
249
|
+
` _tumwater_list "$(tumwater completion --models 2>/dev/null)" "$cur"`,
|
|
151
250
|
` return 0`,
|
|
152
251
|
` fi`,
|
|
153
252
|
` if [ "$COMP_CWORD" -eq 3 ] && [ "\${COMP_WORDS[1]}" = config ] && [[ "\${COMP_WORDS[2]}" == get || "\${COMP_WORDS[2]}" == set || "\${COMP_WORDS[2]}" == unset ]] && [[ "$cur" != -* ]]; then`,
|
|
154
253
|
` COMPREPLY=( $(compgen -W "$(tumwater completion --config-keys 2>/dev/null)" -- "$cur") )`,
|
|
155
254
|
` return 0`,
|
|
156
255
|
` fi`,
|
|
256
|
+
// config set's VALUE sits at word 4, after the key a set write scopes (get/unset take no
|
|
257
|
+
// value, so only set reaches here). It shells out for the key's discrete vocabulary — the
|
|
258
|
+
// dotted fields (roles.<id>.<field>, review.<field>) and the top-level `backend`/`thinking`
|
|
259
|
+
// keys — and resolves to nothing for a free-form value, all decided in configValueWords so
|
|
260
|
+
// the vocabulary lives in exactly one place on every shell.
|
|
261
|
+
` if [ "$COMP_CWORD" -eq 4 ] && [ "\${COMP_WORDS[1]}" = config ] && [ "\${COMP_WORDS[2]}" = set ] && [[ "$cur" != -* ]]; then`,
|
|
262
|
+
` COMPREPLY=( $(compgen -W "$(tumwater completion --config-value "\${COMP_WORDS[3]}" 2>/dev/null)" -- "$cur") )`,
|
|
263
|
+
` return 0`,
|
|
264
|
+
` fi`,
|
|
157
265
|
` if [ "$COMP_CWORD" -eq 1 ]; then`,
|
|
158
266
|
` COMPREPLY=( $(compgen -W "${spec.commands.join(" ")}" -- "$cur") )`,
|
|
159
267
|
` return 0`,
|
|
@@ -167,18 +275,31 @@ function bashScript(help) {
|
|
|
167
275
|
``,
|
|
168
276
|
].join("\n");
|
|
169
277
|
}
|
|
170
|
-
/** The value suffix a fish flag line carries: what completes after the flag.
|
|
171
|
-
|
|
278
|
+
/** The value suffix a fish flag line carries: what completes after the flag. `--role`, `--result`
|
|
279
|
+
* and `--type` take comma lists, so they complete per item through `__fish_complete_list`,
|
|
280
|
+
* skipping the items already listed. */
|
|
281
|
+
function fishFlagValue(command, flag) {
|
|
172
282
|
if (flag === "--role")
|
|
173
|
-
return ` -x -a "(
|
|
283
|
+
return ` -x -a "(__fish_complete_list , __tumwater_roles)"`;
|
|
284
|
+
if (flag === "--transcript" && command === "logs")
|
|
285
|
+
return ` -x -a "(__fish_complete_list , __tumwater_roles)"`;
|
|
174
286
|
if (PATH_FLAGS.includes(flag))
|
|
175
287
|
return ` -r -F`;
|
|
176
288
|
if (flag === "--template")
|
|
177
289
|
return ` -x -a "${templateIds().join(" ")}"`;
|
|
178
290
|
if (flag === "--result")
|
|
179
|
-
return ` -x -a "
|
|
291
|
+
return ` -x -a "(__fish_complete_list , __tumwater_results)"`;
|
|
180
292
|
if (flag === "--type")
|
|
181
|
-
return ` -x -a "
|
|
293
|
+
return ` -x -a "(__fish_complete_list , __tumwater_types)"`;
|
|
294
|
+
if (flag === "--thinking")
|
|
295
|
+
return ` -x -a "${THINKING_LEVEL_WORDS.join(" ")}"`;
|
|
296
|
+
if (flag === "--by")
|
|
297
|
+
return ` -x -a "${HISTORY_SUMMARY_GROUPS.join(" ")}"`;
|
|
298
|
+
// `role --model` completes the closed tier set; `history --model` completes the log's selectors.
|
|
299
|
+
if (flag === "--model" && command === "role")
|
|
300
|
+
return ` -x -a "${MODEL_TIERS.join(" ")}"`;
|
|
301
|
+
if (flag === "--model" && command === "history")
|
|
302
|
+
return ` -x -a "(__fish_complete_list , __tumwater_models)"`;
|
|
182
303
|
return "";
|
|
183
304
|
}
|
|
184
305
|
function fishScript(help) {
|
|
@@ -187,6 +308,12 @@ function fishScript(help) {
|
|
|
187
308
|
`# tumwater completion (generated from \`tumwater help\`)`,
|
|
188
309
|
`complete -c tumwater -f`,
|
|
189
310
|
`function __tumwater_argc; count (commandline -opc); end`,
|
|
311
|
+
`function __tumwater_doctor_checks; printf '%s\\n' ${DOCTOR_CHECK_WORDS}; end`,
|
|
312
|
+
`function __tumwater_unlisted; set -l typed (string split , -- (string match -r '^.*,' -- (commandline -ct))); while read -l word; contains -- $word $typed; or echo $word; end; end`,
|
|
313
|
+
`function __tumwater_roles; tumwater completion --roles 2>/dev/null | __tumwater_unlisted; end`,
|
|
314
|
+
`function __tumwater_results; printf '%s\\n' ${Object.values(HISTORY_RESULT_FLAG_NAMES).join(" ")} | __tumwater_unlisted; end`,
|
|
315
|
+
`function __tumwater_models; tumwater completion --models 2>/dev/null | __tumwater_unlisted; end`,
|
|
316
|
+
`function __tumwater_types; printf '%s\\n' ${EVENT_TYPE_CODES.join(" ")} | __tumwater_unlisted; end`,
|
|
190
317
|
`complete -c tumwater -n __fish_use_subcommand -a "${spec.commands.join(" ")}"`,
|
|
191
318
|
];
|
|
192
319
|
for (const command of spec.commands) {
|
|
@@ -194,9 +321,9 @@ function fishScript(help) {
|
|
|
194
321
|
if (subs.length > 0)
|
|
195
322
|
lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from ${command}; and test (__tumwater_argc) -eq 2" -a "${subs.join(" ")}"`);
|
|
196
323
|
for (const flag of spec.flags[command] ?? [])
|
|
197
|
-
lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from ${command}" -l ${flag.slice(2)}${fishFlagValue(flag)}`);
|
|
324
|
+
lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from ${command}" -l ${flag.slice(2)}${fishFlagValue(command, flag)}`);
|
|
198
325
|
}
|
|
199
|
-
lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from
|
|
326
|
+
lines.push(`complete -c tumwater -n "__fish_seen_subcommand_from ${ROLE_POSITIONAL_COMMANDS.join(" ")}; and test (__tumwater_argc) -eq 2" -a "(tumwater completion --roles 2>/dev/null)"`, `complete -c tumwater -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from get set unset; and test (__tumwater_argc) -eq 3" -a "(tumwater completion --config-keys 2>/dev/null)"`, `complete -c tumwater -n "__fish_seen_subcommand_from config; and __fish_seen_subcommand_from set; and test (__tumwater_argc) -eq 4" -a "(tumwater completion --config-value (commandline -opc)[4] 2>/dev/null)"`, `complete -c tumwater -n "__fish_seen_subcommand_from doctor" -a "(__tumwater_doctor_checks)"`, ``);
|
|
200
327
|
return lines.join("\n");
|
|
201
328
|
}
|
|
202
329
|
export function completionScript(shell, help = HELP) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { loadConfigSafe, knownRoleIds } from "../config/config.js";
|
|
3
2
|
import { fail, say, sayJson, sayJsonLine } from "./cli-output.js";
|
|
4
3
|
import { setConfigKey, unsetConfigKey, } from "../config/config-write.js";
|
|
@@ -9,10 +8,10 @@ import { unknownRoleMessage } from "../roles/roles.js";
|
|
|
9
8
|
/** The `tumwater config` command's CLI layer (split out of operator/operator-commands.ts, which
|
|
10
9
|
* keeps the other operator-command bodies): with no arguments, print the effective merged
|
|
11
10
|
* config — exactly what `loadConfig(root)` returns — as pretty JSON, so an operator
|
|
12
|
-
* debugging scheduling or custom-
|
|
11
|
+
* debugging scheduling or custom-role wiring sees what the team would actually load instead
|
|
13
12
|
* of overlaying defaults onto tumwater.json by hand. A query, not a writer: no redaction (the
|
|
14
13
|
* config holds no secrets — provider keys belong to pi's own env) and no transformation,
|
|
15
|
-
* including the per-role entries custom
|
|
14
|
+
* including the per-role entries custom roles merge into. `get <key>` prints that one key's
|
|
16
15
|
* resolved value (defaults merged in, exactly what the no-arg dump prints) as JSON, failing
|
|
17
16
|
* with the valid top-level keys on an unknown one. An optional key nothing sets (model,
|
|
18
17
|
* provider, fallbackModel, …) prints `null` — JSON's no-value — because JSON.stringify of an
|
|
@@ -28,7 +27,7 @@ import { unknownRoleMessage } from "../roles/roles.js";
|
|
|
28
27
|
/** The config command's malformed-shapes usage line: cli.ts's arity gate fails a non-get/set
|
|
29
28
|
* or wrongly-shaped subcommand with it, and cmdConfig repeats it as the defensive tail for an
|
|
30
29
|
* argument the gate somehow missed. One constant so the synopsis cannot drift between the two
|
|
31
|
-
* sites (mirrors
|
|
30
|
+
* sites (mirrors run-detail.ts's RUN_DETAIL_USAGE). */
|
|
32
31
|
export const CONFIG_USAGE = "usage: tumwater config [get <key> | set <key> <value> | unset <key>] (bare config prints the whole resolved config)";
|
|
33
32
|
/** The key screens `config get` and `config unset` run before resolving or removing a value:
|
|
34
33
|
* the shape parser's own error; the shared unknown-top-level-key message; then, for a dotted
|
|
@@ -64,22 +63,30 @@ function screenOperableKey(root, key) {
|
|
|
64
63
|
}
|
|
65
64
|
return { parsed, config };
|
|
66
65
|
}
|
|
66
|
+
/** The resolved value of one screened key in a loaded config (defaults merged in): what `config
|
|
67
|
+
* get` prints and what `config unset` reports the key now resolves to. Undefined when nothing
|
|
68
|
+
* sets it. */
|
|
69
|
+
function resolvedConfigValue(config, parsed, key) {
|
|
70
|
+
const record = config;
|
|
71
|
+
return parsed.kind === "map"
|
|
72
|
+
? record[parsed.map]?.[parsed.role]
|
|
73
|
+
: parsed.kind === "tier"
|
|
74
|
+
? modelTierMap(record.model)[parsed.tier] // a string is shorthand for { default }
|
|
75
|
+
: parsed.kind === "agent"
|
|
76
|
+
? record.backends?.[parsed.id]?.[parsed.field]
|
|
77
|
+
: parsed.kind === "section"
|
|
78
|
+
? record[parsed.section]?.[parsed.field]
|
|
79
|
+
: parsed.kind === "role"
|
|
80
|
+
? record.roles?.[parsed.id]?.[parsed.field]
|
|
81
|
+
: record[canonicalConfigKey(key)];
|
|
82
|
+
}
|
|
67
83
|
/** The `tumwater config` command body: bare prints the resolved config; `get` and `unset`
|
|
68
84
|
* screen their key through screenOperableKey, while `set` writes through setConfigKey. */
|
|
69
85
|
export async function cmdConfig(root, args = []) {
|
|
70
86
|
const [sub, key, ...rest] = args;
|
|
71
87
|
if (sub === "get") {
|
|
72
88
|
const { parsed, config } = screenOperableKey(root, key ?? "");
|
|
73
|
-
const
|
|
74
|
-
const value = parsed.kind === "map"
|
|
75
|
-
? record[parsed.map]?.[parsed.role]
|
|
76
|
-
: parsed.kind === "tier"
|
|
77
|
-
? modelTierMap(record.model)[parsed.tier] // a string is shorthand for { default }
|
|
78
|
-
: parsed.kind === "agent"
|
|
79
|
-
? record.backends?.[parsed.id]?.[parsed.field]
|
|
80
|
-
: parsed.kind === "role"
|
|
81
|
-
? record.roles?.[parsed.id]?.[parsed.field]
|
|
82
|
-
: record[canonicalConfigKey(key ?? "")];
|
|
89
|
+
const value = resolvedConfigValue(config, parsed, key ?? "");
|
|
83
90
|
sayJsonLine(value === undefined ? null : value); // Absent optional key → JSON null.
|
|
84
91
|
return;
|
|
85
92
|
}
|
|
@@ -92,13 +99,22 @@ export async function cmdConfig(root, args = []) {
|
|
|
92
99
|
// The same screens get runs first, so a typo'd top-level key, role id, or role field
|
|
93
100
|
// fails identically — unsetConfigKey's own parse/field checks are the mutation-side
|
|
94
101
|
// backstop, not the wording the operator sees.
|
|
95
|
-
screenOperableKey(root, k);
|
|
102
|
+
const { parsed } = screenOperableKey(root, k);
|
|
96
103
|
const result = unsetConfigKey(root, k);
|
|
97
104
|
if (!result.ok)
|
|
98
105
|
fail(result.error);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
// The reload only feeds the message, so a failed one leaves `now` undefined.
|
|
107
|
+
const reloaded = loadConfigSafe(root).config;
|
|
108
|
+
const now = reloaded === undefined ? undefined : resolvedConfigValue(reloaded, parsed, k);
|
|
109
|
+
const resolves = now === undefined ? "" : JSON.stringify(now);
|
|
110
|
+
if (result.oldValue === undefined) {
|
|
111
|
+
say(`${k} is not set in tumwater.json, so nothing was removed` +
|
|
112
|
+
(now === undefined ? "" : ` (it resolves to ${resolves})`));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const was = JSON.stringify(result.oldValue);
|
|
116
|
+
say(`unset ${k} (was ${was}${now === undefined ? "" : `; now resolves to ${resolves}`})`);
|
|
117
|
+
}
|
|
102
118
|
return;
|
|
103
119
|
}
|
|
104
120
|
if (sub === "set") {
|
|
@@ -115,7 +131,14 @@ export async function cmdConfig(root, args = []) {
|
|
|
115
131
|
const result = setConfigKey(root, key ?? "", raw);
|
|
116
132
|
if (!result.ok)
|
|
117
133
|
fail(result.error);
|
|
134
|
+
if (result.unchanged) {
|
|
135
|
+
say(`${canonicalConfigKey(key ?? "")} is already ${JSON.stringify(result.value)}, so tumwater.json was not written`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
118
138
|
say(`set ${canonicalConfigKey(key ?? "")} to ${JSON.stringify(result.value)}`);
|
|
139
|
+
const note = result.note;
|
|
140
|
+
if (note)
|
|
141
|
+
say(`note: ${note}`);
|
|
119
142
|
// A bare `roles` set replaces the FILE's section, but the built-in catalog always merges
|
|
120
143
|
// per entry at load, so the replacement cannot disable a role by omission. Say so here
|
|
121
144
|
// rather than let the confirmation imply the role is gone.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** The repaint loop every `-f/--follow` view shares (`status -f`, `queue -f`,
|
|
2
|
+
* `backlog -f`, `report -f`, `diff -f`): render once, then repaint on a fixed interval until
|
|
3
|
+
* Ctrl+C or the process that started the command exits. Lifted out of
|
|
4
|
+
* cli-query-commands.ts when `report -f` landed so the follow views have one leaf
|
|
5
|
+
* home instead of a per-command copy. */
|
|
6
|
+
import { startParentDeathWatch } from "../process/supervisor.js";
|
|
7
|
+
import { stripTerminalControls } from "../text/text.js";
|
|
8
|
+
/** The default repaint interval for a follow view — a fixed cadence, no knob. */
|
|
9
|
+
const FOLLOW_VIEW_INTERVAL_MS = 2000;
|
|
10
|
+
/** A follow view's live loop: render once, then repaint on an interval until Ctrl+C or the
|
|
11
|
+
* process that started this one is gone (the same parent-death rule `logs -f` uses).
|
|
12
|
+
* Repaints in place with the `watch` clear-screen shape on a TTY, and prints frames
|
|
13
|
+
* separated by a blank line when stdout is not a TTY so a piped follow stays readable.
|
|
14
|
+
* The frame text may be read synchronously or async (a `diff -f` frame re-reads the change
|
|
15
|
+
* by running git plumbing). A sync read paints synchronously — each interval tick paints
|
|
16
|
+
* exactly one frame, the deterministic shape the mock-clock follow tests (status, queue,
|
|
17
|
+
* backlog) depend on; an async read is guarded so a slow frame is not stacked by the ticks
|
|
18
|
+
* that arrive while it is still painting. */
|
|
19
|
+
export async function followView(frameText, seams) {
|
|
20
|
+
const tty = seams.tty ?? process.stdout.isTTY;
|
|
21
|
+
const interval = seams.intervalMs ?? FOLLOW_VIEW_INTERVAL_MS;
|
|
22
|
+
// The frame's text is rendered from model-written data (role live progress, run
|
|
23
|
+
// summaries, backlog titles) that can carry terminal escape sequences. The one-shot
|
|
24
|
+
// forms of these commands sanitize at say(); this live reprint writes raw to the
|
|
25
|
+
// terminal while rerendering its own clear-screen prefix, so it must strip controls
|
|
26
|
+
// itself — the display-boundary rule stripTerminalControls documents, applied here.
|
|
27
|
+
const paint = (text) => {
|
|
28
|
+
const clean = stripTerminalControls(text);
|
|
29
|
+
process.stdout.write(tty ? "\x1b[H\x1b[2J" + clean + "\n" : clean + "\n\n");
|
|
30
|
+
};
|
|
31
|
+
// First paint: render once before the repaint loop's interval is registered, awaiting a
|
|
32
|
+
// slow async read so the first frame is on screen before the loop begins. Guarded exactly
|
|
33
|
+
// like the loop below (a failed frame is skipped, not fatal): the first read of a follow
|
|
34
|
+
// view can strike the same transient failure (a git read, a snapshot whose file is
|
|
35
|
+
// momentarily unreadable) as any later tick, and killing the whole interactive follow on
|
|
36
|
+
// it — while the identical failure a tick later is skipped and retried — is the same fault
|
|
37
|
+
// with a different outcome based only on which tick it lands on. `Promise.resolve()`
|
|
38
|
+
// first so a synchronous frame-throw is caught too.
|
|
39
|
+
await Promise.resolve()
|
|
40
|
+
.then(frameText)
|
|
41
|
+
.then(paint)
|
|
42
|
+
.catch(() => { });
|
|
43
|
+
// Repaint on the interval. `painting` guards an async read against stacking frames: while
|
|
44
|
+
// one async frame is in flight, a tick that arrives skips its repaint rather than queueing
|
|
45
|
+
// a second write on top of the first. The guard is checked BEFORE the read, so a tick that
|
|
46
|
+
// lands mid-frame does not start another (git-spawning) read just to discard it — which
|
|
47
|
+
// would also leave that read's rejections unhandled. Sync callers never set `painting`, so
|
|
48
|
+
// the check is a no-op for them: each of their ticks still paints exactly one frame.
|
|
49
|
+
let painting = false;
|
|
50
|
+
await new Promise((resolve) => {
|
|
51
|
+
const timer = setInterval(() => {
|
|
52
|
+
if (painting)
|
|
53
|
+
return;
|
|
54
|
+
const result = frameText();
|
|
55
|
+
if (result instanceof Promise) {
|
|
56
|
+
painting = true;
|
|
57
|
+
void result
|
|
58
|
+
.then(paint)
|
|
59
|
+
.catch(() => { })
|
|
60
|
+
.finally(() => {
|
|
61
|
+
painting = false;
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
paint(result);
|
|
66
|
+
}, interval);
|
|
67
|
+
startParentDeathWatch(() => {
|
|
68
|
+
clearInterval(timer);
|
|
69
|
+
resolve();
|
|
70
|
+
}, {
|
|
71
|
+
...(seams.ppid ? { ppid: seams.ppid } : {}),
|
|
72
|
+
...(seams.intervalMs !== undefined ? { intervalMs: seams.intervalMs } : {}),
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|