tumwater 0.4.0 → 0.4.2
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 +4 -6
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-backend.js +5 -2
- package/dist/src/agent/backend-traits.js +21 -0
- package/dist/src/agent/claude/claude-backend.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +181 -182
- package/dist/src/agent/claude/{write-guard-hook.js → claude-write-guard-hook.js} +1 -1
- package/dist/src/agent/claude/claude-write-guard.js +5 -4
- package/dist/src/agent/codex/codex-backend.js +1 -1
- package/dist/src/agent/codex/codex-rollout.js +48 -45
- package/dist/src/agent/codex/codex-stream.js +269 -215
- package/dist/src/agent/codex/{write-guard-hook.js → codex-write-guard-hook.js} +2 -1
- package/dist/src/agent/codex/codex-write-guard.js +3 -3
- package/dist/src/agent/image-input.js +18 -87
- package/dist/src/agent/notes-shim.js +2 -2
- package/dist/src/agent/opencode/opencode-backend.js +2 -2
- package/dist/src/agent/opencode/opencode-catalog.js +2 -2
- package/dist/src/agent/opencode/opencode-config.js +2 -2
- package/dist/src/agent/opencode/opencode-stream.js +101 -92
- package/dist/src/agent/run-agent.js +76 -382
- package/dist/src/agent/run-settle.js +25 -15
- package/dist/src/agent/run-spawn.js +226 -0
- package/dist/src/agent/run-stream.js +185 -0
- package/dist/src/agent/session-ledger.js +16 -0
- package/dist/src/agent/write-guard.js +5 -3
- package/dist/src/backlog/backlog-archive.js +86 -170
- package/dist/src/backlog/backlog-cli-view.js +89 -70
- package/dist/src/backlog/backlog-eligibility.js +51 -59
- package/dist/src/backlog/backlog-file-bugs.js +133 -0
- package/dist/src/backlog/backlog-index-data.js +159 -0
- package/dist/src/backlog/backlog-index.js +7 -5
- package/dist/src/backlog/backlog-md.js +39 -28
- package/dist/src/backlog/backlog-release.js +21 -36
- package/dist/src/backlog/backlog-render.js +1 -1
- package/dist/src/backlog/backlog-structure.js +14 -145
- package/dist/src/backlog/backlog-write.js +31 -18
- package/dist/src/backlog/backlog.js +14 -4
- package/dist/src/backlog/question-answer.js +33 -15
- package/dist/src/baseline/main-baseline.js +71 -26
- package/dist/src/baseline/main-guardrails.js +76 -15
- package/dist/src/baseline/main-red.js +45 -94
- package/dist/src/baseline/main-watch.js +9 -3
- package/dist/src/brief/brief.js +40 -0
- package/dist/src/budget/budget-fallback-view.js +50 -8
- package/dist/src/budget/budget-wiring.js +15 -11
- package/dist/src/budget/budget.js +3 -2
- package/dist/src/build/build-check-events.js +4 -2
- package/dist/src/build/build-check-report.js +2 -1
- package/dist/src/build/build-check-scoped.js +70 -41
- package/dist/src/change/change-data.js +4 -2
- package/dist/src/cli/cli-args.js +9 -0
- package/dist/src/cli/cli-command-args.js +199 -98
- package/dist/src/cli/cli-flag-specs.js +6 -4
- package/dist/src/cli/cli-marker-commands.js +2 -2
- package/dist/src/cli/cli-query-commands.js +41 -6
- package/dist/src/cli/cli-review-commands.js +2 -1
- package/dist/src/cli/cli-role-command.js +46 -92
- package/dist/src/cli/cli-start.js +123 -47
- package/dist/src/cli/follow-view.js +3 -1
- package/dist/src/cli/help.js +19 -12
- package/dist/src/cli/log-commands.js +128 -107
- package/dist/src/cli/question-commands.js +82 -63
- package/dist/src/cli.js +396 -343
- package/dist/src/collections.js +46 -9
- package/dist/src/config/config-fallbacks.js +0 -4
- package/dist/src/config/config-live.js +179 -147
- package/dist/src/config/config-request.js +176 -51
- package/dist/src/config/config-validation-roles.js +271 -0
- package/dist/src/config/config-validation.js +10 -205
- package/dist/src/config/config-views.js +2 -7
- package/dist/src/config/config-write.js +205 -175
- package/dist/src/config/config.js +2 -1
- package/dist/src/doctor/doctor-backlog-bugs.js +24 -122
- package/dist/src/doctor/doctor-backlog-plans.js +24 -25
- package/dist/src/doctor/doctor-backlog.js +34 -42
- package/dist/src/doctor/doctor-check-names.js +4 -2
- package/dist/src/doctor/doctor-checks.js +16 -4
- package/dist/src/doctor/doctor-claude-checks.js +2 -2
- package/dist/src/doctor/doctor-codex-checks.js +9 -20
- package/dist/src/doctor/doctor-contention-checks.js +52 -19
- package/dist/src/doctor/doctor-holds.js +22 -20
- package/dist/src/doctor/doctor-model-checks.js +8 -184
- package/dist/src/doctor/doctor-notify.js +2 -5
- package/dist/src/doctor/doctor-opencode-checks.js +90 -41
- package/dist/src/doctor/doctor-principles.js +26 -0
- package/dist/src/doctor/doctor-project-checks.js +69 -19
- package/dist/src/doctor/doctor-role-notes.js +33 -0
- package/dist/src/doctor/doctor.js +13 -6
- package/dist/src/doctor/probe.js +1 -1
- package/dist/src/events/event-format.js +307 -162
- package/dist/src/events/event-labels.js +0 -1
- package/dist/src/events/event-legacy.js +1 -1
- package/dist/src/events/event-window.js +1 -1
- package/dist/src/events/events.js +15 -2
- package/dist/src/events/notify.js +1 -1
- package/dist/src/failure/failure-cluster.js +4 -3
- package/dist/src/failure/failure-data.js +126 -94
- package/dist/src/failure/failure-render.js +58 -17
- package/dist/src/failure/failure-state-change.js +308 -27
- package/dist/src/failure/time-spend.js +139 -106
- package/dist/src/files/files.js +7 -0
- package/dist/src/files/json-object.js +15 -2
- package/dist/src/gates/budget-gates.js +90 -68
- package/dist/src/gates/gate-polls.js +92 -61
- package/dist/src/gates/role-cap-gates.js +1 -1
- package/dist/src/gates/startup-gate.js +28 -28
- package/dist/src/gates/streak-gate.js +1 -1
- package/dist/src/git/git.js +1 -1
- package/dist/src/git/slot-salvage.js +9 -9
- package/dist/src/git/slots-state.js +12 -3
- package/dist/src/git/worktree-pool-startup.js +127 -0
- package/dist/src/git/worktree-pool.js +1 -120
- package/dist/src/gui/gui-admin-endpoints.js +3 -4
- package/dist/src/gui/gui-args.js +1 -1
- package/dist/src/gui/gui-backlog-commands.js +20 -11
- package/dist/src/gui/gui-backlog-endpoints.js +2 -8
- package/dist/src/gui/gui-config-commands.js +51 -76
- package/dist/src/gui/gui-endpoint-commands.js +4 -2
- package/dist/src/gui/gui-endpoint-common.js +4 -3
- package/dist/src/gui/gui-history-endpoints.js +36 -27
- package/dist/src/gui/gui-operator-commands.js +43 -17
- package/dist/src/gui/gui-prompt-commands.js +27 -21
- package/dist/src/gui/gui-quarantine-commands.js +30 -0
- package/dist/src/gui/gui-report-endpoints.js +13 -9
- package/dist/src/gui/gui-server.js +5 -3
- package/dist/src/gui/gui-team-commands.js +1 -1
- package/dist/src/history/history-data.js +7 -1
- package/dist/src/history/history-render.js +15 -10
- package/dist/src/history/history.js +103 -68
- package/dist/src/inbox/inbox-submit.js +1 -5
- package/dist/src/inbox/pending-prompt.js +3 -2
- package/dist/src/inbox/prompt-commands.js +194 -161
- package/dist/src/init/init.js +104 -25
- package/dist/src/merge/merge-core.js +1 -1
- package/dist/src/merge/merge-drain.js +1 -1
- package/dist/src/merge/merge-git.js +5 -5
- package/dist/src/merge/{merge-post-review.js → merge-post-review-drain.js} +1 -1
- package/dist/src/merge/merge-queue.js +2 -1
- package/dist/src/merge/merge-to-main.js +1 -1
- package/dist/src/merge/merge-verify.js +3 -2
- package/dist/src/operator/operator-commands.js +84 -52
- package/dist/src/operator/operator-intent.js +26 -3
- package/dist/src/operator/retire.js +2 -1
- package/dist/src/operator/revert.js +18 -12
- package/dist/src/orchestrator/orchestrator-poll.js +2 -2
- package/dist/src/orchestrator/orchestrator.js +1 -1
- package/dist/src/orchestrator/retention.js +6 -5
- package/dist/src/paths.js +10 -10
- package/dist/src/pi/pi-bin.js +2 -2
- package/dist/src/pi/pi-models.js +9 -0
- package/dist/src/pi/pi-stream.js +63 -41
- package/dist/src/pi/pi-watchdogs.js +84 -49
- package/dist/src/pi-extension/context-shake.js +55 -31
- package/dist/src/pi-extension/full-output.js +2 -3
- package/dist/src/process/process.js +24 -1
- package/dist/src/process/run-marker.js +2 -2
- package/dist/src/process/supervisor.js +24 -5
- package/dist/src/prompt/gate-notes.js +41 -16
- package/dist/src/prompt/notes-backlog.js +22 -29
- package/dist/src/prompt/principles.js +11 -0
- package/dist/src/prompt/prompt-followup.js +4 -12
- package/dist/src/prompt/prompt.js +15 -12
- package/dist/src/redeploy/redeploy-probes.js +11 -1
- package/dist/src/redeploy/redeployer.js +54 -7
- package/dist/src/redeploy/self-reload.js +7 -2
- package/dist/src/report/report-data.js +224 -320
- package/dist/src/report/report-fold.js +23 -231
- package/dist/src/report/report-main-red.js +70 -3
- package/dist/src/report/report-render.js +181 -48
- package/dist/src/report/report-since-data.js +218 -0
- package/dist/src/report/report-usage-fold.js +288 -0
- package/dist/src/report/report.js +2 -1
- package/dist/src/review/known-flakes.js +22 -3
- package/dist/src/review/post-merge-review-accept.js +3 -2
- package/dist/src/review/post-merge-review.js +16 -14
- package/dist/src/review/quarantine-render.js +29 -11
- package/dist/src/review/review-precheck.js +2 -1
- package/dist/src/roles/role-catalog.js +30 -29
- package/dist/src/roles/role-guidance.js +26 -43
- package/dist/src/roles/role-render.js +19 -0
- package/dist/src/roles/role-view.js +19 -5
- package/dist/src/roles/roles.js +2 -22
- package/dist/src/run/ci-parity.js +5 -6
- package/dist/src/run/feedback-filings.js +10 -1
- package/dist/src/run/qa-coverage.js +4 -4
- package/dist/src/run/run-apply.js +14 -2
- package/dist/src/run/run-detail-data.js +50 -10
- package/dist/src/run/run-detail-render.js +32 -1
- package/dist/src/run/run-detail.js +44 -22
- package/dist/src/run/run-dismiss.js +43 -0
- package/dist/src/run/run-finalize.js +75 -46
- package/dist/src/run/run-prompt.js +271 -187
- package/dist/src/run/run-resume.js +32 -31
- package/dist/src/run/run-stage.js +116 -64
- package/dist/src/run/run-timing.js +18 -4
- package/dist/src/run/run-verdict.js +119 -83
- package/dist/src/run/stage-backlog-checks.js +4 -31
- package/dist/src/run/stage-check.js +4 -12
- package/dist/src/run/stage-checks-shared.js +15 -0
- package/dist/src/run/stage-name-checks.js +3 -13
- package/dist/src/run/stage-path-checks.js +26 -29
- package/dist/src/runner/leftover.js +13 -4
- package/dist/src/runner/revision.js +2 -2
- package/dist/src/runner/runner-fallback.js +1 -1
- package/dist/src/runner/runner-outcome.js +0 -5
- package/dist/src/runner/runner-pi.js +72 -49
- package/dist/src/runner/runner-run.js +19 -102
- package/dist/src/runner/runner-state-load.js +0 -10
- package/dist/src/runner/runner.js +1 -32
- package/dist/src/scheduling/claims.js +4 -11
- package/dist/src/status/status-data.js +140 -91
- package/dist/src/status/status-polls.js +41 -5
- package/dist/src/status/status-role-notes.js +53 -0
- package/dist/src/status/status-roles.js +10 -37
- package/dist/src/text/datetime.js +8 -1
- package/dist/src/text/format.js +13 -1
- package/dist/src/text/phrases.js +16 -2
- package/dist/src/text/text.js +12 -0
- package/dist/src/ui/alert-feeds.js +115 -0
- package/dist/src/ui/badges.js +3 -4
- package/dist/src/ui/gui/gui-client-boot.js +78 -57
- package/dist/src/ui/gui/gui-client-drawer-config.js +8 -3
- package/dist/src/ui/gui/gui-client-drawer.js +18 -2
- package/dist/src/ui/gui/gui-client-feed.js +3 -8
- package/dist/src/ui/gui/gui-client-history.js +16 -16
- package/dist/src/ui/gui/gui-client-model.js +9 -9
- package/dist/src/ui/gui/gui-client-operator.js +6 -10
- package/dist/src/ui/gui/gui-client-pending.js +4 -4
- package/dist/src/ui/gui/gui-client-report-chart.js +111 -10
- package/dist/src/ui/gui/gui-client-report.js +70 -11
- package/dist/src/ui/gui/gui-client-roles.js +52 -12
- package/dist/src/ui/gui/gui-client-settings.js +31 -26
- package/dist/src/ui/gui/gui-client-team.js +28 -2
- package/dist/src/ui/gui/gui-client.js +33 -4
- package/dist/src/ui/gui/gui-icons.js +7 -1
- package/dist/src/ui/progress-data.js +2 -2
- package/dist/src/ui/run-progress-model.js +2 -2
- package/dist/src/ui/status-model.js +26 -16
- package/dist/src/ui/status-payload.js +149 -326
- package/dist/src/ui/status-render.js +131 -80
- package/dist/src/ui/team-alert-backlog.js +236 -0
- package/dist/src/ui/team-alert-shared.js +92 -0
- package/dist/src/ui/team-alert-status.js +326 -0
- package/dist/src/ui/team-alert-tail.js +238 -0
- package/dist/src/ui/team-alerts.js +16 -984
- package/dist/src/ui/transcript-tail.js +137 -94
- package/dist/src/ui/tui/tui-backlog.js +1 -1
- package/dist/src/ui/tui/tui-editor-answer.js +54 -44
- package/dist/src/ui/tui/tui-editor-attach.js +74 -63
- package/dist/src/ui/tui/tui-editor-backends.js +62 -56
- package/dist/src/ui/tui/tui-editor-brief.js +64 -54
- package/dist/src/ui/tui/tui-editor-budget.js +106 -89
- package/dist/src/ui/tui/tui-editor-config.js +2 -4
- package/dist/src/ui/tui/tui-editor-ctx.js +12 -1
- package/dist/src/ui/tui/tui-editor-entry.js +171 -153
- package/dist/src/ui/tui/tui-editor-instances.js +2 -1
- package/dist/src/ui/tui/tui-editor-instructions.js +50 -107
- package/dist/src/ui/tui/tui-editor-interval.js +39 -112
- package/dist/src/ui/tui/tui-editor-notes.js +28 -84
- package/dist/src/ui/tui/tui-editor-pause.js +210 -183
- package/dist/src/ui/tui/tui-editor-prompt.js +46 -35
- package/dist/src/ui/tui/tui-editor-queued.js +74 -64
- package/dist/src/ui/tui/tui-editor-quiet.js +122 -108
- package/dist/src/ui/tui/tui-editor-release.js +85 -0
- package/dist/src/ui/tui/tui-editor-retire.js +57 -46
- package/dist/src/ui/tui/tui-editor-role-enabled.js +90 -80
- package/dist/src/ui/tui/tui-editor-role-file.js +87 -0
- package/dist/src/ui/tui/tui-editor-role-key.js +50 -42
- package/dist/src/ui/tui/tui-editor-search.js +70 -58
- package/dist/src/ui/tui/tui-editor-session.js +3 -0
- package/dist/src/ui/tui/tui-editors.js +4 -1
- package/dist/src/ui/tui/tui-frame.js +7 -3
- package/dist/src/ui/tui/tui-history.js +12 -10
- package/dist/src/ui/tui/tui-keys.js +6 -1
- package/dist/src/ui/tui/tui-pane-activity.js +62 -50
- package/dist/src/ui/tui/tui-pane-backlog.js +4 -4
- package/dist/src/ui/tui/tui-pane-ctx.js +1 -1
- package/dist/src/ui/tui/tui-pane-health.js +45 -26
- package/dist/src/ui/tui/tui-pane-history.js +296 -264
- package/dist/src/ui/tui/tui-pane-report.js +74 -57
- package/dist/src/ui/tui/tui-pane-session.js +6 -2
- package/dist/src/ui/tui/tui-pane-transcript.js +158 -131
- package/dist/src/ui/tui/tui-pane.js +201 -174
- package/dist/src/ui/tui/tui-panes.js +211 -148
- package/dist/src/ui/tui/tui.js +4 -4
- package/dist/src/verdict/fix-claim.js +18 -6
- package/dist/src/verdict/refusal.js +32 -7
- package/package.json +1 -1
- package/dist/src/doctor/image-probe.js +0 -257
- /package/dist/src/gui/{http-body.js → gui-http-body.js} +0 -0
- /package/dist/src/merge/{backlog-conflicts.js → merge-backlog-conflicts.js} +0 -0
|
@@ -3,6 +3,7 @@ import { isTeamPaused, pausedRoles, pauseTeam, pauseRole, resumeTeam, resumeRole
|
|
|
3
3
|
import { durationLabel } from "../../cli/cli-args.js";
|
|
4
4
|
import { teamPausePhrase, teamResumePhrase } from "../../text/phrases.js";
|
|
5
5
|
import { parsePauseInput, parseRolePauseInput, parseRoleWakeInput, parseStopInInput, } from "./tui-input.js";
|
|
6
|
+
import { viewedRole } from "./tui-editor-ctx.js";
|
|
6
7
|
/** The pause/stop/wake editor on the shared prompt line: the whole-team Ctrl+F pause and Ctrl+Q
|
|
7
8
|
* stop editors, the per-role Ctrl+P pause / Ctrl+A abort / Ctrl+W wake controls, and the
|
|
8
9
|
* parse/dispatch leaves those write. It owns its mode flags (pauseEditMode/`pauseEditRole`/
|
|
@@ -42,213 +43,239 @@ export function createPauseEditor(session) {
|
|
|
42
43
|
session.cursor = 0;
|
|
43
44
|
session.flashMessage(hint);
|
|
44
45
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (pauseEditMode) {
|
|
58
|
-
exitPauseEditMode();
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
if (isTeamPaused(session.root)) {
|
|
63
|
-
session.flashMessage(resumeTeam(session.root) ? teamResumePhrase() : "team was not paused");
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
// An unpaused team opens the one-line editor: "[duration] [reason]", empty pauses
|
|
67
|
-
// until resumed. A paused team resumes at once.
|
|
68
|
-
openPauseEditor(null, false, false, 'pause the team: [duration] [reason], e.g. "2h deploy freeze" (empty pauses until resumed) — Enter to pause, Esc to cancel');
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
session.flashError(err);
|
|
73
|
-
}
|
|
46
|
+
// Ctrl+F toggles the whole-team pause (mnemonic: **F**leet) through the same
|
|
47
|
+
// pauseTeam/resumeTeam marker writers `tumwater pause`/`resume` and the dashboard's
|
|
48
|
+
// /api/pause call use, so the surfaces cannot drift on marker format or idempotence.
|
|
49
|
+
// The shared teamPausePhrase/teamResumePhrase base lines keep the flash wording the
|
|
50
|
+
// event feed and failure digest already read; a no-op flashes the same
|
|
51
|
+
// already-paused/was-not-paused contract the CLI prints. Guarded out of the budget and
|
|
52
|
+
// role-prompt editors, whose prompt line the team toggle must not disturb — the same
|
|
53
|
+
// inertness the per-role keys honor below. The write can fail (a lock timeout, a torn
|
|
54
|
+
// fs), so flash the reason instead of letting the throw kill the TUI.
|
|
55
|
+
const teamPauseToggle = (_ctx) => {
|
|
56
|
+
if (pauseEditMode) {
|
|
57
|
+
exitPauseEditMode();
|
|
74
58
|
return true;
|
|
75
59
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// the same requestScheduledStop/cancelScheduledStopMessage cores `tumwater stop --in` /
|
|
80
|
-
// `--cancel` and the dashboard use. A pending stop cancels at once; otherwise it opens
|
|
81
|
-
// the duration editor. A second press closes any open pause/wake/stop editor unwritten.
|
|
82
|
-
if (pauseEditMode) {
|
|
83
|
-
exitPauseEditMode();
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
try {
|
|
87
|
-
if (scheduledStopAt(session.root) !== undefined) {
|
|
88
|
-
session.flashMessage(cancelScheduledStopMessage(session.root));
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
// The same one-line entry state as the Ctrl+F and per-role editors, scoped to the
|
|
92
|
-
// stop intent (no role pinned, stop mode on): nothing is written until Enter.
|
|
93
|
-
openPauseEditor(null, false, true, 'stop the team later: a duration, e.g. "2h" — current runs finish, then the team stops — Enter to schedule, Esc to cancel');
|
|
94
|
-
}
|
|
60
|
+
try {
|
|
61
|
+
if (isTeamPaused(session.root)) {
|
|
62
|
+
session.flashMessage(resumeTeam(session.root) ? teamResumePhrase() : "team was not paused");
|
|
95
63
|
}
|
|
96
|
-
|
|
97
|
-
|
|
64
|
+
else {
|
|
65
|
+
// An unpaused team opens the one-line editor: "[duration] [reason]", empty pauses
|
|
66
|
+
// until resumed. A paused team resumes at once.
|
|
67
|
+
openPauseEditor(null, false, false, 'pause the team: [duration] [reason], e.g. "2h deploy freeze" (empty pauses until resumed) — Enter to pause, Esc to cancel');
|
|
98
68
|
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
session.flashError(err);
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
};
|
|
75
|
+
// Ctrl+Q (mnemonic: **q**uit later) schedules or cancels a graceful team stop through
|
|
76
|
+
// the same requestScheduledStop/cancelScheduledStopMessage cores `tumwater stop --in` /
|
|
77
|
+
// `--cancel` and the dashboard use. A pending stop cancels at once; otherwise it opens
|
|
78
|
+
// the duration editor. A second press closes any open pause/wake/stop editor unwritten.
|
|
79
|
+
const stopLaterToggle = (_ctx) => {
|
|
80
|
+
if (pauseEditMode) {
|
|
81
|
+
exitPauseEditMode();
|
|
99
82
|
return true;
|
|
100
83
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// of `tumwater restart` and the dashboard update alert's restart button, all three
|
|
105
|
-
// through the same requestRestart marker writer. A refusal carries the CLI's wording
|
|
106
|
-
// (a red main, failed compile, swap error, or boot refusal still blocks; a fresh build
|
|
107
|
-
// refuses as "current with main"), so the flash matches what a terminal press would
|
|
108
|
-
// print. Inert on every other view (the transcript's Ctrl+R still opens the per-role
|
|
109
|
-
// prompt editor, Backlog's still releases an entry, Pending/Health's still refresh) and
|
|
110
|
-
// out of pause-edit mode, whose prompt line the restart must not disturb. The write can
|
|
111
|
-
// fail like any marker write, so flash the reason instead of letting the throw escape.
|
|
112
|
-
try {
|
|
113
|
-
const result = requestRestart(session.root);
|
|
114
|
-
session.flashMessage(result.ok ? result.message : result.error);
|
|
84
|
+
try {
|
|
85
|
+
if (scheduledStopAt(session.root) !== undefined) {
|
|
86
|
+
session.flashMessage(cancelScheduledStopMessage(session.root));
|
|
115
87
|
}
|
|
116
|
-
|
|
117
|
-
|
|
88
|
+
else {
|
|
89
|
+
// The same one-line entry state as the Ctrl+F and per-role editors, scoped to the
|
|
90
|
+
// stop intent (no role pinned, stop mode on): nothing is written until Enter.
|
|
91
|
+
openPauseEditor(null, false, true, 'stop the team later: a duration, e.g. "2h" — current runs finish, then the team stops — Enter to schedule, Esc to cancel');
|
|
118
92
|
}
|
|
119
|
-
return true;
|
|
120
93
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// editor (Ctrl+R opens the role-prompt editor for it — the prompt editor's arms handle
|
|
124
|
-
// that key). They call the
|
|
125
|
-
// same marker-writing/submit cores the CLI's --role flags do, so the surfaces cannot
|
|
126
|
-
// drift on marker format, idempotence, or wording. Guarded to the transcript views and
|
|
127
|
-
// out of budget-edit mode; everywhere else the keys fall through to applyKey. Every
|
|
128
|
-
// branch is a disk write that can fail (a lock timeout, a torn fs), and an unguarded
|
|
129
|
-
// throw would escape this keypress handler and kill the TUI — flash the reason instead.
|
|
130
|
-
if (key.ctrl && (key.name === "p" || key.name === "w") && pauseEditRole !== null) {
|
|
131
|
-
// A second Ctrl+P or Ctrl+W closes the per-role pause/wake editor, mirroring Ctrl+F's
|
|
132
|
-
// second press.
|
|
133
|
-
exitPauseEditMode();
|
|
134
|
-
return true;
|
|
94
|
+
catch (err) {
|
|
95
|
+
session.flashError(err);
|
|
135
96
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
97
|
+
return true;
|
|
98
|
+
};
|
|
99
|
+
// Ctrl+R on the Activity view applies the pending self-redeploy now — the terminal twin
|
|
100
|
+
// of `tumwater restart` and the dashboard update alert's restart button, all three
|
|
101
|
+
// through the same requestRestart marker writer. A refusal carries the CLI's wording
|
|
102
|
+
// (a red main, failed compile, swap error, or boot refusal still blocks; a fresh build
|
|
103
|
+
// refuses as "current with main"), so the flash matches what a terminal press would
|
|
104
|
+
// print. Inert on every other view (the transcript's Ctrl+R still opens the per-role
|
|
105
|
+
// prompt editor, Backlog's still releases an entry, Pending/Health's still refresh) and
|
|
106
|
+
// out of pause-edit mode, whose prompt line the restart must not disturb. The write can
|
|
107
|
+
// fail like any marker write, so flash the reason instead of letting the throw escape.
|
|
108
|
+
const restartNow = (_ctx) => {
|
|
109
|
+
try {
|
|
110
|
+
const result = requestRestart(session.root);
|
|
111
|
+
session.flashMessage(result.ok ? result.message : result.error);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
session.flashError(err);
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
};
|
|
118
|
+
// A second Ctrl+P or Ctrl+W closes the per-role pause/wake editor, mirroring Ctrl+F's
|
|
119
|
+
// second press.
|
|
120
|
+
const closeRolePauseEdit = () => {
|
|
121
|
+
exitPauseEditMode();
|
|
122
|
+
return true;
|
|
123
|
+
};
|
|
124
|
+
// Per-role controls on the transcript pane: Ctrl+P toggles the viewed role's pause,
|
|
125
|
+
// Ctrl+A aborts its in-flight run, Ctrl+V zeroes its counters, Ctrl+W opens the wake
|
|
126
|
+
// editor (Ctrl+R opens the role-prompt editor for it — the prompt editor's arms handle
|
|
127
|
+
// that key). They call the
|
|
128
|
+
// same marker-writing/submit cores the CLI's --role flags do, so the surfaces cannot
|
|
129
|
+
// drift on marker format, idempotence, or wording. Guarded to the transcript views and
|
|
130
|
+
// out of budget-edit mode; everywhere else the keys fall through to applyKey. Every
|
|
131
|
+
// branch is a disk write that can fail (a lock timeout, a torn fs), and an unguarded
|
|
132
|
+
// throw would escape this keypress handler and kill the TUI — flash the reason instead.
|
|
133
|
+
const roleControlArm = (name, ctx) => {
|
|
134
|
+
const role = viewedRole(ctx); // defined: view is clamped inside the transcript range
|
|
135
|
+
try {
|
|
136
|
+
if (name === "p") {
|
|
137
|
+
// Toggle by the marker's current state, read fresh: pauseRole/resumeRole's false
|
|
138
|
+
// return means another window raced us to the same state, and the wording
|
|
139
|
+
// helpers render that honestly — the changed-state contract the CLI prints.
|
|
140
|
+
if (pausedRoles(session.root).includes(role)) {
|
|
141
|
+
session.flashMessage(roleResumeMessage(session.root, role, resumeRole(session.root, role)));
|
|
164
142
|
}
|
|
165
143
|
else if (session.held.rolePromptFor || session.held.search) {
|
|
166
144
|
session.flashMessage(session.held.rolePromptFor ? session.busyFlash("role prompt") : session.busyFlash("search"));
|
|
167
145
|
}
|
|
168
146
|
else {
|
|
169
|
-
//
|
|
170
|
-
|
|
147
|
+
// An unpaused role opens the one-line duration editor; nothing is written until
|
|
148
|
+
// Enter. Empty pauses until resumed.
|
|
149
|
+
openPauseEditor(role, false, false, `pause ${role}: [duration], e.g. "2h" (empty pauses until resumed) — Enter to pause, Esc to cancel`);
|
|
171
150
|
}
|
|
172
151
|
}
|
|
173
|
-
|
|
174
|
-
session.
|
|
152
|
+
else if (name === "a") {
|
|
153
|
+
const result = requestAbort(session.root, role);
|
|
154
|
+
session.flashMessage(result.ok ? result.message : `error: ${result.error}`);
|
|
155
|
+
}
|
|
156
|
+
else if (name === "v") {
|
|
157
|
+
session.flashMessage(requestResetCounters(session.root, [role]));
|
|
175
158
|
}
|
|
159
|
+
else if (session.held.rolePromptFor || session.held.search) {
|
|
160
|
+
session.flashMessage(session.held.rolePromptFor ? session.busyFlash("role prompt") : session.busyFlash("search"));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Ctrl+W opens the one-line wake editor; nothing is written until Enter. Empty wakes now.
|
|
164
|
+
openPauseEditor(role, true, false, `wake ${role}: [duration], e.g. "2h", or "cancel" (empty wakes now) — Enter to apply, Esc to cancel`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
session.flashError(err);
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
};
|
|
172
|
+
// Esc cancels the pause editor without writing, restoring the previous prompt text.
|
|
173
|
+
const cancelPauseEdit = () => {
|
|
174
|
+
exitPauseEditMode();
|
|
175
|
+
return true;
|
|
176
|
+
};
|
|
177
|
+
// Enter in pause-edit mode parses "[duration] [reason]" and writes the same marker
|
|
178
|
+
// `tumwater pause --for/--reason` does. An invalid entry flashes and STAYS in the editor.
|
|
179
|
+
// It reads the current mode/draft and dispatches to the single named writer for the
|
|
180
|
+
// intent it resolves: a scheduled stop, a per-role wake, a per-role pause, or the team
|
|
181
|
+
// pause.
|
|
182
|
+
const commitPauseEntry = () => {
|
|
183
|
+
const target = pauseEditRole;
|
|
184
|
+
const stopParsed = pauseEditStop ? parseStopInInput(session.input) : null;
|
|
185
|
+
const wakeParsed = pauseEditWake && target !== null ? parseRoleWakeInput(session.input) : null;
|
|
186
|
+
const parsed = target !== null ? parseRolePauseInput(session.input) : parsePauseInput(session.input);
|
|
187
|
+
if (stopParsed) {
|
|
188
|
+
applyStopEntry(stopParsed);
|
|
176
189
|
return true;
|
|
177
190
|
}
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
exitPauseEditMode();
|
|
191
|
+
if (wakeParsed) {
|
|
192
|
+
applyWakeEntry(wakeParsed, target);
|
|
181
193
|
return true;
|
|
182
194
|
}
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
// `tumwater pause --for/--reason` does. An invalid entry flashes and STAYS in the editor.
|
|
186
|
-
const target = pauseEditRole;
|
|
187
|
-
const stopParsed = pauseEditStop ? parseStopInInput(session.input) : null;
|
|
188
|
-
const wakeParsed = pauseEditWake && target !== null ? parseRoleWakeInput(session.input) : null;
|
|
189
|
-
const parsed = target !== null ? parseRolePauseInput(session.input) : parsePauseInput(session.input);
|
|
190
|
-
if (stopParsed) {
|
|
191
|
-
if (!stopParsed.ok) {
|
|
192
|
-
session.flashMessage(stopParsed.error);
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
try {
|
|
196
|
-
const result = requestScheduledStop(session.root, stopParsed.inMs);
|
|
197
|
-
exitPauseEditMode();
|
|
198
|
-
session.flashMessage(result.ok ? result.message : `error: ${result.error}`);
|
|
199
|
-
}
|
|
200
|
-
catch (err) {
|
|
201
|
-
session.flashError(err);
|
|
202
|
-
}
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
if (wakeParsed) {
|
|
206
|
-
if (!wakeParsed.ok) {
|
|
207
|
-
session.flashMessage(wakeParsed.error);
|
|
208
|
-
return true;
|
|
209
|
-
}
|
|
210
|
-
try {
|
|
211
|
-
const message = wakeParsed.cancel ? cancelWakes(session.root, [target]) : requestWake(session.root, [target], wakeParsed.inMs);
|
|
212
|
-
exitPauseEditMode();
|
|
213
|
-
session.flashMessage(message);
|
|
214
|
-
}
|
|
215
|
-
catch (err) {
|
|
216
|
-
session.flashError(err);
|
|
217
|
-
}
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
if (!parsed.ok) {
|
|
221
|
-
session.flashMessage(parsed.error);
|
|
222
|
-
return true;
|
|
223
|
-
}
|
|
224
|
-
if (target !== null) {
|
|
225
|
-
try {
|
|
226
|
-
const at = session.now();
|
|
227
|
-
const until = parsed.forMs === undefined ? undefined : at + parsed.forMs;
|
|
228
|
-
const changed = pauseRole(session.root, target, until);
|
|
229
|
-
exitPauseEditMode();
|
|
230
|
-
session.flashMessage(rolePauseMessage(session.root, target, changed, until === undefined ? undefined : { ms: parsed.forMs, untilMs: until }, at));
|
|
231
|
-
}
|
|
232
|
-
catch (err) {
|
|
233
|
-
session.flashError(err);
|
|
234
|
-
}
|
|
235
|
-
return true;
|
|
236
|
-
}
|
|
237
|
-
const team = parsed;
|
|
238
|
-
try {
|
|
239
|
-
const until = team.forMs === undefined ? undefined : session.now() + team.forMs;
|
|
240
|
-
const changed = pauseTeam(session.root, until, team.reason);
|
|
241
|
-
exitPauseEditMode();
|
|
242
|
-
const forSuffix = team.forMs === undefined ? "" : ` for ${durationLabel(team.forMs)}`;
|
|
243
|
-
session.flashMessage(changed || until !== undefined
|
|
244
|
-
? `${teamPausePhrase()}${forSuffix}${changed && team.reason ? `: ${team.reason}` : ""}`
|
|
245
|
-
: "team is already paused");
|
|
246
|
-
}
|
|
247
|
-
catch (err) {
|
|
248
|
-
session.flashError(err);
|
|
249
|
-
}
|
|
195
|
+
if (!parsed.ok) {
|
|
196
|
+
session.flashMessage(parsed.error);
|
|
250
197
|
return true;
|
|
251
198
|
}
|
|
199
|
+
if (target !== null) {
|
|
200
|
+
applyRolePauseEntry(parsed, target);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
applyTeamPauseEntry(parsed);
|
|
204
|
+
return true;
|
|
205
|
+
};
|
|
206
|
+
const applyStopEntry = (stopParsed) => {
|
|
207
|
+
if (!stopParsed.ok) {
|
|
208
|
+
session.flashMessage(stopParsed.error);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
const result = requestScheduledStop(session.root, stopParsed.inMs);
|
|
213
|
+
exitPauseEditMode();
|
|
214
|
+
session.flashMessage(result.ok ? result.message : `error: ${result.error}`);
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
session.flashError(err);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const applyWakeEntry = (wakeParsed, target) => {
|
|
221
|
+
if (!wakeParsed.ok) {
|
|
222
|
+
session.flashMessage(wakeParsed.error);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const message = wakeParsed.cancel ? cancelWakes(session.root, [target]) : requestWake(session.root, [target], wakeParsed.inMs);
|
|
227
|
+
exitPauseEditMode();
|
|
228
|
+
session.flashMessage(message);
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
session.flashError(err);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const applyRolePauseEntry = (parsed, target) => {
|
|
235
|
+
try {
|
|
236
|
+
const at = session.now();
|
|
237
|
+
const until = parsed.forMs === undefined ? undefined : at + parsed.forMs;
|
|
238
|
+
const changed = pauseRole(session.root, target, until);
|
|
239
|
+
exitPauseEditMode();
|
|
240
|
+
session.flashMessage(rolePauseMessage(session.root, target, changed, until === undefined ? undefined : { ms: parsed.forMs, untilMs: until }, at));
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
session.flashError(err);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const applyTeamPauseEntry = (parsed) => {
|
|
247
|
+
try {
|
|
248
|
+
const until = parsed.forMs === undefined ? undefined : session.now() + parsed.forMs;
|
|
249
|
+
const changed = pauseTeam(session.root, until, parsed.reason);
|
|
250
|
+
exitPauseEditMode();
|
|
251
|
+
const forSuffix = parsed.forMs === undefined ? "" : ` for ${durationLabel(parsed.forMs)}`;
|
|
252
|
+
session.flashMessage(changed || until !== undefined
|
|
253
|
+
? `${teamPausePhrase()}${forSuffix}${changed && parsed.reason ? `: ${parsed.reason}` : ""}`
|
|
254
|
+
: "team is already paused");
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
session.flashError(err);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const handleKey = (_str, key, ctx) => {
|
|
261
|
+
// Ordered dispatch: a guard miss falls through to the next arm, then to applyKey.
|
|
262
|
+
if (key.ctrl && key.name === "f" && !session.anyEditorHeld("pause"))
|
|
263
|
+
return teamPauseToggle(ctx);
|
|
264
|
+
if (key.ctrl && key.name === "q" && !session.anyEditorHeld("pause"))
|
|
265
|
+
return stopLaterToggle(ctx);
|
|
266
|
+
if (key.ctrl && key.name === "r" && ctx.view === 0 && !pauseEditMode && !session.anyEditorHeld("pause"))
|
|
267
|
+
return restartNow(ctx);
|
|
268
|
+
if (key.ctrl && (key.name === "p" || key.name === "w") && pauseEditRole !== null)
|
|
269
|
+
return closeRolePauseEdit();
|
|
270
|
+
if (!session.anyEditorHeld("rolePromptFor", "search") &&
|
|
271
|
+
ctx.roleIds.length > 0 &&
|
|
272
|
+
ctx.view >= 1 && ctx.view <= ctx.roleIds.length &&
|
|
273
|
+
key.ctrl && (key.name === "p" || key.name === "a" || key.name === "w" || key.name === "v"))
|
|
274
|
+
return roleControlArm(key.name, ctx);
|
|
275
|
+
if (key.name === "escape" && pauseEditMode)
|
|
276
|
+
return cancelPauseEdit();
|
|
277
|
+
if (key.name === "return" && pauseEditMode)
|
|
278
|
+
return commitPauseEntry();
|
|
252
279
|
return false;
|
|
253
280
|
};
|
|
254
281
|
return { handleKey, exit: exitPauseEditMode };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { submitRolePromptAndWake } from "../../operator/operator-intent.js";
|
|
2
2
|
import { pushPromptHistory } from "./tui-prompt-history.js";
|
|
3
3
|
import { parseRolePromptInput } from "./tui-input.js";
|
|
4
|
+
import { viewedRole } from "./tui-editor-ctx.js";
|
|
4
5
|
/** The per-role prompt Ctrl+R editor on the shared prompt line. It owns its mode flag (the
|
|
5
6
|
* viewed role's role id), its saved-draft pair, its exit helper, and the handleKey arms for its
|
|
6
7
|
* key: the per-role toggle (guarded out of the other editors' prompt line) and its Esc/Enter
|
|
@@ -19,17 +20,16 @@ export function createPromptEditor(session) {
|
|
|
19
20
|
session.held.rolePromptFor = null;
|
|
20
21
|
restoreDraft();
|
|
21
22
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
// Ctrl+R toggles role-prompt mode for the viewed role (mnemonic: p**R**ompt — Ctrl+P is
|
|
24
|
+
// taken by pause): entering saves the director draft in this mode's own pair and blanks
|
|
25
|
+
// the line; entering again (or Esc) restores it. Mutually exclusive with budget mode by
|
|
26
|
+
// the outer guard and the mirrored refusal in the Ctrl+B branch. Rides the same per-role
|
|
27
|
+
// guard as the Ctrl+P/A/W pause controls so an editor's prompt line is never disturbed.
|
|
28
|
+
const toggleRolePromptEdit = (ctx) => {
|
|
28
29
|
if (!session.anyEditorHeld("rolePromptFor") &&
|
|
29
30
|
ctx.roleIds.length > 0 &&
|
|
30
|
-
ctx.view >= 1 && ctx.view <= ctx.roleIds.length
|
|
31
|
-
|
|
32
|
-
const role = ctx.roleIds[ctx.view - 1]; // defined: view is clamped inside the transcript range
|
|
31
|
+
ctx.view >= 1 && ctx.view <= ctx.roleIds.length) {
|
|
32
|
+
const role = viewedRole(ctx); // defined: view is clamped inside the transcript range
|
|
33
33
|
try {
|
|
34
34
|
if (rolePromptFor) {
|
|
35
35
|
exitRolePromptMode();
|
|
@@ -53,37 +53,48 @@ export function createPromptEditor(session) {
|
|
|
53
53
|
}
|
|
54
54
|
return true;
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
return false;
|
|
57
|
+
};
|
|
58
|
+
// Esc cancels role-prompt mode the same way, restoring the previous prompt text.
|
|
59
|
+
const cancelRolePromptEdit = () => {
|
|
60
|
+
exitRolePromptMode();
|
|
61
|
+
return true;
|
|
62
|
+
};
|
|
63
|
+
// Enter in role-prompt mode submits for the viewed role through the same path
|
|
64
|
+
// `tumwater prompt --role` uses: the shared submitRolePromptAndWake enqueues into
|
|
65
|
+
// that role's own queue (length-capped by the shared rule), logs under the role,
|
|
66
|
+
// and wakes it so a live team's role comes in within one poll. An invalid
|
|
67
|
+
// (whitespace-only) line flashes and STAYS in edit mode; a failed queue write
|
|
68
|
+
// flashes the reason and keeps the text, the same contract the director path
|
|
69
|
+
// honors; success restores the saved draft.
|
|
70
|
+
const submitRolePromptEdit = () => {
|
|
71
|
+
const role = rolePromptFor; // dispatch guarantees it is set; kept for TS narrowing
|
|
72
|
+
if (role === null)
|
|
59
73
|
return true;
|
|
74
|
+
const parsed = parseRolePromptInput(session.input);
|
|
75
|
+
if (!parsed.ok) {
|
|
76
|
+
session.flashMessage(parsed.error);
|
|
60
77
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// flashes the reason and keeps the text, the same contract the director path
|
|
68
|
-
// honors; success restores the saved draft.
|
|
69
|
-
const parsed = parseRolePromptInput(session.input);
|
|
70
|
-
if (!parsed.ok) {
|
|
71
|
-
session.flashMessage(parsed.error);
|
|
78
|
+
else {
|
|
79
|
+
try {
|
|
80
|
+
submitRolePromptAndWake(session.root, role, parsed.value, undefined);
|
|
81
|
+
session.promptHistory = pushPromptHistory(session.promptHistory, parsed.value);
|
|
82
|
+
exitRolePromptMode();
|
|
83
|
+
session.flashMessage(`added to ${role}'s inbox`);
|
|
72
84
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
submitRolePromptAndWake(session.root, role, parsed.value, undefined);
|
|
77
|
-
session.promptHistory = pushPromptHistory(session.promptHistory, parsed.value);
|
|
78
|
-
exitRolePromptMode();
|
|
79
|
-
session.flashMessage(`added to ${role}'s inbox`);
|
|
80
|
-
}
|
|
81
|
-
catch (err) {
|
|
82
|
-
session.flashError(err);
|
|
83
|
-
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
session.flashError(err);
|
|
84
87
|
}
|
|
85
|
-
return true;
|
|
86
88
|
}
|
|
89
|
+
return true;
|
|
90
|
+
};
|
|
91
|
+
const handleKey = (_str, key, ctx) => {
|
|
92
|
+
if (key.ctrl && key.name === "r")
|
|
93
|
+
return toggleRolePromptEdit(ctx);
|
|
94
|
+
if (key.name === "escape" && rolePromptFor)
|
|
95
|
+
return cancelRolePromptEdit();
|
|
96
|
+
if (key.name === "return" && rolePromptFor)
|
|
97
|
+
return submitRolePromptEdit();
|
|
87
98
|
return false;
|
|
88
99
|
};
|
|
89
100
|
return { handleKey, exit: exitRolePromptMode };
|