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,30 +1,37 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { setConfigKey, unsetConfigKey } from "../../config/config-write.js";
|
|
3
2
|
import { loadConfigSafe } from "../../config/config.js";
|
|
4
3
|
import { DIRECTOR_ROLE } from "../../roles/roles.js";
|
|
5
|
-
import { baseRoleOf } from "../../roles/
|
|
6
|
-
/** The Ctrl+O quiet-hours editor on the shared prompt line, the
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
4
|
+
import { baseRoleOf } from "../../roles/runner-ids.js";
|
|
5
|
+
/** The Ctrl+O per-role / Ctrl+S team-wide quiet-hours editor on the shared prompt line, the
|
|
6
|
+
* terminal twin of the dashboard's `Quiet hours` rows and `tumwater role <id> --quiet-hours`
|
|
7
|
+
* / `tumwater config set quietHours`. It owns its mode flags, its saved-draft pair, and the
|
|
8
|
+
* role pinned when it opened (per-role scope only), so a roster shift cannot redirect the
|
|
9
|
+
* write. Enter writes through the shared setConfigKey/unsetConfigKey family the CLI and the
|
|
10
|
+
* drawer use — so checkQuietHours (naming `quietHoursPerRole.<id>`) and validateConfig (naming
|
|
11
|
+
* `quietHours` for the team key) own the window's truth — and Esc, the matching Ctrl again,
|
|
12
|
+
* and Ctrl+T cancel by restoring the prompt draft. Mutually exclusive with the other editors
|
|
13
|
+
* on the one prompt line via the session's held registry. The two scopes never overlap: Ctrl+O
|
|
14
|
+
* opens only on a role's Transcript and toggles only the per-role scope, Ctrl+S only on the
|
|
15
|
+
* Activity view and toggles only the team scope, so a view change cannot leave a half-open
|
|
16
|
+
* editor pointing at the wrong window. */
|
|
14
17
|
export function createQuietEditor(session) {
|
|
15
18
|
let quietMode = false;
|
|
16
|
-
let
|
|
17
|
-
let
|
|
18
|
-
// The role scope pinned when the editor opened, so Enter writes the
|
|
19
|
-
// if syncRoster shrinks or reorders the roster while the editor is
|
|
19
|
+
let quietTeam = false;
|
|
20
|
+
let restoreDraft = () => { };
|
|
21
|
+
// The role scope pinned when the editor opened (per-role scope only), so Enter writes the
|
|
22
|
+
// same role's window even if syncRoster shrinks or reorders the roster while the editor is
|
|
23
|
+
// open. The team scope pins no role: it writes the top-level `quietHours` key.
|
|
20
24
|
let lockedRole = null;
|
|
21
|
-
// Leave quiet-edit mode (Esc, Ctrl
|
|
25
|
+
// Leave quiet-edit mode (Esc, the matching Ctrl again, or Ctrl+T): restore the saved prompt
|
|
26
|
+
// text. Clears both scope flags; the caller's arm decides which scope to wake next.
|
|
22
27
|
const exitQuietMode = () => {
|
|
23
28
|
if (!quietMode)
|
|
24
29
|
return;
|
|
25
30
|
quietMode = false;
|
|
31
|
+
quietTeam = false;
|
|
26
32
|
session.held.quiet = false;
|
|
27
|
-
session.
|
|
33
|
+
session.held.quietTeam = false;
|
|
34
|
+
restoreDraft();
|
|
28
35
|
lockedRole = null;
|
|
29
36
|
};
|
|
30
37
|
const handleKey = (_str, key, ctx) => {
|
|
@@ -33,11 +40,19 @@ export function createQuietEditor(session) {
|
|
|
33
40
|
// hours) on its Transcript view. Every non-transcript view keeps Ctrl+O — the guard
|
|
34
41
|
// lets the key fall through to the pane arms (Activity's event-type cycle, History's
|
|
35
42
|
// outcome cycle, Health's problems-only toggle) unless the quiet editor already holds
|
|
36
|
-
// the line
|
|
37
|
-
//
|
|
38
|
-
//
|
|
43
|
+
// the line. While a scope is open, Ctrl+O toggles only the per-role scope out; in the
|
|
44
|
+
// team scope it is consumed and does nothing. Entering pre-fills the window from
|
|
45
|
+
// `quietHoursPerRole.<base>` (empty when unset — empty means "off" on save) and saves
|
|
46
|
+
// the prompt text; leaving restores it. The director is exempt — its
|
|
39
47
|
// quietHoursPerRole.director entry is inert (the gate and doctor both exempt it).
|
|
40
|
-
if (
|
|
48
|
+
if (quietMode) {
|
|
49
|
+
// Consumed either way: in the per-role scope it toggles the editor out, in the team
|
|
50
|
+
// scope Ctrl+O leaves the team editor open.
|
|
51
|
+
if (!quietTeam)
|
|
52
|
+
exitQuietMode();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (!(ctx.view >= 1 && ctx.view <= ctx.roleIds.length))
|
|
41
56
|
return false;
|
|
42
57
|
const role = ctx.roleIds[ctx.view - 1];
|
|
43
58
|
const held = session.heldEditorFlash("quiet");
|
|
@@ -51,23 +66,62 @@ export function createQuietEditor(session) {
|
|
|
51
66
|
session.flashMessage("the director has no quiet hours");
|
|
52
67
|
return true;
|
|
53
68
|
}
|
|
54
|
-
if (quietMode) {
|
|
55
|
-
exitQuietMode();
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
69
|
// Pin the role first so the write below is safe against a mid-edit roster shift, then
|
|
59
70
|
// pre-fill from the file's own entry — one fresh read per open is the smallest honest
|
|
60
71
|
// source; a broken config degrades to no pre-fill and the write reports the error.
|
|
61
72
|
lockedRole = role;
|
|
62
73
|
const existing = loadConfigSafe(session.root).config?.quietHoursPerRole?.[baseRoleOf(role)] ?? "";
|
|
63
|
-
|
|
74
|
+
restoreDraft = session.takeDraft();
|
|
64
75
|
quietMode = true;
|
|
76
|
+
quietTeam = false;
|
|
65
77
|
session.held.quiet = true;
|
|
78
|
+
session.held.quietTeam = false;
|
|
66
79
|
session.input = existing;
|
|
67
80
|
session.cursor = session.input.length;
|
|
68
81
|
session.flashMessage(`edit ${role}'s quiet hours (e.g. 23:00-07:00, empty clears): Enter to save, Esc to cancel`);
|
|
69
82
|
return true;
|
|
70
83
|
}
|
|
84
|
+
if (key.ctrl && key.name === "s") {
|
|
85
|
+
// Ctrl+S edits the team-wide quiet-hours window on the Activity view (view 0) — the
|
|
86
|
+
// terminal twin of the dashboard Settings `quietHours` row and `tumwater config set
|
|
87
|
+
// quietHours`, so an operator can put the whole team to sleep for a nightly window. On
|
|
88
|
+
// every non-Activity view Ctrl+S keeps its other meaning — the guard lets the key fall
|
|
89
|
+
// through to the interval editor (a role's Transcript) and the pane arms (History's
|
|
90
|
+
// trailing-window cycle). While a scope is open, Ctrl+S toggles only the team scope out;
|
|
91
|
+
// in the per-role scope it is consumed and does nothing (so it never opens the interval
|
|
92
|
+
// editor over the quiet editor). Entering pre-fills the window from the FILE's top-level
|
|
93
|
+
// `quietHours` (empty when unset — empty means "off" on save) and saves the prompt text;
|
|
94
|
+
// leaving restores it. The team window owns no role, so lockedRole stays null.
|
|
95
|
+
if (quietMode) {
|
|
96
|
+
// In the team scope Ctrl+S toggles the editor out. In the per-role scope it must not
|
|
97
|
+
// touch the per-role editor, but it also must not silently vanish: fall through so the
|
|
98
|
+
// interval editor (the other Ctrl+S arm, which runs after this one) flashes the way out,
|
|
99
|
+
// naming the per-role quiet editor as the holder.
|
|
100
|
+
if (!quietTeam)
|
|
101
|
+
return false;
|
|
102
|
+
exitQuietMode();
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
if (ctx.view !== 0)
|
|
106
|
+
return false;
|
|
107
|
+
const held = session.heldEditorFlash("quiet");
|
|
108
|
+
if (held) {
|
|
109
|
+
// Mutually exclusive with the other editors: all share one prompt line, so a mode may
|
|
110
|
+
// not enter while another holds it. Flash the way out first.
|
|
111
|
+
session.flashMessage(held);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
const existing = loadConfigSafe(session.root).config?.quietHours ?? "";
|
|
115
|
+
restoreDraft = session.takeDraft();
|
|
116
|
+
quietMode = true;
|
|
117
|
+
quietTeam = true;
|
|
118
|
+
session.held.quiet = true;
|
|
119
|
+
session.held.quietTeam = true;
|
|
120
|
+
session.input = existing;
|
|
121
|
+
session.cursor = session.input.length;
|
|
122
|
+
session.flashMessage("edit the team's quiet hours (e.g. 23:00-07:00, empty clears): Enter to save, Esc to cancel");
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
71
125
|
if (key.name === "escape" && quietMode) {
|
|
72
126
|
// Esc cancels quiet-edit mode, restoring the previous prompt text.
|
|
73
127
|
exitQuietMode();
|
|
@@ -75,22 +129,32 @@ export function createQuietEditor(session) {
|
|
|
75
129
|
}
|
|
76
130
|
if (key.name === "return" && quietMode) {
|
|
77
131
|
// Enter commits the window through the shared setter family the CLI's `--quiet-hours`
|
|
78
|
-
// and the dashboard
|
|
79
|
-
// (`unsetConfigKey`), otherwise `setConfigKey` writes
|
|
80
|
-
// .<base>` entry
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
const cfgKey = `quietHoursPerRole.${baseRoleOf(
|
|
132
|
+
// and `tumwater config set quietHours` / the dashboard rows use: an empty or
|
|
133
|
+
// whitespace-only line clears the key (`unsetConfigKey`), otherwise `setConfigKey` writes
|
|
134
|
+
// the dotted `quietHoursPerRole.<base>` entry (per-role scope) or the top-level
|
|
135
|
+
// `quietHours` (team scope) as a JSON string. checkQuietHours (naming the dotted key)
|
|
136
|
+
// rejects a malformed per-role window and validateConfig guards the team write; both
|
|
137
|
+
// write tumwater.json atomically and the running orchestrator picks the change up on its
|
|
138
|
+
// next poll. An invalid window flashes and STAYS in edit mode so the operator can fix
|
|
139
|
+
// it; success restores the saved prompt text.
|
|
140
|
+
const cfgKey = quietTeam ? "quietHours" : `quietHoursPerRole.${baseRoleOf(lockedRole)}`;
|
|
87
141
|
const text = session.input.trim();
|
|
88
142
|
const result = text === ""
|
|
89
143
|
? unsetConfigKey(session.root, cfgKey)
|
|
90
144
|
: setConfigKey(session.root, cfgKey, JSON.stringify(text));
|
|
91
145
|
if (result.ok) {
|
|
146
|
+
const team = quietTeam;
|
|
147
|
+
const role = lockedRole;
|
|
92
148
|
exitQuietMode();
|
|
93
|
-
|
|
149
|
+
const scope = team ? "team" : `${role}`;
|
|
150
|
+
const noop = text === "" ? result.oldValue === undefined : "unchanged" in result;
|
|
151
|
+
session.flashMessage(noop
|
|
152
|
+
? text === ""
|
|
153
|
+
? `${scope}: quiet hours is not set in tumwater.json, so nothing was cleared`
|
|
154
|
+
: `${scope}: quiet hours is already ${text}, so tumwater.json was not written`
|
|
155
|
+
: text === ""
|
|
156
|
+
? `${scope}: quiet hours cleared`
|
|
157
|
+
: `${scope}: quiet hours set to ${text}`);
|
|
94
158
|
}
|
|
95
159
|
else {
|
|
96
160
|
session.flashMessage(result.error); // broken config or write failure — stay in edit mode
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { artifactPhrase, retireRole } from "../../operator/retire.js";
|
|
3
2
|
/** The Health view's Ctrl+X retire editor on the shared prompt line, the terminal twin of
|
|
4
3
|
* `tumwater retire --role <id>` and the dashboard Settings card's Retire button. It owns its
|
|
@@ -12,20 +11,19 @@ import { artifactPhrase, retireRole } from "../../operator/retire.js";
|
|
|
12
11
|
* so the operator can fix the id, Esc cancels and restores the draft. */
|
|
13
12
|
export function createRetireEditor(session) {
|
|
14
13
|
let retireMode = false;
|
|
15
|
-
let
|
|
16
|
-
let retireSavedCursor = 0;
|
|
14
|
+
let restoreDraft = () => { };
|
|
17
15
|
// Leave retire-edit mode (Esc, Enter's success path, or Ctrl+T): restore the saved prompt text.
|
|
18
16
|
const exitRetireMode = () => {
|
|
19
17
|
if (!retireMode)
|
|
20
18
|
return;
|
|
21
19
|
retireMode = false;
|
|
22
20
|
session.held.retire = false;
|
|
23
|
-
|
|
21
|
+
restoreDraft();
|
|
24
22
|
};
|
|
25
23
|
const handleKey = (_str, key, ctx) => {
|
|
26
24
|
if (key.ctrl && key.name === "x" && ctx.view === ctx.roleIds.length + 7 && !retireMode) {
|
|
27
25
|
// Ctrl+X toggles retire-edit mode on the Health view's prompt line (mnemonic: **x**
|
|
28
|
-
// remove — the same key the Transcript
|
|
26
|
+
// remove — the same key the Transcript notes-clear, Backlog cancel, and Inbox cancel
|
|
29
27
|
// arms use on their own views, guarded away here by the Health index). The line edits one
|
|
30
28
|
// role id; Enter retires that role's leftovers through the same retireRole core the CLI
|
|
31
29
|
// and the dashboard button use. Entering saves the prompt draft and blanks the line;
|
|
@@ -41,7 +39,7 @@ export function createRetireEditor(session) {
|
|
|
41
39
|
// Mid-recall, hand the arrows' saved draft back before the retire editor takes the line —
|
|
42
40
|
// the same settle the role editors do — so leaving restores the draft, not a
|
|
43
41
|
// history entry, with no stale recall state riding along.
|
|
44
|
-
|
|
42
|
+
restoreDraft = session.takeDraft();
|
|
45
43
|
retireMode = true;
|
|
46
44
|
session.held.retire = true;
|
|
47
45
|
session.input = "";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { baseRoleOf } from "../../roles/runner-ids.js";
|
|
2
|
+
/** Build a role-pinned editor. It may take the line only on a role's Transcript view
|
|
3
|
+
* (view 1..roleIds.length) or when it already holds it (the toggle-out arm), and only while no
|
|
4
|
+
* other editor holds the line. An invalid value flashes and STAYS in edit mode so the operator
|
|
5
|
+
* can fix it; success restores the saved prompt text. */
|
|
6
|
+
export function createRoleKeyEditor(session, spec) {
|
|
7
|
+
let mode = false;
|
|
8
|
+
let restoreDraft = () => { };
|
|
9
|
+
// The role pinned when the editor opened, so Enter writes the same role's key even if
|
|
10
|
+
// syncRoster shrinks or reorders the roster while the editor is open.
|
|
11
|
+
let lockedRole = null;
|
|
12
|
+
// Leave the editor (Esc, the key again, or Ctrl+T): restore the saved prompt text.
|
|
13
|
+
const exit = () => {
|
|
14
|
+
if (!mode)
|
|
15
|
+
return;
|
|
16
|
+
mode = false;
|
|
17
|
+
session.held[spec.mode] = false;
|
|
18
|
+
restoreDraft();
|
|
19
|
+
lockedRole = null;
|
|
20
|
+
};
|
|
21
|
+
const handleKey = (_str, key, ctx) => {
|
|
22
|
+
if (key.ctrl && key.name === spec.openCtrl) {
|
|
23
|
+
// While open the key toggles the editor out. Otherwise it opens only on a role's
|
|
24
|
+
// Transcript view; elsewhere it keeps its own meaning and falls through to the pane arms.
|
|
25
|
+
if (mode) {
|
|
26
|
+
exit();
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (!(ctx.view >= 1 && ctx.view <= ctx.roleIds.length) || spec.yieldsOn?.(ctx))
|
|
30
|
+
return false;
|
|
31
|
+
const role = ctx.roleIds[ctx.view - 1];
|
|
32
|
+
const held = session.heldEditorFlash(spec.mode);
|
|
33
|
+
if (held) {
|
|
34
|
+
// Mutually exclusive with the other editors: all share one prompt line, so a mode may
|
|
35
|
+
// not enter while another holds it. Flash the way out first.
|
|
36
|
+
session.flashMessage(held);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Pin the role first so the write below is safe against a mid-edit roster shift, then
|
|
40
|
+
// pre-fill from the file's own entry — one fresh read per open is the smallest honest
|
|
41
|
+
// source; a broken config degrades to no pre-fill and the write reports the error.
|
|
42
|
+
lockedRole = role;
|
|
43
|
+
const existing = spec.prefill(session, baseRoleOf(role));
|
|
44
|
+
restoreDraft = session.takeDraft();
|
|
45
|
+
mode = true;
|
|
46
|
+
session.held[spec.mode] = true;
|
|
47
|
+
session.input = existing;
|
|
48
|
+
session.cursor = session.input.length;
|
|
49
|
+
session.flashMessage(spec.openFlash(role));
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (key.name === "escape" && mode) {
|
|
53
|
+
// Esc cancels the editor, restoring the previous prompt text.
|
|
54
|
+
exit();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (key.name === "return" && mode) {
|
|
58
|
+
// Enter commits the whitespace-trimmed line through the spec's shared setter. A rejected
|
|
59
|
+
// value flashes and STAYS in edit mode so the operator can fix it; success restores the
|
|
60
|
+
// saved prompt text.
|
|
61
|
+
const role = lockedRole;
|
|
62
|
+
const text = session.input.trim();
|
|
63
|
+
const result = spec.commit(session, baseRoleOf(role), text);
|
|
64
|
+
if (result.ok) {
|
|
65
|
+
exit();
|
|
66
|
+
session.flashMessage(result.noop && spec.noopFlash ? spec.noopFlash(role, text) : spec.savedFlash(role, text));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
session.flashMessage(result.error); // broken config or write failure — stay in edit mode
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
75
|
+
return { handleKey, exit };
|
|
76
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { setRoleModelFields } from "../../config/config-write.js";
|
|
2
|
+
import { rawRoleField } from "../../roles/role-view.js";
|
|
3
|
+
import { createRoleKeyEditor } from "./tui-editor-role-key.js";
|
|
4
|
+
/** The Ctrl+X role-model editor on the Transcript view's shared prompt line, the terminal twin
|
|
5
|
+
* of `tumwater role <id> --model` / `--clear-model` and the dashboard role drawer's Model
|
|
6
|
+
* overrides editor. Enter writes the viewed base role's `roles.<base>.model` through the shared
|
|
7
|
+
* setRoleModelFields the CLI and the drawer use — so checkModelTripleField (a non-empty model id
|
|
8
|
+
* or a bare tier name like `strong`) owns the value's truth, and an empty line clears the
|
|
9
|
+
* override. Pre-fill reads the FILE's raw `roles.<base>.model`: overlayDefaults seeds every
|
|
10
|
+
* built-in role's model from the catalog, so the merged value cannot tell an operator override
|
|
11
|
+
* from a seeded default. On the notes view Ctrl+X keeps its clear-notes meaning, and on every
|
|
12
|
+
* non-Transcript view it falls through to its own pane arms (the backlog cancel, the queued
|
|
13
|
+
* cancel, the Health retire). The shape it shares with the instances editor lives in
|
|
14
|
+
* createRoleKeyEditor. */
|
|
15
|
+
export function createRoleModelEditor(session) {
|
|
16
|
+
return createRoleKeyEditor(session, {
|
|
17
|
+
mode: "roleModel",
|
|
18
|
+
openCtrl: "x",
|
|
19
|
+
yieldsOn: (ctx) => ctx.noteMode,
|
|
20
|
+
prefill: (s, base) => {
|
|
21
|
+
const existing = rawRoleField(s.root, base, "model");
|
|
22
|
+
return typeof existing === "string" ? existing : "";
|
|
23
|
+
},
|
|
24
|
+
openFlash: (role) => `edit ${role}'s model override (a model id or tier name like strong; empty clears): Enter to save, Esc to cancel`,
|
|
25
|
+
commit: (s, base, text) => setRoleModelFields(s.root, base, { model: text }),
|
|
26
|
+
savedFlash: (role, text) => text === "" ? `${role}: model override cleared` : `${role}: model override set to ${text}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
/** The shared `/` search editor on the prompt line: over the History pane's
|
|
1
|
+
/** The shared `/` search editor on the prompt line: over the History pane's run rows or the
|
|
2
2
|
* Activity feed's events. It owns its mode flag (`searchMode`), its target pane (`searchFor`),
|
|
3
3
|
* its saved-draft pair, and the applyHistorySearch / applyActivitySearch leaves. Mutually
|
|
4
4
|
* exclusive with the other editors via the session's held registry. */
|
|
5
5
|
export function createSearchEditor(session) {
|
|
6
6
|
let searchMode = false;
|
|
7
|
-
// Which pane the shared `/` editor feeds: History's
|
|
8
|
-
//
|
|
7
|
+
// Which pane the shared `/` editor feeds: History's run search, Activity's event search, the
|
|
8
|
+
// Backlog pane's entry search, or a role's live-transcript search. The target is captured when
|
|
9
|
+
// `/` opens so a roster change mid-edit cannot retarget Enter.
|
|
9
10
|
let searchFor = "history";
|
|
10
|
-
let
|
|
11
|
-
let searchSavedCursor = 0;
|
|
11
|
+
let restoreDraft = () => { };
|
|
12
12
|
// Leave the shared search editor (Enter applies, Esc cancels, Ctrl+T cycles): restore the
|
|
13
13
|
// saved prompt text, and reset the recall state with it — the same settle contract the budget
|
|
14
14
|
// and role-prompt editors honor. The applied activityGrep/historyGrep itself persists across
|
|
@@ -18,27 +18,37 @@ export function createSearchEditor(session) {
|
|
|
18
18
|
return;
|
|
19
19
|
searchMode = false;
|
|
20
20
|
session.held.search = false;
|
|
21
|
-
|
|
21
|
+
restoreDraft();
|
|
22
22
|
};
|
|
23
23
|
const handleKey = (str, key, ctx) => {
|
|
24
|
-
if (!key.ctrl && str === "/" && !searchMode && !session.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
!session.held.attach && !session.held.retire &&
|
|
28
|
-
(ctx.view === 0 || ctx.view === ctx.roleIds.length + 4) && session.input === "") {
|
|
24
|
+
if (!key.ctrl && str === "/" && !searchMode && !session.anyEditorHeld() &&
|
|
25
|
+
(ctx.view === 0 || ctx.view === ctx.roleIds.length + 1 || ctx.view === ctx.roleIds.length + 4 || ctx.view === ctx.roleIds.length + 6 ||
|
|
26
|
+
(ctx.view >= 1 && ctx.view <= ctx.roleIds.length && !ctx.noteMode && !ctx.changeMode)) && session.input === "") {
|
|
29
27
|
// `/` opens a free-text search on the prompt line (the pager's search key; this project
|
|
30
|
-
// already reserves `/` for a meta action): over the History pane's
|
|
31
|
-
// over the Activity feed's events on Activity
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
// already reserves `/` for a meta action): over the History pane's run rows on History,
|
|
29
|
+
// over the Activity feed's events on Activity, and over the Backlog pane's active entries
|
|
30
|
+
// on Backlog, over the Inbox pane's queued prompts, and over a role's live transcript.
|
|
31
|
+
// Guarded to those views and to an empty line, so elsewhere it types into the prompt as
|
|
32
|
+
// today and a director draft is never disturbed. Pre-fills the applied pattern so Enter
|
|
33
|
+
// re-submits it and the operator can edit it; Esc cancels without applying.
|
|
34
|
+
restoreDraft = session.takeDraft();
|
|
35
|
+
if (ctx.view === 0)
|
|
36
|
+
searchFor = "activity";
|
|
37
|
+
else if (ctx.view === ctx.roleIds.length + 1)
|
|
38
|
+
searchFor = "backlog";
|
|
39
|
+
else if (ctx.view === ctx.roleIds.length + 4)
|
|
40
|
+
searchFor = "history";
|
|
41
|
+
else if (ctx.view === ctx.roleIds.length + 6)
|
|
42
|
+
searchFor = "queued";
|
|
43
|
+
else
|
|
44
|
+
searchFor = "transcript";
|
|
37
45
|
searchMode = true;
|
|
38
46
|
session.held.search = true;
|
|
39
|
-
|
|
47
|
+
const applied = { activity: ctx.activityGrep, history: ctx.trailSearch ? ctx.trailGrep : ctx.historyGrep, backlog: ctx.backlogGrep, queued: ctx.queuedGrep, transcript: ctx.transcriptGrep }[searchFor];
|
|
48
|
+
const noun = { activity: "events", history: ctx.trailSearch ? "transcript" : "runs", backlog: "backlog", queued: "inbox", transcript: "transcript" }[searchFor];
|
|
49
|
+
session.input = applied ?? "";
|
|
40
50
|
session.cursor = session.input.length;
|
|
41
|
-
session.flashMessage(
|
|
51
|
+
session.flashMessage(`search ${noun}: Enter to filter, Esc to cancel`);
|
|
42
52
|
return true;
|
|
43
53
|
}
|
|
44
54
|
if (key.name === "escape" && searchMode) {
|
|
@@ -50,21 +60,23 @@ export function createSearchEditor(session) {
|
|
|
50
60
|
// Enter applies the trimmed line to the pane the editor opened over: Activity sets
|
|
51
61
|
// activityGrep (an empty line clears it) and resets the scroll to the live tail — the
|
|
52
62
|
// offset indexed the old filtered list; History recomputes its row cache now (the pane
|
|
53
|
-
// is showing) and re-enters at its head
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
// is showing) and re-enters at its head; Backlog sets backlogGrep and clears its entry
|
|
64
|
+
// selection so the next frame starts in list mode; Inbox sets queuedGrep, clears its row
|
|
65
|
+
// selection, and re-reads the filtered rows. A successful apply restores the saved
|
|
66
|
+
// prompt draft through exitHistorySearch, the shared editor's exit.
|
|
67
|
+
const applied = session.input.trim() === "" ? null : session.input.trim();
|
|
68
|
+
if (searchFor === "activity")
|
|
58
69
|
session.applyActivitySearch(applied);
|
|
59
|
-
|
|
60
|
-
session.flashMessage(applied === null ? "search cleared" : `search: "${applied}"`);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
const applied = pattern === "" ? null : pattern;
|
|
70
|
+
else if (searchFor === "history")
|
|
64
71
|
session.applyHistorySearch(applied);
|
|
65
|
-
|
|
66
|
-
session.
|
|
67
|
-
|
|
72
|
+
else if (searchFor === "backlog")
|
|
73
|
+
session.applyBacklogSearch(applied);
|
|
74
|
+
else if (searchFor === "queued")
|
|
75
|
+
session.applyQueuedSearch(applied);
|
|
76
|
+
else
|
|
77
|
+
session.applyTranscriptSearch(applied);
|
|
78
|
+
exitHistorySearch();
|
|
79
|
+
session.flashMessage(applied === null ? "search cleared" : `search: "${applied}"`);
|
|
68
80
|
return true;
|
|
69
81
|
}
|
|
70
82
|
return false;
|
|
@@ -1,5 +1,26 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { newPromptHistory, resetPromptRecall, settlePromptRecall, } from "./tui-prompt-history.js";
|
|
2
|
+
/** The prompt-line editors a keypress can be refused for, each with its busy-guard subject, in
|
|
3
|
+
* the order `heldEditorFlash` reports them when more than one flag reads held. */
|
|
4
|
+
const HOLDER_SUBJECTS = [
|
|
5
|
+
["attach", "image attach"],
|
|
6
|
+
["notes", "notes edit"],
|
|
7
|
+
["brief", "brief edit"],
|
|
8
|
+
["retire", "retire role"],
|
|
9
|
+
["quiet", "quiet hours"],
|
|
10
|
+
["model", "model edit"],
|
|
11
|
+
["interval", "min run interval"],
|
|
12
|
+
["instructions", "instructions edit"],
|
|
13
|
+
["providerCaps", "provider caps"],
|
|
14
|
+
["concurrency", "run cap edit"],
|
|
15
|
+
["slots", "worktree slots"],
|
|
16
|
+
["notify", "notify hook"],
|
|
17
|
+
["backends", "agent backends"],
|
|
18
|
+
["fallback", "fallback edit"],
|
|
19
|
+
["roleModel", "role model edit"],
|
|
20
|
+
["instances", "role instances"],
|
|
21
|
+
["claudeReserve", "claude reserve"],
|
|
22
|
+
["budget", "budget edit"],
|
|
23
|
+
];
|
|
3
24
|
/** Build the shared prompt-line session from the disk-side deps the aggregator received. The
|
|
4
25
|
* editor modules then take this session plus each keypress's `TuiEditorCtx`. */
|
|
5
26
|
export function createTuiEditorSession(deps) {
|
|
@@ -24,7 +45,19 @@ export function createTuiEditorSession(deps) {
|
|
|
24
45
|
brief: false,
|
|
25
46
|
retire: false,
|
|
26
47
|
quiet: false,
|
|
48
|
+
quietTeam: false,
|
|
27
49
|
interval: false,
|
|
50
|
+
instructions: null,
|
|
51
|
+
providerCaps: false,
|
|
52
|
+
concurrency: false,
|
|
53
|
+
slots: false,
|
|
54
|
+
notify: false,
|
|
55
|
+
backends: false,
|
|
56
|
+
fallback: false,
|
|
57
|
+
roleModel: false,
|
|
58
|
+
model: false,
|
|
59
|
+
instances: false,
|
|
60
|
+
claudeReserve: false,
|
|
28
61
|
},
|
|
29
62
|
root: deps.root,
|
|
30
63
|
now: deps.now,
|
|
@@ -35,28 +68,41 @@ export function createTuiEditorSession(deps) {
|
|
|
35
68
|
clearBacklogSelection: deps.clearBacklogSelection,
|
|
36
69
|
applyHistorySearch: deps.applyHistorySearch,
|
|
37
70
|
applyActivitySearch: deps.applyActivitySearch,
|
|
71
|
+
applyBacklogSearch: deps.applyBacklogSearch,
|
|
72
|
+
applyQueuedSearch: deps.applyQueuedSearch,
|
|
73
|
+
applyTranscriptSearch: deps.applyTranscriptSearch,
|
|
38
74
|
flashMessage: deps.flashMessage,
|
|
39
75
|
flashError: deps.flashError,
|
|
40
76
|
commitBacklogEdit: deps.commitBacklogEdit,
|
|
41
|
-
|
|
42
|
-
session.input = text;
|
|
43
|
-
session.cursor = pos;
|
|
44
|
-
session.promptHistory = resetPromptRecall(session.promptHistory);
|
|
45
|
-
},
|
|
46
|
-
settleDraft(saveInput, saveCursor) {
|
|
77
|
+
takeDraft() {
|
|
47
78
|
const settled = settlePromptRecall(session.promptHistory, session.input, session.cursor);
|
|
48
79
|
session.promptHistory = settled.history;
|
|
49
|
-
|
|
50
|
-
|
|
80
|
+
return () => {
|
|
81
|
+
session.input = settled.text;
|
|
82
|
+
session.cursor = settled.cursor;
|
|
83
|
+
session.promptHistory = resetPromptRecall(session.promptHistory);
|
|
84
|
+
};
|
|
51
85
|
},
|
|
52
86
|
busyFlash(subject) {
|
|
53
87
|
return `finish or cancel the ${subject} first (Esc cancels)`;
|
|
54
88
|
},
|
|
89
|
+
anyEditorHeld(...except) {
|
|
90
|
+
const h = session.held;
|
|
91
|
+
if (h.search && !except.includes("search"))
|
|
92
|
+
return true;
|
|
93
|
+
if (h.pause && !except.includes("pause"))
|
|
94
|
+
return true;
|
|
95
|
+
if (h.rolePromptFor && !except.includes("rolePromptFor"))
|
|
96
|
+
return true;
|
|
97
|
+
if (h.queued || h.answer || h.entry)
|
|
98
|
+
return true;
|
|
99
|
+
return HOLDER_SUBJECTS.some(([mode]) => h[mode]);
|
|
100
|
+
},
|
|
55
101
|
heldEditorFlash(entering) {
|
|
56
102
|
const h = session.held;
|
|
57
103
|
if (h.search)
|
|
58
104
|
return session.busyFlash("search");
|
|
59
|
-
if (h.pause)
|
|
105
|
+
if (h.pause && entering !== "pause")
|
|
60
106
|
return session.busyFlash("pause");
|
|
61
107
|
if (h.queued)
|
|
62
108
|
return session.busyFlash("inbox edit");
|
|
@@ -66,30 +112,10 @@ export function createTuiEditorSession(deps) {
|
|
|
66
112
|
return session.busyFlash("entry edit");
|
|
67
113
|
if (h.rolePromptFor)
|
|
68
114
|
return session.busyFlash(`prompt for ${h.rolePromptFor}`);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (h.brief && entering !== "brief")
|
|
74
|
-
return session.busyFlash("brief edit");
|
|
75
|
-
if (h.retire && entering !== "retire")
|
|
76
|
-
return session.busyFlash("retire role");
|
|
77
|
-
if (h.quiet && entering !== "quiet")
|
|
78
|
-
return session.busyFlash("quiet hours");
|
|
79
|
-
if (h.interval && entering !== "interval")
|
|
80
|
-
return session.busyFlash("min run interval");
|
|
81
|
-
if (entering === "attach" && h.budget)
|
|
82
|
-
return session.busyFlash("budget edit");
|
|
83
|
-
if (entering === "notes" && (h.attach || h.budget))
|
|
84
|
-
return session.busyFlash(h.attach ? "image attach" : "budget edit");
|
|
85
|
-
if (entering === "brief" && h.budget)
|
|
86
|
-
return session.busyFlash("budget edit");
|
|
87
|
-
if (entering === "retire" && (h.attach || h.notes || h.budget))
|
|
88
|
-
return session.busyFlash(h.attach ? "image attach" : h.notes ? "notes edit" : "budget edit");
|
|
89
|
-
if (entering === "quiet" && (h.attach || h.notes || h.budget || h.brief || h.retire))
|
|
90
|
-
return session.busyFlash(h.attach ? "image attach" : h.notes ? "notes edit" : h.brief ? "brief edit" : h.retire ? "retire role" : "budget edit");
|
|
91
|
-
if (entering === "interval" && (h.attach || h.notes || h.budget || h.brief || h.retire || h.quiet))
|
|
92
|
-
return session.busyFlash(h.attach ? "image attach" : h.notes ? "notes edit" : h.brief ? "brief edit" : h.retire ? "retire role" : h.quiet ? "quiet hours" : "budget edit");
|
|
115
|
+
for (const [mode, subject] of HOLDER_SUBJECTS) {
|
|
116
|
+
if (h[mode] && entering !== mode)
|
|
117
|
+
return session.busyFlash(subject);
|
|
118
|
+
}
|
|
93
119
|
return null;
|
|
94
120
|
},
|
|
95
121
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { loadConfigSafe } from "../../config/config.js";
|
|
2
|
+
import { createTeamConfigKeyEditor } from "./tui-editor-config.js";
|
|
3
|
+
/** The Ctrl+W worktree-pool editor on the shared prompt line, the terminal twin of the
|
|
4
|
+
* dashboard Settings `Worktree slots` field and `tumwater config set worktreeSlots`. It owns
|
|
5
|
+
* its mode flag and its saved-draft pair. Enter writes through the shared
|
|
6
|
+
* setConfigKey/unsetConfigKey family the CLI and the dashboard use — so validateConfig owns
|
|
7
|
+
* the value's truth (`worktreeSlots must be an integer of at least 1`) — and Esc, Ctrl+W
|
|
8
|
+
* again, and Ctrl+T cancel by restoring the prompt draft. On the Activity view (view 0) it
|
|
9
|
+
* opens pre-filled from the file's `worktreeSlots` (empty when unset — the default is
|
|
10
|
+
* `maxConcurrent + 1`); on a role's Transcript view (where the shared pause editor's wake arm
|
|
11
|
+
* pins Ctrl+W) it falls through so the wake editor keeps the key. Mutually exclusive with the
|
|
12
|
+
* other editors on the one prompt line via the session's held registry. */
|
|
13
|
+
export function createSlotsEditor(session) {
|
|
14
|
+
return createTeamConfigKeyEditor(session, {
|
|
15
|
+
mode: "slots",
|
|
16
|
+
openCtrl: "w",
|
|
17
|
+
configKey: "worktreeSlots",
|
|
18
|
+
prefill: (s) => String(loadConfigSafe(s.root).config?.worktreeSlots ?? ""),
|
|
19
|
+
openFlash: "edit the team's worktree pool size (worktreeSlots, an integer ≥ 1; empty restores the default of maxConcurrent + 1): Enter to save, Esc to cancel",
|
|
20
|
+
clearedFlash: "worktree slots reset to the default",
|
|
21
|
+
setFlash: (text) => `worktree slots set to ${text}`,
|
|
22
|
+
});
|
|
23
|
+
}
|