tumwater 0.4.2 → 0.4.4
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 +6 -6
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-backend.js +6 -6
- package/dist/src/agent/{run-agent.js → agent-run.js} +27 -13
- package/dist/src/agent/{run-settle.js → agent-settle.js} +48 -24
- package/dist/src/agent/{run-spawn.js → agent-spawn.js} +21 -12
- package/dist/src/agent/{run-stream.js → agent-stream.js} +4 -4
- package/dist/src/agent/backend-traits.js +2 -2
- package/dist/src/agent/claude/claude-account.js +6 -27
- package/dist/src/agent/claude/claude-backend.js +3 -3
- package/dist/src/agent/claude/claude-env.js +27 -31
- package/dist/src/agent/claude/claude-stream.js +111 -54
- package/dist/src/agent/codex/codex-account.js +8 -0
- package/dist/src/agent/codex/codex-args.js +5 -5
- package/dist/src/agent/codex/codex-backend.js +2 -2
- package/dist/src/agent/codex/codex-env.js +28 -15
- package/dist/src/agent/codex/codex-hook-trust.js +39 -20
- package/dist/src/agent/codex/codex-rollout.js +93 -56
- package/dist/src/agent/codex/codex-stream.js +1 -1
- package/dist/src/agent/env-scrub.js +18 -0
- package/dist/src/agent/image-input.js +68 -11
- package/dist/src/agent/notes-shim.js +2 -2
- package/dist/src/agent/opencode/opencode-backend.js +26 -24
- package/dist/src/agent/opencode/opencode-catalog.js +85 -36
- package/dist/src/agent/opencode/opencode-config.js +32 -14
- package/dist/src/agent/opencode/opencode-env.js +12 -13
- package/dist/src/agent/opencode/opencode-stream.js +47 -25
- package/dist/src/agent/session-ledger.js +23 -27
- package/dist/src/agent/subscription-account.js +2 -83
- package/dist/src/backlog/backlog-archive.js +3 -4
- package/dist/src/backlog/backlog-cli-view.js +81 -41
- package/dist/src/backlog/backlog-cli.js +57 -26
- package/dist/src/backlog/backlog-eligibility.js +56 -122
- package/dist/src/backlog/backlog-md.js +5 -5
- package/dist/src/backlog/backlog-parts.js +65 -27
- package/dist/src/backlog/{question-answer.js → backlog-question-answer.js} +1 -1
- package/dist/src/backlog/backlog-release.js +12 -12
- package/dist/src/backlog/backlog-structure.js +114 -61
- package/dist/src/backlog/backlog.js +3 -2
- package/dist/src/baseline/main-baseline.js +148 -84
- package/dist/src/baseline/main-guardrails.js +2 -2
- package/dist/src/baseline/main-watch.js +84 -50
- package/dist/src/brief/brief.js +26 -13
- package/dist/src/budget/budget-fallback-view.js +100 -243
- package/dist/src/budget/budget-wiring.js +29 -65
- package/dist/src/budget/budget.js +4 -5
- package/dist/src/budget/fallback-breaker.js +2 -2
- package/dist/src/build/build-check-detect.js +43 -14
- package/dist/src/build/build-check-events.js +2 -2
- package/dist/src/build/build-check-report.js +10 -0
- package/dist/src/build/build-check-scoped.js +40 -18
- package/dist/src/build/build-check.js +13 -5
- package/dist/src/build/build-stage.js +6 -4
- package/dist/src/change/change-data.js +1 -4
- package/dist/src/cli/cli-command-args.js +89 -52
- package/dist/src/cli/cli-completion-command.js +75 -0
- package/dist/src/cli/{config-commands.js → cli-config-commands.js} +82 -71
- package/dist/src/cli/cli-doctor-command.js +103 -0
- package/dist/src/cli/cli-flag-specs.js +42 -22
- package/dist/src/cli/cli-init.js +36 -14
- package/dist/src/cli/{log-commands.js → cli-log-commands.js} +43 -23
- package/dist/src/cli/{notify-command.js → cli-notify-command.js} +2 -2
- package/dist/src/cli/cli-query-commands.js +2 -2
- package/dist/src/cli/{question-commands.js → cli-question-commands.js} +86 -60
- package/dist/src/cli/cli-repo-gate.js +2 -2
- package/dist/src/cli/cli-role-command.js +2 -41
- package/dist/src/cli/cli-start-summary.js +4 -3
- package/dist/src/cli/cli-start-supervisor.js +190 -0
- package/dist/src/cli/cli-start.js +94 -244
- package/dist/src/cli/completion.js +85 -49
- package/dist/src/cli/follow-view.js +20 -2
- package/dist/src/cli/help.js +6 -13
- package/dist/src/cli.js +70 -176
- package/dist/src/collections.js +39 -27
- package/dist/src/concurrency/check-slots.js +70 -0
- package/dist/src/concurrency/lock.js +23 -1
- package/dist/src/concurrency/run-permit.js +49 -0
- package/dist/src/concurrency/semaphore.js +46 -250
- package/dist/src/config/config-editable-keys.js +4 -7
- package/dist/src/config/config-fallbacks.js +81 -101
- package/dist/src/config/config-field-checks.js +66 -37
- package/dist/src/config/config-keys.js +66 -40
- package/dist/src/config/config-live.js +4 -28
- package/dist/src/config/{model-selector.js → config-model-selector.js} +4 -4
- package/dist/src/config/config-request.js +163 -102
- package/dist/src/config/config-schema.js +10 -12
- package/dist/src/config/config-selector-checks.js +1 -1
- package/dist/src/config/config-validation-agents.js +2 -2
- package/dist/src/config/config-validation-roles.js +8 -72
- package/dist/src/config/config-validation.js +4 -39
- package/dist/src/config/config-views.js +26 -50
- package/dist/src/config/config-write.js +128 -102
- package/dist/src/config/config.js +5 -14
- package/dist/src/doctor/doctor-backlog-bugs.js +7 -6
- package/dist/src/doctor/doctor-backlog-plans.js +53 -120
- package/dist/src/doctor/doctor-backlog.js +16 -14
- package/dist/src/doctor/doctor-check-names.js +3 -6
- package/dist/src/doctor/doctor-checks.js +8 -8
- package/dist/src/doctor/doctor-claude-checks.js +70 -36
- package/dist/src/doctor/doctor-codex-checks.js +6 -6
- package/dist/src/doctor/doctor-contention-checks.js +57 -117
- package/dist/src/doctor/doctor-fallback-checks.js +48 -26
- package/dist/src/doctor/doctor-holds.js +8 -47
- package/dist/src/doctor/doctor-install.js +1 -1
- package/dist/src/doctor/doctor-launch-services.js +1 -1
- package/dist/src/doctor/doctor-model-checks.js +178 -94
- package/dist/src/doctor/doctor-notify.js +2 -2
- package/dist/src/doctor/doctor-opencode-checks.js +5 -4
- package/dist/src/doctor/doctor-orphans.js +122 -21
- package/dist/src/doctor/{outcome.js → doctor-outcome.js} +7 -0
- package/dist/src/doctor/doctor-pi-checks.js +2 -2
- package/dist/src/doctor/doctor-principles.js +3 -3
- package/dist/src/doctor/doctor-project-checks.js +24 -11
- package/dist/src/doctor/doctor-role-notes.js +1 -1
- package/dist/src/doctor/doctor.js +8 -11
- package/dist/src/events/event-format.js +44 -64
- package/dist/src/events/event-labels.js +1 -5
- package/dist/src/events/event-legacy.js +3 -5
- package/dist/src/events/{notify.js → event-notify.js} +6 -6
- package/dist/src/events/event-read.js +1 -1
- package/dist/src/events/event-window.js +1 -1
- package/dist/src/events/events.js +8 -0
- package/dist/src/failure/failure-cluster.js +9 -18
- package/dist/src/failure/failure-data.js +12 -8
- package/dist/src/failure/failure-render.js +46 -36
- package/dist/src/failure/failure-state-change.js +54 -120
- package/dist/src/failure/{time-spend.js → failure-time-spend.js} +117 -84
- package/dist/src/files/files.js +30 -0
- package/dist/src/files/json-object.js +8 -8
- package/dist/src/files/stat-cache.js +12 -8
- package/dist/src/gates/budget-gates.js +85 -84
- package/dist/src/gates/gate-polls.js +32 -74
- package/dist/src/gates/pause-gates.js +16 -2
- package/dist/src/gates/readiness.js +1 -1
- package/dist/src/gates/role-cap-gates.js +44 -35
- package/dist/src/gates/{startup-gate.js → startup-gates.js} +9 -8
- package/dist/src/gates/{streak-gate.js → streak-gates.js} +75 -52
- package/dist/src/git/git-diff.js +6 -2
- package/dist/src/git/git.js +75 -45
- package/dist/src/git/worktree-pool.js +3 -6
- package/dist/src/gui/gui-admin-endpoints.js +3 -3
- package/dist/src/gui/gui-args.js +12 -0
- package/dist/src/gui/gui-backlog-commands.js +4 -4
- package/dist/src/gui/gui-backlog-endpoints.js +61 -41
- package/dist/src/gui/gui-command.js +43 -24
- package/dist/src/gui/gui-config-commands.js +2 -64
- package/dist/src/gui/gui-endpoint-commands.js +1 -1
- package/dist/src/gui/gui-endpoint-common.js +19 -1
- package/dist/src/gui/gui-history-endpoints.js +100 -52
- package/dist/src/gui/gui-operator-commands.js +43 -48
- package/dist/src/gui/gui-prompt-commands.js +25 -25
- package/dist/src/gui/gui-report-endpoints.js +1 -1
- package/dist/src/gui/gui-server.js +1 -2
- package/dist/src/gui/gui-team-commands.js +2 -1
- package/dist/src/history/history-data.js +71 -44
- package/dist/src/history/history-queued.js +49 -27
- package/dist/src/history/history.js +54 -36
- package/dist/src/inbox/prompt-commands.js +59 -42
- package/dist/src/init/init.js +88 -40
- package/dist/src/merge/merge-backlog-conflicts.js +1 -1
- package/dist/src/merge/merge-check-failures.js +12 -9
- package/dist/src/merge/merge-core.js +7 -32
- package/dist/src/merge/merge-drain.js +11 -13
- package/dist/src/merge/merge-pipeline.js +6 -7
- package/dist/src/merge/merge-post-review-drain.js +11 -14
- package/dist/src/merge/merge-queue-render.js +3 -3
- package/dist/src/merge/merge-requeue.js +1 -1
- package/dist/src/merge/merge-slot.js +0 -8
- package/dist/src/merge/merge-stack.js +17 -18
- package/dist/src/merge/merge-to-main.js +13 -58
- package/dist/src/merge/merge-verify.js +12 -21
- package/dist/src/notes-cli.js +52 -42
- package/dist/src/operator/operator-commands.js +80 -47
- package/dist/src/operator/operator-intent.js +3 -3
- package/dist/src/orchestrator/orchestrator-launch.js +31 -63
- package/dist/src/orchestrator/orchestrator-poll.js +44 -69
- package/dist/src/orchestrator/orchestrator-scheduling.js +5 -9
- package/dist/src/orchestrator/orchestrator.js +8 -21
- package/dist/src/orchestrator/scheduling-admit.js +101 -68
- package/dist/src/orchestrator/scheduling-scope.js +18 -27
- package/dist/src/orchestrator/scheduling-skip.js +10 -14
- package/dist/src/orchestrator/startup-migrations.js +1 -1
- package/dist/src/paths.js +10 -9
- package/dist/src/pi/pi-args.js +5 -2
- package/dist/src/pi/pi-backend.js +2 -2
- package/dist/src/pi/pi-bin.js +3 -3
- package/dist/src/pi/pi-event-line.js +28 -1
- package/dist/src/pi/pi-listed-models.js +13 -0
- package/dist/src/pi/pi-models.js +43 -29
- package/dist/src/pi/pi-settings.js +43 -20
- package/dist/src/pi/pi-stream.js +41 -8
- package/dist/src/pi/pi-watchdogs.js +43 -15
- package/dist/src/pi/pi.js +2 -2
- package/dist/src/pi-extension/context-shake.js +32 -20
- package/dist/src/pi-extension/kill-guard.js +69 -0
- package/dist/src/process/process-group.js +51 -26
- package/dist/src/process/process.js +20 -12
- package/dist/src/process/run-marker.js +33 -15
- package/dist/src/process/supervisor.js +40 -28
- package/dist/src/prompt/dialect.js +1 -1
- package/dist/src/prompt/gate-notes.js +2 -2
- package/dist/src/prompt/gate-prompts.js +1 -44
- package/dist/src/prompt/notes-backlog.js +66 -37
- package/dist/src/prompt/principles.js +6 -4
- package/dist/src/prompt/prompt-followup.js +12 -4
- package/dist/src/prompt/prompt.js +88 -38
- package/dist/src/redeploy/redeployer.js +21 -1
- package/dist/src/report/report-data.js +53 -37
- package/dist/src/report/report-fold.js +16 -9
- package/dist/src/report/report-render.js +21 -194
- package/dist/src/report/report-since-data.js +4 -3
- package/dist/src/report/report-since-render.js +173 -0
- package/dist/src/report/report-usage-fold.js +8 -8
- package/dist/src/report/report.js +46 -22
- package/dist/src/review/diff-rules.js +35 -21
- package/dist/src/review/post-merge-review-render.js +9 -3
- package/dist/src/review/post-merge-review.js +48 -41
- package/dist/src/review/review-precheck.js +14 -4
- package/dist/src/review/review.js +48 -170
- package/dist/src/review/secret-leaks.js +26 -16
- package/dist/src/roles/legacy-role-migration.js +6 -3
- package/dist/src/roles/role-catalog.js +11 -3
- package/dist/src/roles/role-guidance.js +16 -12
- package/dist/src/roles/role-render.js +7 -46
- package/dist/src/roles/role-view.js +10 -33
- package/dist/src/run/acceptance-greps.js +88 -45
- package/dist/src/run/ci-parity.js +19 -8
- package/dist/src/run/run-apply.js +12 -15
- package/dist/src/run/run-detail-data.js +121 -68
- package/dist/src/run/run-detail-render.js +92 -35
- package/dist/src/run/run-detail.js +72 -41
- package/dist/src/run/run-prompt.js +63 -50
- package/dist/src/run/run-resume.js +76 -29
- package/dist/src/run/run-stage.js +141 -90
- package/dist/src/run/run-timing.js +8 -2
- package/dist/src/run/run-usage.js +31 -1
- package/dist/src/run/run-verdict.js +128 -50
- package/dist/src/run/stage-check.js +60 -50
- package/dist/src/run/stage-checks-shared.js +28 -0
- package/dist/src/run/stage-name-checks.js +111 -92
- package/dist/src/run/stage-path-checks.js +69 -42
- package/dist/src/run/stage-prose-checks.js +55 -40
- package/dist/src/runner/{leftover.js → runner-leftover.js} +9 -26
- package/dist/src/runner/runner-outcome.js +7 -2
- package/dist/src/runner/runner-pi.js +9 -22
- package/dist/src/runner/runner-recovery.js +5 -13
- package/dist/src/runner/{revision.js → runner-revision.js} +1 -2
- package/dist/src/runner/runner-run.js +103 -50
- package/dist/src/runner/runner-state-load.js +18 -28
- package/dist/src/runner/runner-state.js +0 -14
- package/dist/src/runner/runner.js +41 -25
- package/dist/src/scheduling/backoff.js +8 -3
- package/dist/src/scheduling/claim-entries.js +2 -1
- package/dist/src/scheduling/claims.js +0 -4
- package/dist/src/scheduling/scheduling.js +53 -66
- package/dist/src/status/status-budget.js +4 -43
- package/dist/src/status/status-data.js +35 -39
- package/dist/src/status/status-role-notes.js +2 -2
- package/dist/src/status/status-roles.js +9 -18
- package/dist/src/team/{error-storm.js → team-error-storm.js} +1 -1
- package/dist/src/team/{failure-spread.js → team-failure-spread.js} +5 -5
- package/dist/src/team/team-hold.js +105 -70
- package/dist/src/team/{orchestrator-info.js → team-orchestrator-info.js} +55 -36
- package/dist/src/team/team-polls.js +53 -201
- package/dist/src/team/{reclaim.js → team-reclaim.js} +61 -31
- package/dist/src/team/team-state.js +4 -13
- package/dist/src/text/datetime.js +16 -7
- package/dist/src/text/markdown.js +1 -1
- package/dist/src/text/phrases.js +29 -15
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +6 -5
- package/dist/src/ui/alert-feeds.js +46 -111
- package/dist/src/ui/badges.js +17 -88
- package/dist/src/ui/gui/gui-client-boot.js +2 -8
- package/dist/src/ui/gui/gui-client-composer.js +1 -1
- package/dist/src/ui/gui/gui-client-drawer-config.js +8 -33
- package/dist/src/ui/gui/gui-client-drawer.js +1 -1
- package/dist/src/ui/gui/gui-client-feed.js +1 -1
- package/dist/src/ui/gui/gui-client-history.js +28 -14
- package/dist/src/ui/gui/gui-client-model.js +0 -12
- package/dist/src/ui/gui/gui-client-operator.js +7 -5
- package/dist/src/ui/gui/gui-client-pending.js +7 -6
- package/dist/src/ui/gui/gui-client-report-chart.js +5 -5
- package/dist/src/ui/gui/gui-client-report.js +1 -1
- package/dist/src/ui/gui/gui-client-roles.js +0 -1
- package/dist/src/ui/gui/gui-client-settings.js +43 -84
- package/dist/src/ui/gui/gui-client-team.js +12 -6
- package/dist/src/ui/gui/gui-client.js +7 -1
- package/dist/src/ui/progress-data.js +107 -44
- package/dist/src/ui/run-progress-model.js +20 -4
- package/dist/src/ui/status-model.js +2 -24
- package/dist/src/ui/status-payload.js +11 -30
- package/dist/src/ui/status-render.js +13 -24
- package/dist/src/ui/team-alert-backlog.js +14 -204
- package/dist/src/ui/team-alert-shared.js +6 -29
- package/dist/src/ui/team-alert-status.js +9 -170
- package/dist/src/ui/team-alert-tail.js +19 -215
- package/dist/src/ui/team-alerts.js +8 -15
- package/dist/src/ui/transcript-run.js +27 -16
- package/dist/src/ui/tui/tui-backlog.js +2 -2
- package/dist/src/ui/tui/tui-editor-answer.js +12 -10
- package/dist/src/ui/tui/tui-editor-attach.js +4 -3
- package/dist/src/ui/tui/tui-editor-backends.js +4 -3
- package/dist/src/ui/tui/tui-editor-brief.js +6 -9
- package/dist/src/ui/tui/tui-editor-budget.js +4 -3
- package/dist/src/ui/tui/tui-editor-config.js +80 -68
- package/dist/src/ui/tui/tui-editor-entry.js +12 -20
- package/dist/src/ui/tui/tui-editor-pause.js +51 -57
- package/dist/src/ui/tui/tui-editor-prompt.js +9 -13
- package/dist/src/ui/tui/tui-editor-queued.js +11 -14
- package/dist/src/ui/tui/tui-editor-quiet.js +4 -3
- package/dist/src/ui/tui/tui-editor-release.js +4 -3
- package/dist/src/ui/tui/tui-editor-retire.js +7 -7
- package/dist/src/ui/tui/tui-editor-role-enabled.js +4 -3
- package/dist/src/ui/tui/tui-editor-role-file.js +4 -4
- package/dist/src/ui/tui/tui-editor-role-key.js +4 -3
- package/dist/src/ui/tui/tui-editor-role-model.js +97 -15
- package/dist/src/ui/tui/tui-editor-search.js +4 -3
- package/dist/src/ui/tui/tui-editor-session.js +17 -4
- package/dist/src/ui/tui/tui-editors.js +5 -10
- package/dist/src/ui/tui/tui-frame.js +182 -134
- package/dist/src/ui/tui/tui-guard.js +20 -0
- package/dist/src/ui/tui/tui-input.js +167 -98
- package/dist/src/ui/tui/tui-keymap.js +51 -29
- package/dist/src/ui/tui/tui-keys.js +1 -1
- package/dist/src/ui/tui/tui-pane-activity.js +5 -4
- package/dist/src/ui/tui/tui-pane-backlog.js +74 -36
- package/dist/src/ui/tui/tui-pane-ctx.js +1 -1
- package/dist/src/ui/tui/tui-pane-health.js +252 -230
- package/dist/src/ui/tui/tui-pane-history.js +67 -74
- package/dist/src/ui/tui/tui-pane-pending.js +288 -247
- package/dist/src/ui/tui/tui-pane-queued.js +25 -27
- package/dist/src/ui/tui/tui-pane-report.js +2 -1
- package/dist/src/ui/tui/tui-pane-session.js +15 -10
- package/dist/src/ui/tui/tui-pane-transcript.js +19 -31
- package/dist/src/ui/tui/tui-pane.js +14 -11
- package/dist/src/ui/tui/tui-panes.js +38 -33
- package/dist/src/ui/tui/tui.js +4 -7
- package/dist/src/verdict/fix-claim.js +107 -56
- package/dist/src/verdict/refusal.js +1 -1
- package/dist/src/verdict/reply-contract.js +3 -4
- package/package.json +5 -5
- package/dist/src/concurrency/provider-lease.js +0 -105
- package/dist/src/review/review-followup.js +0 -87
- package/dist/src/review/review-run.js +0 -395
- package/dist/src/runner/model-fallback.js +0 -76
- package/dist/src/runner/runner-fallback.js +0 -66
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +0 -24
- package/dist/src/ui/tui/tui-editor-provider-caps.js +0 -27
- /package/dist/src/cli/{brief-command.js → cli-brief-command.js} +0 -0
- /package/dist/src/doctor/{probe.js → doctor-probe.js} +0 -0
- /package/dist/src/gates/{disk-gate.js → disk-gates.js} +0 -0
- /package/dist/src/operator/{retire.js → operator-retire.js} +0 -0
- /package/dist/src/operator/{revert.js → operator-revert.js} +0 -0
|
@@ -4,6 +4,8 @@ import { movePromptToTop } from "../../inbox/inbox-top.js";
|
|
|
4
4
|
import { moveEntrySelection } from "./tui-backlog.js";
|
|
5
5
|
import { arrowDir } from "./tui-keymap.js";
|
|
6
6
|
import { promptLineFree } from "./tui-pane-ctx.js";
|
|
7
|
+
import { guardError } from "./tui-guard.js";
|
|
8
|
+
import { paneAtHead } from "./tui-pane-session.js";
|
|
7
9
|
/** The Queued pane (view roleIds.length + 6) of the TUI (src/ui/tui/tui.tsx): the prompt row
|
|
8
10
|
* selection, the up/down select and Esc-to-list arms, and the Ctrl+X cancel and Ctrl+V
|
|
9
11
|
* move-to-top arms. Split out of the pane-navigation monolith; it owns the pane's
|
|
@@ -41,11 +43,11 @@ export function createQueuedPane(session) {
|
|
|
41
43
|
// (`tumwater prompt --cancel <n> --role <id>`): cancelRolePrompt removes that role's Nth
|
|
42
44
|
// queue file and logs the prompt_cancelled event, so the pane, the CLI, and the dashboard
|
|
43
45
|
// cancel cannot drift. It then re-reads the queue so the pane's list and rows reflect the
|
|
44
|
-
// removal and the selection clamps. Its write and flash stay under one
|
|
45
|
-
//
|
|
46
|
-
//
|
|
46
|
+
// removal and the selection clamps. Its write and flash stay under one guard; the caller
|
|
47
|
+
// guards on the row being defined (a no-selection list-mode press, or any other view,
|
|
48
|
+
// leaves the queue untouched).
|
|
47
49
|
const cancelQueuedRow = (row) => {
|
|
48
|
-
|
|
50
|
+
guardError(session, () => {
|
|
49
51
|
const outcome = cancelRolePrompt(session.root, row.role, row.position);
|
|
50
52
|
// A gone outcome is the concurrent-dequeue race (cancelRolePrompt's own contract),
|
|
51
53
|
// not a failure: flash it honestly and still refresh the listing.
|
|
@@ -53,21 +55,18 @@ export function createQueuedPane(session) {
|
|
|
53
55
|
? `cancelled inbox message #${row.position} for ${row.role}`
|
|
54
56
|
: `inbox message #${row.position} for ${row.role} was already gone`);
|
|
55
57
|
refreshQueued();
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
session.flashError(err);
|
|
59
|
-
}
|
|
58
|
+
});
|
|
60
59
|
};
|
|
61
60
|
// Ctrl+V moves the selected queued prompt to the head of its role's queue through the
|
|
62
61
|
// CLI's own per-role path (`tumwater prompt --top <n>`): movePromptToTop renames that
|
|
63
62
|
// role's Nth queue file to the head and logs the prompt_topped event, so the pane, the
|
|
64
63
|
// CLI, and the dashboard cannot drift. A position-1 row is already the head (a no-op); a
|
|
65
64
|
// gone outcome is the concurrent-dequeue race (movePromptToTop's own contract), not a
|
|
66
|
-
// failure, so flash it honestly. Its write and flash stay under one
|
|
65
|
+
// failure, so flash it honestly. Its write and flash stay under one guard; the caller
|
|
67
66
|
// guards on the row being defined (a no-selection list-mode press, or any other view,
|
|
68
67
|
// leaves the queues untouched).
|
|
69
68
|
const moveQueuedRow = (row) => {
|
|
70
|
-
|
|
69
|
+
guardError(session, () => {
|
|
71
70
|
if (row.position === 1) {
|
|
72
71
|
// A head row is a no-op, not movePromptToTop's throw: it is already where the
|
|
73
72
|
// reorder would put it, and throwing would flash an error for a press that
|
|
@@ -81,30 +80,30 @@ export function createQueuedPane(session) {
|
|
|
81
80
|
session.flashMessage(outcome.status === "topped"
|
|
82
81
|
? `moved inbox message #${row.position} for ${row.role} to the top: ${outcome.preview}`
|
|
83
82
|
: `inbox message #${row.position} for ${row.role} was already gone`);
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
session.flashError(err);
|
|
87
|
-
}
|
|
83
|
+
});
|
|
88
84
|
};
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
// Ctrl+X cancels the selected queued prompt and Ctrl+V moves it to its role queue's head,
|
|
86
|
+
// each through the CLI's own per-role path (cancelRolePrompt / movePromptToTop). The two
|
|
87
|
+
// arms share one shape — a guarded ctrl-keypress that resolves the clamped selected row,
|
|
88
|
+
// runs cancel or move, and repaints — differing only in the key and the action, so one
|
|
89
|
+
// helper owns the guard, the clamp, and the render.
|
|
90
|
+
const handleQueuedRowAction = (key, ctx, keyName, action) => {
|
|
91
|
+
if (key.ctrl && key.name === keyName &&
|
|
91
92
|
promptLineFree(ctx.es) &&
|
|
92
93
|
session.view === session.roleIds.length + 6 && selectedQueued !== null) {
|
|
93
94
|
const row = queuedRows[Math.min(selectedQueued, queuedRows.length - 1)];
|
|
94
95
|
if (row !== undefined)
|
|
95
|
-
|
|
96
|
+
action(row);
|
|
96
97
|
session.requestRender();
|
|
97
98
|
return true;
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
session.requestRender();
|
|
100
|
+
return false;
|
|
101
|
+
};
|
|
102
|
+
const handleKey = (key, ctx) => {
|
|
103
|
+
if (handleQueuedRowAction(key, ctx, "x", cancelQueuedRow))
|
|
104
|
+
return true;
|
|
105
|
+
if (handleQueuedRowAction(key, ctx, "v", moveQueuedRow))
|
|
106
106
|
return true;
|
|
107
|
-
}
|
|
108
107
|
const arrow = arrowDir(key.name);
|
|
109
108
|
if (session.view === session.roleIds.length + 6 && arrow !== null) {
|
|
110
109
|
// In the Queued pane, up/down select a queued prompt row in full (wrapping, the backlog
|
|
@@ -129,8 +128,7 @@ export function createQueuedPane(session) {
|
|
|
129
128
|
// was cancelled), so the pane shows the same renderQueuedList it entered with. The
|
|
130
129
|
// shared paneScroll resets with the body switch, like a selection move.
|
|
131
130
|
selectedQueued = null;
|
|
132
|
-
session
|
|
133
|
-
session.requestRender();
|
|
131
|
+
paneAtHead(session);
|
|
134
132
|
return true;
|
|
135
133
|
}
|
|
136
134
|
return false;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { collectReport } from "../../report/report-data.js";
|
|
2
2
|
import { collectReportSince } from "../../report/report-since-data.js";
|
|
3
|
-
import { renderReportMarkdown
|
|
3
|
+
import { renderReportMarkdown } from "../../report/report-render.js";
|
|
4
|
+
import { renderSinceReportMarkdown } from "../../report/report-since-render.js";
|
|
4
5
|
import { REPORT_DEFAULT_DAYS, REPORT_SINCE_MAX_MS } from "../../events/event-window.js";
|
|
5
6
|
import { collectFailureReport, collectFailureReportSince } from "../../failure/failure-data.js";
|
|
6
7
|
import { renderFailureMarkdown } from "../../failure/failure-render.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { REPORT_SINCE_MAX_MS } from "../../events/event-window.js";
|
|
2
|
+
import { DAY_MS, HOUR_MS } from "../../text/datetime.js";
|
|
2
3
|
import { HISTORY_RESULT_CLASSES, HISTORY_RESULT_FLAG_NAMES } from "../../history/history-data.js";
|
|
3
4
|
import { baseRoleOf } from "../../roles/runner-ids.js";
|
|
5
|
+
import { distinctOrdered } from "../../collections.js";
|
|
4
6
|
/** Every Ctrl+<key> cycle walks its own ReadonlyArray<[key, label]> table one slot at a time,
|
|
5
7
|
* wrapping past the last back to the first. Each handler holds a key the table carries (a null
|
|
6
8
|
* default slot included), so findIndex always hits. */
|
|
@@ -18,9 +20,9 @@ export function cycleLabel(table, current) {
|
|
|
18
20
|
* report --since`'s bound) rather than History's old hard-coded 604_800_000 magic number, which
|
|
19
21
|
* was the same value but untethered from the cap it mirrors. */
|
|
20
22
|
const SESSION_WINDOW_TAIL = [
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
23
|
+
[HOUR_MS, "1h"],
|
|
24
|
+
[6 * HOUR_MS, "6h"],
|
|
25
|
+
[DAY_MS, "1d"],
|
|
24
26
|
[REPORT_SINCE_MAX_MS, "7d"],
|
|
25
27
|
];
|
|
26
28
|
/** The History pane's session window cycle, Ctrl+S: the default newest-N read, then the same
|
|
@@ -40,13 +42,7 @@ export const HISTORY_WINDOWS = [
|
|
|
40
42
|
* names that collect it identically. `feature`/`feature-2` therefore offer one slot, and the
|
|
41
43
|
* name the tab strip and hint show is the name the collector honors. */
|
|
42
44
|
export function scopeCycle(roleIds) {
|
|
43
|
-
|
|
44
|
-
for (const id of roleIds) {
|
|
45
|
-
const base = baseRoleOf(id);
|
|
46
|
-
if (!bases.includes(base))
|
|
47
|
-
bases.push(base);
|
|
48
|
-
}
|
|
49
|
-
return [null, ...bases];
|
|
45
|
+
return [null, ...distinctOrdered(roleIds.map((id) => baseRoleOf(id)))];
|
|
50
46
|
}
|
|
51
47
|
/** The History pane's session outcome cycle, Ctrl+O: all runs, then the canonical classes
|
|
52
48
|
* `tumwater history --result` and the dashboard's History filter speak. The class list comes
|
|
@@ -131,3 +127,12 @@ export function createTuiPaneSession(deps) {
|
|
|
131
127
|
runPatch: deps.runPatch,
|
|
132
128
|
};
|
|
133
129
|
}
|
|
130
|
+
/** Re-enter the active pane at its head: reset the shared within-body scroll offset to the top
|
|
131
|
+
* and repaint. The panes' key-handler and refresh arms reset the scroll and request a render
|
|
132
|
+
* together every time they return a view to its start, so this single helper keeps that pair
|
|
133
|
+
* from drifting — and names the intent (the pane starts at its head) once instead of at each
|
|
134
|
+
* call site. A key-handler caller that consumed the key follows with its own `return true`. */
|
|
135
|
+
export function paneAtHead(session) {
|
|
136
|
+
session.paneScroll = 0;
|
|
137
|
+
session.requestRender();
|
|
138
|
+
}
|
|
@@ -3,17 +3,19 @@ import { roleNotesPath } from "../../paths.js";
|
|
|
3
3
|
import { renderRoleChange } from "../../change/change-render.js";
|
|
4
4
|
import { readMergeQueue } from "../../merge/merge-queue.js";
|
|
5
5
|
import { renderMergeQueue, scopeMergeQueue } from "../../merge/merge-queue-render.js";
|
|
6
|
-
import { orchestratorAlive } from "../../team/orchestrator-info.js";
|
|
6
|
+
import { orchestratorAlive } from "../../team/team-orchestrator-info.js";
|
|
7
7
|
import { queueInFlight } from "../../status/status-polls.js";
|
|
8
8
|
import { roleInspectMarkdown } from "./tui-pane.js";
|
|
9
9
|
import { pageMarkdownBody } from "./tui-backlog.js";
|
|
10
10
|
import { pageDir } from "./tui-keymap.js";
|
|
11
11
|
import { promptLineFree } from "./tui-pane-ctx.js";
|
|
12
|
+
import { guardError } from "./tui-guard.js";
|
|
13
|
+
import { paneAtHead } from "./tui-pane-session.js";
|
|
12
14
|
/** The per-role transcript panes (views 1..roleIds.length) of the TUI: the Ctrl+N
|
|
13
|
-
* transcript→notes→change cycle and its two-step Ctrl+X notes-clear arm,
|
|
14
|
-
* notes/change PgUp/PgDn body window, and the `/` search over
|
|
15
|
-
* out of the pane-navigation monolith; it owns the
|
|
16
|
-
* touch them. */
|
|
15
|
+
* transcript→notes→change cycle and its two-step Ctrl+X notes-clear arm, the Ctrl+Y
|
|
16
|
+
* change-diff toggle, plus the notes/change PgUp/PgDn body window, and the `/` search over
|
|
17
|
+
* the live transcript step. Split out of the pane-navigation monolith; it owns the
|
|
18
|
+
* notes/change mode state and the arms that touch them. */
|
|
17
19
|
export function createTranscriptPane(session) {
|
|
18
20
|
// Ctrl+N toggles the viewed role's pane between its live transcript and a read-only
|
|
19
21
|
// notes view (its note and next run's prompt). Like paneCache, noteCache is computed
|
|
@@ -53,17 +55,13 @@ export function createTranscriptPane(session) {
|
|
|
53
55
|
const target = role;
|
|
54
56
|
// The role's waiting merges head the change, exact-matching this one runner id.
|
|
55
57
|
let queueText = "";
|
|
56
|
-
|
|
58
|
+
guardError(session, () => {
|
|
57
59
|
const { view, scope } = scopeMergeQueue(readMergeQueue(session.root), [role], (r) => r === role);
|
|
58
60
|
if (view.entries.length > 0) {
|
|
59
61
|
const inFlight = queueInFlight(session.root, view.entries, orchestratorAlive(session.root));
|
|
60
62
|
queueText = renderMergeQueue(view, session.now(), inFlight, scope) + "\n\n";
|
|
61
63
|
}
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
queueText = "";
|
|
65
|
-
session.flashError(err);
|
|
66
|
-
}
|
|
64
|
+
});
|
|
67
65
|
void session.collectChange(session.root, target, changeStat ? { stat: true } : undefined).then((change) => {
|
|
68
66
|
// changeGen drops a load superseded by a re-load or a leave; the role match drops one
|
|
69
67
|
// a roster change (syncRoster mutates session.roleIds without resetting this pane)
|
|
@@ -83,9 +81,8 @@ export function createTranscriptPane(session) {
|
|
|
83
81
|
// because routeCtrlN in tui-panes.ts routes it last and relies on this pane consuming
|
|
84
82
|
// Ctrl+N as the fallback.
|
|
85
83
|
const transcriptCycle = (ctx) => {
|
|
86
|
-
// Ctrl+N cycles the viewed role's pane live transcript → notes → change → transcript
|
|
87
|
-
//
|
|
88
|
-
// loop's pending change in the TUI transcript pane"). The change step renders the same
|
|
84
|
+
// Ctrl+N cycles the viewed role's pane live transcript → notes → change → transcript.
|
|
85
|
+
// The change step renders the same
|
|
89
86
|
// collectRoleChange/renderRoleChange view the CLI's `tumwater diff --role <id>` and the
|
|
90
87
|
// dashboard drawer use. Guarded to a transcript view and out of budget-edit and
|
|
91
88
|
// role-prompt modes, the same way the per-role controls below are; the History view's
|
|
@@ -123,17 +120,13 @@ export function createTranscriptPane(session) {
|
|
|
123
120
|
// rolePayload reads the notes and assembles the next run's prompt off disk; a
|
|
124
121
|
// throw leaves the transcript shown (the mode stays off) and flashes the reason
|
|
125
122
|
// instead of escaping the handler and killing the TUI.
|
|
126
|
-
|
|
123
|
+
noteCache = null;
|
|
124
|
+
guardError(session, () => {
|
|
127
125
|
noteCache = roleInspectMarkdown(session.root, role);
|
|
128
126
|
noteMode = true;
|
|
129
|
-
}
|
|
130
|
-
catch (err) {
|
|
131
|
-
noteCache = null;
|
|
132
|
-
session.flashError(err);
|
|
133
|
-
}
|
|
127
|
+
});
|
|
134
128
|
}
|
|
135
|
-
session
|
|
136
|
-
session.requestRender();
|
|
129
|
+
paneAtHead(session);
|
|
137
130
|
return true;
|
|
138
131
|
};
|
|
139
132
|
// The Ctrl+Y diffstat toggle, live only on the change step (mnemonic: summarY). Returns
|
|
@@ -166,14 +159,11 @@ export function createTranscriptPane(session) {
|
|
|
166
159
|
}
|
|
167
160
|
const role = viewedRole();
|
|
168
161
|
if (session.armedNotes === role) {
|
|
169
|
-
|
|
162
|
+
guardError(session, () => {
|
|
170
163
|
session.flashMessage(`${role}: ${saveRoleNote(roleNotesPath(session.root, role), "")}`);
|
|
171
164
|
noteCache = roleInspectMarkdown(session.root, role);
|
|
172
165
|
session.paneScroll = 0;
|
|
173
|
-
}
|
|
174
|
-
catch (err) {
|
|
175
|
-
session.flashError(err);
|
|
176
|
-
}
|
|
166
|
+
});
|
|
177
167
|
}
|
|
178
168
|
else {
|
|
179
169
|
session.notesClearArmed = role;
|
|
@@ -216,8 +206,7 @@ export function createTranscriptPane(session) {
|
|
|
216
206
|
if (!noteMode || viewedRole() !== role)
|
|
217
207
|
return;
|
|
218
208
|
noteCache = roleInspectMarkdown(session.root, role);
|
|
219
|
-
session
|
|
220
|
-
session.requestRender();
|
|
209
|
+
paneAtHead(session);
|
|
221
210
|
},
|
|
222
211
|
reset() {
|
|
223
212
|
// A cycle away leaves notes and change modes and drops their snapshots; changeGen
|
|
@@ -238,8 +227,7 @@ export function createTranscriptPane(session) {
|
|
|
238
227
|
if (session.view < 1 || session.view > session.roleIds.length)
|
|
239
228
|
return;
|
|
240
229
|
transcriptSearch = pattern === null ? null : { role: viewedRole(), pattern };
|
|
241
|
-
session
|
|
242
|
-
session.requestRender();
|
|
230
|
+
paneAtHead(session);
|
|
243
231
|
},
|
|
244
232
|
state() {
|
|
245
233
|
const transcriptGrep = transcriptSearch !== null && viewedRole() === transcriptSearch.role
|
|
@@ -11,7 +11,7 @@ import { eventMatchesGrep, eventResult, formatEvent } from "../../events/event-f
|
|
|
11
11
|
import { eventTypeLabel } from "../../events/event-labels.js";
|
|
12
12
|
import { eventTypeTally } from "../../events/event-tally.js";
|
|
13
13
|
import { backlogLines, entryBodyWindow, browsableBacklogEntries, isOpenBacklogLabel, planListLines } from "./tui-backlog.js";
|
|
14
|
-
import { answeredQuestionSummaries } from "../../backlog/question-answer.js";
|
|
14
|
+
import { answeredQuestionSummaries } from "../../backlog/backlog-question-answer.js";
|
|
15
15
|
import { DASHBOARD_ANSWERED_QUESTIONS, recentFinished } from "../status-payload.js";
|
|
16
16
|
import { donePlanEntries, DONE_DATE_RE, entryMatches, FIXED_DATE_RE, fixedBugEntries } from "../../backlog/backlog.js";
|
|
17
17
|
import { isNotableEvent } from "../tone.js";
|
|
@@ -42,6 +42,14 @@ export function activityEvents(root, role, grep, type, notable = false) {
|
|
|
42
42
|
export function roleInspectMarkdown(root, role) {
|
|
43
43
|
return inspectMarkdownLines(rolePayload(root, role), Date.now()).join("\n");
|
|
44
44
|
}
|
|
45
|
+
/** The pane's cached body windowed to its clipped lines, or no lines while the cache is still
|
|
46
|
+
* null (the async collector has not resolved yet) — so the frame prints the pane's own
|
|
47
|
+
* loading/empty note rather than entryBodyWindow's "(no details for this entry)" placeholder.
|
|
48
|
+
* Shared by the history, pending, health, brief, and queued panes, whose bodies differ only in
|
|
49
|
+
* that note, so the null-cache shape cannot drift between them. */
|
|
50
|
+
function paneCacheLines(state, budget, width) {
|
|
51
|
+
return state.paneCache ? entryBodyWindow(state.paneCache, state.paneScroll, budget, width).lines : [];
|
|
52
|
+
}
|
|
45
53
|
/** Compose the body lines for one pane at this frame's width and budgets. Same rules
|
|
46
54
|
* tui.tsx's inline builder followed: transcripts keep the tail, the backlog list keeps
|
|
47
55
|
* the head with the selected entry's full body in entry mode, usage/failures re-window
|
|
@@ -187,9 +195,8 @@ function historyBody(pane, opts) {
|
|
|
187
195
|
// historyPaneText returns "" when the log holds no completed runs; return no lines
|
|
188
196
|
// (rather than windowing an empty string, which entryBodyWindow replaces with its
|
|
189
197
|
// "no details" placeholder) so the frame prints the pane's own empty note instead.
|
|
190
|
-
const win = state.paneCache ? entryBodyWindow(state.paneCache, state.paneScroll, eventBudget, width) : { lines: [] };
|
|
191
198
|
return {
|
|
192
|
-
body:
|
|
199
|
+
body: paneCacheLines(state, eventBudget, width).map((l) => toneLine(l, width)),
|
|
193
200
|
emptyNote: "(no runs yet)",
|
|
194
201
|
};
|
|
195
202
|
}
|
|
@@ -207,25 +214,22 @@ function pendingBody(_pane, opts) {
|
|
|
207
214
|
emptyNote: "(loading pending changes…)",
|
|
208
215
|
};
|
|
209
216
|
}
|
|
210
|
-
const win = state.paneCache ? entryBodyWindow(state.paneCache, state.paneScroll, eventBudget, width) : { lines: [] };
|
|
211
217
|
return {
|
|
212
|
-
body:
|
|
218
|
+
body: paneCacheLines(state, eventBudget, width).map((l) => toneLine(l, width)),
|
|
213
219
|
emptyNote: "(loading pending changes…)",
|
|
214
220
|
};
|
|
215
221
|
}
|
|
216
222
|
function healthBody(_pane, opts) {
|
|
217
223
|
const { width, eventBudget, state } = opts;
|
|
218
|
-
const win = state.paneCache ? entryBodyWindow(state.paneCache, state.paneScroll, eventBudget, width) : { lines: [] };
|
|
219
224
|
return {
|
|
220
|
-
body:
|
|
225
|
+
body: paneCacheLines(state, eventBudget, width).map((l) => toneLine(l, width)),
|
|
221
226
|
emptyNote: "(running health checks…)",
|
|
222
227
|
};
|
|
223
228
|
}
|
|
224
229
|
function briefBody(_pane, opts) {
|
|
225
230
|
const { width, eventBudget, state } = opts;
|
|
226
|
-
const win = state.paneCache ? entryBodyWindow(state.paneCache, state.paneScroll, eventBudget, width) : { lines: [] };
|
|
227
231
|
return {
|
|
228
|
-
body:
|
|
232
|
+
body: paneCacheLines(state, eventBudget, width).map((l) => toneLine(l, width)),
|
|
229
233
|
emptyNote: "(no project brief with a prompt block — run `tumwater init` first)",
|
|
230
234
|
};
|
|
231
235
|
}
|
|
@@ -257,9 +261,8 @@ function queuedBody(pane, opts) {
|
|
|
257
261
|
return { body: [...searchLine, toneLine(`(no queued prompt matches "${pane.grep}")`, width)], emptyNote: "(inbox empty)" };
|
|
258
262
|
}
|
|
259
263
|
const listBudget = Math.max(1, eventBudget - searchLine.length);
|
|
260
|
-
const win = state.paneCache ? entryBodyWindow(state.paneCache, state.paneScroll, listBudget, width) : { lines: [] };
|
|
261
264
|
return {
|
|
262
|
-
body: [...searchLine, ...
|
|
265
|
+
body: [...searchLine, ...paneCacheLines(state, listBudget, width).map((l) => toneLine(l, width))],
|
|
263
266
|
emptyNote: "(inbox empty)",
|
|
264
267
|
};
|
|
265
268
|
}
|
|
@@ -154,7 +154,15 @@ export function createTuiPanes(deps) {
|
|
|
154
154
|
return true;
|
|
155
155
|
return report.handleKey?.(key, ctx) ?? false;
|
|
156
156
|
};
|
|
157
|
-
const routeCtrlK = (key, ctx) =>
|
|
157
|
+
const routeCtrlK = (key, ctx) => {
|
|
158
|
+
// Health owns Ctrl+K (kill orphans), routed ahead of every other pane like the other
|
|
159
|
+
// Health arms; its own two-step kill arm consumes the key on the Health view and falls
|
|
160
|
+
// through (returns false) off it. The explicit guard keeps the key in the Ctrl set the
|
|
161
|
+
// TUI keys docs check scans, matching the rest of these routers.
|
|
162
|
+
if (key.ctrl && key.name === "k")
|
|
163
|
+
return health.handleKey?.(key, ctx) ?? false;
|
|
164
|
+
return false;
|
|
165
|
+
};
|
|
158
166
|
const routeCtrlW = (key, ctx) => history.handleKey?.(key, ctx) ?? false;
|
|
159
167
|
const routeCtrlS = (key, ctx) => {
|
|
160
168
|
// Health owns Ctrl+S (drop broken pins) ahead of the pane router's fallthrough; off the
|
|
@@ -318,6 +326,32 @@ export function createTuiPanes(deps) {
|
|
|
318
326
|
return true;
|
|
319
327
|
return queued.handleKey?.(key, ctx) ?? false;
|
|
320
328
|
};
|
|
329
|
+
/** The ordered Ctrl dispatch table: each letter a pane router serves maps to its handler. */
|
|
330
|
+
const ctrlRoutes = {
|
|
331
|
+
n: routeCtrlN,
|
|
332
|
+
g: routeCtrlG,
|
|
333
|
+
e: routeCtrlE,
|
|
334
|
+
k: routeCtrlK,
|
|
335
|
+
w: routeCtrlW,
|
|
336
|
+
s: routeCtrlS,
|
|
337
|
+
p: routeCtrlP,
|
|
338
|
+
a: routeCtrlA,
|
|
339
|
+
u: routeCtrlU,
|
|
340
|
+
b: routeCtrlB,
|
|
341
|
+
l: routeCtrlL,
|
|
342
|
+
y: routeCtrlY,
|
|
343
|
+
o: routeCtrlO,
|
|
344
|
+
x: routeCtrlX,
|
|
345
|
+
r: routeCtrlR,
|
|
346
|
+
v: routeCtrlV,
|
|
347
|
+
};
|
|
348
|
+
/** Look up one bound Ctrl key in `ctrlRoutes`; null when the key is not a bound Ctrl chord. */
|
|
349
|
+
const ctrlRoute = (key, ctx) => {
|
|
350
|
+
if (!key.ctrl || key.name === undefined)
|
|
351
|
+
return null;
|
|
352
|
+
const route = ctrlRoutes[key.name];
|
|
353
|
+
return route === undefined ? null : route(key, ctx);
|
|
354
|
+
};
|
|
321
355
|
/** Run the pane arms of the key dispatch; true when one consumed the key. `es` is the
|
|
322
356
|
* editors' state, so the exclusion guards read the flags the editors hold. Each pane module
|
|
323
357
|
* checks its own view/guard and returns true only when it consumed the key; this router keeps
|
|
@@ -327,38 +361,9 @@ export function createTuiPanes(deps) {
|
|
|
327
361
|
// writes the line and return true whenever one is open — but each module restates its
|
|
328
362
|
// mutual-exclusion guard so it reads on its own instead of leaning on the routing order.
|
|
329
363
|
const ctx = { es };
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
return routeCtrlG(key, ctx);
|
|
334
|
-
if (key.ctrl && key.name === "e")
|
|
335
|
-
return routeCtrlE(key, ctx);
|
|
336
|
-
if (key.ctrl && key.name === "k")
|
|
337
|
-
return routeCtrlK(key, ctx);
|
|
338
|
-
if (key.ctrl && key.name === "w")
|
|
339
|
-
return routeCtrlW(key, ctx);
|
|
340
|
-
if (key.ctrl && key.name === "s")
|
|
341
|
-
return routeCtrlS(key, ctx);
|
|
342
|
-
if (key.ctrl && key.name === "p")
|
|
343
|
-
return routeCtrlP(key, ctx);
|
|
344
|
-
if (key.ctrl && key.name === "a")
|
|
345
|
-
return routeCtrlA(key, ctx);
|
|
346
|
-
if (key.ctrl && key.name === "u")
|
|
347
|
-
return routeCtrlU(key, ctx);
|
|
348
|
-
if (key.ctrl && key.name === "b")
|
|
349
|
-
return routeCtrlB(key, ctx);
|
|
350
|
-
if (key.ctrl && key.name === "l")
|
|
351
|
-
return routeCtrlL(key, ctx);
|
|
352
|
-
if (key.ctrl && key.name === "y")
|
|
353
|
-
return routeCtrlY(key, ctx);
|
|
354
|
-
if (key.ctrl && key.name === "o")
|
|
355
|
-
return routeCtrlO(key, ctx);
|
|
356
|
-
if (key.ctrl && key.name === "x")
|
|
357
|
-
return routeCtrlX(key, ctx);
|
|
358
|
-
if (key.ctrl && key.name === "r")
|
|
359
|
-
return routeCtrlR(key, ctx);
|
|
360
|
-
if (key.ctrl && key.name === "v")
|
|
361
|
-
return routeCtrlV(key, ctx);
|
|
364
|
+
const ctrl = ctrlRoute(key, ctx);
|
|
365
|
+
if (ctrl !== null)
|
|
366
|
+
return ctrl;
|
|
362
367
|
const arrow = arrowDir(key.name);
|
|
363
368
|
if (arrow !== null)
|
|
364
369
|
return routeArrow(key, ctx);
|
package/dist/src/ui/tui/tui.js
CHANGED
|
@@ -2,13 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { render as inkRender } from "ink";
|
|
3
3
|
import { TuiApp } from "./tui-app.js";
|
|
4
4
|
import { openQuestions } from "../../backlog/backlog.js";
|
|
5
|
-
import { refusedEntries
|
|
6
|
-
import {
|
|
7
|
-
import { strandedPlanEntriesFor } from "../../backlog/backlog-structure.js";
|
|
8
|
-
import { duplicatedBacklogHeadings, fixClaimProblems, liveFinishedEntriesFor, validationGapProblems } from "../../doctor/doctor-backlog-plans.js";
|
|
5
|
+
import { refusedEntries } from "../../backlog/backlog-eligibility.js";
|
|
6
|
+
import { getOrphanAlert } from "../alert-feeds.js";
|
|
9
7
|
import { snapshot } from "../../status/status-data.js";
|
|
10
8
|
import { renderStatusSpans } from "../status-render.js";
|
|
11
|
-
import { staleClaimEntries } from "../../scheduling/claim-entries.js";
|
|
12
9
|
import { teamAlerts } from "../team-alerts.js";
|
|
13
10
|
import { captureStartupBuild, createReloadWatch, reexecSelf, watchReloadSupervisor, } from "../../redeploy/self-reload.js";
|
|
14
11
|
import { renderInputView, tuiTerminalError, } from "./tui-input.js";
|
|
@@ -93,7 +90,7 @@ export async function runTui(root, seams = {}) {
|
|
|
93
90
|
const view = s.view;
|
|
94
91
|
// What needs the operator — the dashboard's alert banners (team-alerts.ts's teamAlerts), as
|
|
95
92
|
// attention lines under the header. Each consumes one line of the height budget.
|
|
96
|
-
const attention = alertLines(teamAlerts(snap, openQuestions(root), status.roles, Date.now(), refusedEntries(root),
|
|
93
|
+
const attention = alertLines(teamAlerts(snap, openQuestions(root), status.roles, Date.now(), refusedEntries(root), getOrphanAlert(root)), width);
|
|
97
94
|
const statusLines = [status.lines[0] ?? [], ...attention, ...status.lines.slice(1)];
|
|
98
95
|
// Numbered previews of prompts queued for the director, between the table and the
|
|
99
96
|
// activity pane: what will run next, in execution order. Each line consumes exactly
|
|
@@ -124,7 +121,7 @@ export async function runTui(root, seams = {}) {
|
|
|
124
121
|
// The frame as the ink tree draws it (tui-app.tsx): the same composed lines the
|
|
125
122
|
// hand-painted string frame joined, as clipped StatusLines — one column row per line,
|
|
126
123
|
// one styled Text per span, colors through tui-app.tsx's toneColor.
|
|
127
|
-
const mode = { budget: s.budgetMode, concurrencyMode: s.concurrencyMode, checksMode: s.checksMode, checkMode: s.checkMode, fallbackMode: s.fallbackMode, modelMode: s.modelMode, rolePromptFor: s.rolePromptFor, attachMode: s.attachMode, pauseEditMode: s.pauseEditMode, pauseEditRole: s.pauseEditRole, pauseEditWake: s.pauseEditWake, pauseEditStop: s.pauseEditStop, queuedEditFor: s.queuedEditFor, answerFor: s.answerFor, entryEditFor: s.entryEditFor, notesEditFor: s.notesEditFor, briefEditMode: s.briefEditMode, retireMode: s.retireMode, releaseMode: s.releaseMode, roleEnabledMode: s.roleEnabledMode, quietMode: s.quietMode, quietTeam: s.quietTeam,
|
|
124
|
+
const mode = { budget: s.budgetMode, concurrencyMode: s.concurrencyMode, checksMode: s.checksMode, checkMode: s.checkMode, fallbackMode: s.fallbackMode, modelMode: s.modelMode, rolePromptFor: s.rolePromptFor, attachMode: s.attachMode, pauseEditMode: s.pauseEditMode, pauseEditRole: s.pauseEditRole, pauseEditWake: s.pauseEditWake, pauseEditStop: s.pauseEditStop, queuedEditFor: s.queuedEditFor, answerFor: s.answerFor, entryEditFor: s.entryEditFor, notesEditFor: s.notesEditFor, briefEditMode: s.briefEditMode, retireMode: s.retireMode, releaseMode: s.releaseMode, roleEnabledMode: s.roleEnabledMode, quietMode: s.quietMode, quietTeam: s.quietTeam, intervalMode: s.intervalMode, roleModelMode: s.roleModelMode, instructionsEditFor: s.instructionsEditFor, slotsMode: s.slotsMode, images: s.images, notifyMode: s.notifyMode, backendsMode: s.backendsMode, instancesMode: s.instancesMode };
|
|
128
125
|
const lines = [...statusLines, []]; // a blank row below the header
|
|
129
126
|
for (const [i, preview] of queued.entries())
|
|
130
127
|
lines.push(toneLine(`${i + 1}. ${preview}`, width));
|