parallel-codex-tui 0.1.3 → 0.1.5
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/.parallel-codex/config.example.toml +136 -3
- package/README.md +299 -21
- package/dist/bootstrap.js +37 -17
- package/dist/cli-args.js +34 -3
- package/dist/cli-help.js +20 -0
- package/dist/cli-startup-preflight.js +18 -0
- package/dist/cli-startup-recovery.js +82 -0
- package/dist/cli-workspace-picker.js +330 -0
- package/dist/cli-workspace-transition.js +33 -0
- package/dist/cli-workspace.js +7 -71
- package/dist/cli.js +234 -24
- package/dist/core/collaboration-timeline.js +268 -0
- package/dist/core/config-errors.js +14 -0
- package/dist/core/config.js +297 -109
- package/dist/core/file-store.js +119 -6
- package/dist/core/lease-finalization.js +22 -0
- package/dist/core/paths.js +7 -0
- package/dist/core/process-identity.js +48 -0
- package/dist/core/process-mutation-turn.js +128 -0
- package/dist/core/process-ownership.js +276 -0
- package/dist/core/process-tree.js +90 -0
- package/dist/core/router-audit.js +155 -0
- package/dist/core/router-redaction.js +31 -0
- package/dist/core/router.js +462 -35
- package/dist/core/session-index.js +412 -88
- package/dist/core/session-manager.js +1110 -40
- package/dist/core/task-session-details.js +175 -0
- package/dist/core/task-state-machine.js +18 -0
- package/dist/core/workspace-commit-recovery.js +118 -0
- package/dist/core/workspace.js +19 -11
- package/dist/doctor.js +373 -34
- package/dist/domain/schemas.js +142 -7
- package/dist/orchestrator/collaboration-channel.js +289 -6
- package/dist/orchestrator/feature-plan.js +70 -0
- package/dist/orchestrator/final-acceptance.js +86 -0
- package/dist/orchestrator/judge-artifacts.js +236 -0
- package/dist/orchestrator/orchestrator.js +2086 -203
- package/dist/orchestrator/prompts.js +168 -5
- package/dist/orchestrator/supervisor-summary.js +56 -2
- package/dist/orchestrator/workspace-sandbox.js +927 -0
- package/dist/tui/App.js +3187 -161
- package/dist/tui/AppShell.js +196 -25
- package/dist/tui/CollaborationTimelineView.js +327 -0
- package/dist/tui/FeatureBoardView.js +232 -0
- package/dist/tui/InputBar.js +581 -57
- package/dist/tui/RouterDiagnosticsView.js +469 -0
- package/dist/tui/StatusBar.js +610 -57
- package/dist/tui/StatusDetailView.js +164 -0
- package/dist/tui/TaskSessionDetailView.js +222 -0
- package/dist/tui/TaskSessionsView.js +210 -0
- package/dist/tui/TerminalOutput.js +53 -9
- package/dist/tui/WorkerOutputView.js +1404 -161
- package/dist/tui/WorkerOverviewView.js +269 -0
- package/dist/tui/chat-history.js +25 -0
- package/dist/tui/chat-input.js +67 -19
- package/dist/tui/chat-paste.js +76 -0
- package/dist/tui/display-width.js +41 -3
- package/dist/tui/incremental-text-file.js +101 -0
- package/dist/tui/keyboard.js +49 -0
- package/dist/tui/markdown-text.js +14 -0
- package/dist/tui/raw-input-decoder.js +3 -0
- package/dist/tui/scrolling.js +2 -1
- package/dist/tui/status-line.js +360 -11
- package/dist/tui/task-memory.js +13 -1
- package/dist/tui/task-result.js +105 -0
- package/dist/tui/terminal-screen.js +13 -1
- package/dist/tui/theme-contrast.js +144 -0
- package/dist/tui/theme-preview.js +109 -0
- package/dist/tui/theme.js +158 -0
- package/dist/version.js +1 -1
- package/dist/workers/capabilities.js +213 -0
- package/dist/workers/live-probe.js +177 -0
- package/dist/workers/mock-adapter.js +73 -8
- package/dist/workers/native-attach.js +106 -16
- package/dist/workers/process-adapter.js +572 -77
- package/dist/workers/provider.js +26 -0
- package/dist/workers/registry.js +12 -20
- package/package.json +11 -2
package/dist/tui/InputBar.js
CHANGED
|
@@ -1,39 +1,122 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import { compactTailByDisplayWidth, displayWidth } from "./display-width.js";
|
|
4
|
-
|
|
5
|
-
export function InputBar({ mode, busy = false, hasWorkers = false, nativeClosed = false,
|
|
3
|
+
import { compactEndByDisplayWidth, compactTailByDisplayWidth, displayWidth } from "./display-width.js";
|
|
4
|
+
import { TUI_THEME } from "./theme.js";
|
|
5
|
+
export function InputBar({ mode, ready = true, busy = false, routeFallback = false, collaborationDetail = false, collaborationUnresolved = false, collaborationBack = "workers", featureCanCancel = false, featureCanPause = false, featureCanReassign = false, featureCancelConfirm = false, featurePauseConfirm = false, featureAssignment = false, taskSessionAction = null, taskSessionsIncludeArchived = false, taskSessionDetail = false, taskSessionDetailHasNative = false, taskSessionDetailCanFork = false, canRetry = false, hasWorkers = false, hasActiveTask = false, hasTaskResult = false, taskResultExpanded = false, chatScrollOffset = 0, chatMaxScrollOffset = 0, nativeClosed = false, searchMatchIndex = 0, searchMatchCount = 0, value, cursor, terminalWidth: providedTerminalWidth, onChange, onSubmit }) {
|
|
6
|
+
const terminalWidth = providedTerminalWidth ?? process.stdout.columns ?? 120;
|
|
7
|
+
const fillRail = providedTerminalWidth !== undefined || typeof process.stdout.columns === "number";
|
|
8
|
+
if (mode === "worker-search") {
|
|
9
|
+
const suffix = workerSearchInputSuffix(terminalWidth, searchMatchIndex, searchMatchCount);
|
|
10
|
+
const prefix = terminalWidth < 4 ? "/" : "/ ";
|
|
11
|
+
const textBudget = Math.max(1, terminalWidth - (terminalWidth > 1 ? 2 : 0));
|
|
12
|
+
const valueWidth = Math.max(1, textBudget - displayWidth(prefix) - 1 - displayWidth(suffix));
|
|
13
|
+
const display = chatInputDisplayParts(value, cursor ?? Array.from(value).length, valueWidth + 6);
|
|
14
|
+
const textWidth = displayWidth(`${prefix}${display.before}|${display.after}${suffix}`);
|
|
15
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: textWidth, fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prefix }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.before }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.after }), suffix ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: suffix }) : null] }));
|
|
16
|
+
}
|
|
17
|
+
if (mode === "status") {
|
|
18
|
+
const hints = statusDetailInputHints(terminalWidth);
|
|
19
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
20
|
+
}
|
|
21
|
+
if (mode === "sessions") {
|
|
22
|
+
if (taskSessionAction?.type === "rename") {
|
|
23
|
+
const prefix = terminalWidth < 12 ? "> " : "rename > ";
|
|
24
|
+
const valueWidth = Math.max(1, terminalWidth - displayWidth(prefix) - 3);
|
|
25
|
+
const display = chatInputDisplayParts(taskSessionAction.value, taskSessionAction.cursor, valueWidth);
|
|
26
|
+
const textWidth = displayWidth(`${prefix}${display.before}|${display.after}`);
|
|
27
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: textWidth, fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prefix }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.before }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.after })] }));
|
|
28
|
+
}
|
|
29
|
+
if (taskSessionAction?.type === "delete") {
|
|
30
|
+
const hints = taskSessionDeleteInputHints(terminalWidth, taskSessionAction.title);
|
|
31
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.danger, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
32
|
+
}
|
|
33
|
+
if (taskSessionDetail) {
|
|
34
|
+
const hints = taskSessionDetailInputHints(terminalWidth, taskSessionDetailHasNative, taskSessionDetailCanFork);
|
|
35
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
36
|
+
}
|
|
37
|
+
const hints = taskSessionsInputHints(terminalWidth, taskSessionsIncludeArchived);
|
|
38
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
39
|
+
}
|
|
40
|
+
if (mode === "collaboration") {
|
|
41
|
+
const hints = collaborationDetail
|
|
42
|
+
? collaborationDetailInputHints(terminalWidth)
|
|
43
|
+
: collaborationTimelineInputHints(terminalWidth, collaborationUnresolved, collaborationBack);
|
|
44
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
45
|
+
}
|
|
46
|
+
if (mode === "features") {
|
|
47
|
+
const hints = featureBoardInputHints(terminalWidth, {
|
|
48
|
+
canCancel: featureCanCancel,
|
|
49
|
+
canPause: featureCanPause,
|
|
50
|
+
canReassign: featureCanReassign,
|
|
51
|
+
confirmCancel: featureCancelConfirm,
|
|
52
|
+
confirmPause: featurePauseConfirm,
|
|
53
|
+
assignment: featureAssignment,
|
|
54
|
+
canRetry
|
|
55
|
+
});
|
|
56
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
57
|
+
}
|
|
58
|
+
if (mode === "workers") {
|
|
59
|
+
const hints = workerOverviewInputHints(terminalWidth);
|
|
60
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
61
|
+
}
|
|
6
62
|
if (mode === "worker") {
|
|
7
63
|
const hints = workerInputHints(terminalWidth);
|
|
8
|
-
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), children: [_jsx(Text, { backgroundColor:
|
|
64
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
9
65
|
}
|
|
10
66
|
if (mode === "native") {
|
|
11
67
|
const hints = nativeInputHints(terminalWidth, nativeClosed);
|
|
12
|
-
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), children: [_jsx(Text, { backgroundColor:
|
|
68
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
69
|
+
}
|
|
70
|
+
if (mode === "router") {
|
|
71
|
+
const hints = routerInputHints(terminalWidth);
|
|
72
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
|
|
73
|
+
}
|
|
74
|
+
if (!ready) {
|
|
75
|
+
const starting = chatStartingDisplayValue(terminalWidth);
|
|
76
|
+
return (_jsx(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(starting), fill: fillRail, children: _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: starting }) }));
|
|
77
|
+
}
|
|
78
|
+
if (routeFallback) {
|
|
79
|
+
const hints = routeFallbackInputHints(terminalWidth);
|
|
80
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.warning, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: hints.detail }) : null] }));
|
|
13
81
|
}
|
|
14
82
|
const busyText = chatBusyDisplayValue(terminalWidth);
|
|
15
83
|
const prompt = busy ? "run" : ">";
|
|
16
84
|
if (busy) {
|
|
17
|
-
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(busyText ? `${prompt} ${busyText}` : prompt), children: [_jsx(Text, { backgroundColor:
|
|
85
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(busyText ? `${prompt} ${busyText}` : prompt), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.warning, bold: true, children: prompt }), busyText ? (_jsxs(_Fragment, { children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, children: " " }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.warning, children: busyText })] })) : null] }));
|
|
18
86
|
}
|
|
19
87
|
if (value) {
|
|
20
|
-
const
|
|
21
|
-
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${prompt} ${
|
|
88
|
+
const display = chatInputDisplayParts(value, cursor ?? Array.from(value).length, terminalWidth);
|
|
89
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${prompt} ${display.before}|${display.after}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prompt }), _jsx(Text, { backgroundColor: TUI_THEME.rail, children: " " }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.before }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.after })] }));
|
|
22
90
|
}
|
|
23
91
|
const hasLeadingPromptSpace = terminalWidth >= 10;
|
|
24
|
-
const placeholder = chatPlaceholderDisplayText(terminalWidth, {
|
|
25
|
-
|
|
92
|
+
const placeholder = chatPlaceholderDisplayText(terminalWidth, {
|
|
93
|
+
hasWorkers,
|
|
94
|
+
hasActiveTask,
|
|
95
|
+
hasTaskResult,
|
|
96
|
+
taskResultExpanded,
|
|
97
|
+
canRetry,
|
|
98
|
+
scrollOffset: chatScrollOffset,
|
|
99
|
+
maxScrollOffset: chatMaxScrollOffset
|
|
100
|
+
}, { leadingSpace: hasLeadingPromptSpace });
|
|
101
|
+
return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${prompt}${hasLeadingPromptSpace ? " " : ""}|${placeholder}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prompt }), hasLeadingPromptSpace ? _jsx(Text, { backgroundColor: TUI_THEME.rail, children: " " }) : null, _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: canRetry ? TUI_THEME.warning : hasTaskResult ? TUI_THEME.accent : TUI_THEME.muted, children: placeholder })] }));
|
|
26
102
|
}
|
|
27
|
-
function InputRail({ terminalWidth, textWidth, children }) {
|
|
103
|
+
function InputRail({ fill, terminalWidth, textWidth, children }) {
|
|
104
|
+
const { leadingWidth, trailingWidth } = inputRailLayout(terminalWidth, textWidth, { fill });
|
|
105
|
+
return (_jsxs(Box, { children: [leadingWidth > 0 ? _jsx(Text, { backgroundColor: TUI_THEME.rail, children: " ".repeat(leadingWidth) }) : null, children, trailingWidth > 0 ? _jsx(Text, { backgroundColor: TUI_THEME.rail, children: " ".repeat(trailingWidth) }) : null] }));
|
|
106
|
+
}
|
|
107
|
+
export function inputRailLayout(terminalWidth, textWidth, options = {}) {
|
|
28
108
|
const leadingWidth = terminalWidth > 1 ? 1 : 0;
|
|
109
|
+
if (options.fill === false) {
|
|
110
|
+
return { leadingWidth, trailingWidth: 0 };
|
|
111
|
+
}
|
|
29
112
|
const renderWidth = typeof process.stdout.columns === "number"
|
|
30
113
|
? Math.max(1, Math.min(terminalWidth, process.stdout.columns))
|
|
31
|
-
:
|
|
32
|
-
const barWidth =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: Math.max(0, barWidth - leadingWidth - textWidth)
|
|
36
|
-
|
|
114
|
+
: Math.max(1, terminalWidth);
|
|
115
|
+
const barWidth = Math.max(1, renderWidth - 1);
|
|
116
|
+
return {
|
|
117
|
+
leadingWidth,
|
|
118
|
+
trailingWidth: Math.max(0, barWidth - leadingWidth - Math.max(0, textWidth))
|
|
119
|
+
};
|
|
37
120
|
}
|
|
38
121
|
export function chatPlaceholderDisplayText(terminalWidth, options = {}, display = {}) {
|
|
39
122
|
const placeholder = chatPlaceholderDisplayValue(terminalWidth, options);
|
|
@@ -44,37 +127,211 @@ export function chatPlaceholderDisplayText(terminalWidth, options = {}, display
|
|
|
44
127
|
}
|
|
45
128
|
export function chatInputDisplayValue(value, terminalWidth) {
|
|
46
129
|
const valueWidth = Math.max(1, terminalWidth - 6);
|
|
47
|
-
return compactTailByDisplayWidth(value, valueWidth);
|
|
130
|
+
return compactTailByDisplayWidth(chatInputVisibleValue(value), valueWidth);
|
|
131
|
+
}
|
|
132
|
+
export function chatInputDisplayParts(value, cursor, terminalWidth) {
|
|
133
|
+
const sourceChars = Array.from(value);
|
|
134
|
+
const chars = sourceChars.map(chatInputVisibleCharacter);
|
|
135
|
+
const clampedCursor = Math.min(sourceChars.length, Math.max(0, Math.trunc(cursor)));
|
|
136
|
+
const valueWidth = Math.max(1, terminalWidth - 6);
|
|
137
|
+
if (displayWidth(chars.join("")) <= valueWidth) {
|
|
138
|
+
return {
|
|
139
|
+
before: chars.slice(0, clampedCursor).join(""),
|
|
140
|
+
after: chars.slice(clampedCursor).join("")
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const beforeCursor = chars.slice(0, clampedCursor).join("");
|
|
144
|
+
const afterCursor = chars.slice(clampedCursor).join("");
|
|
145
|
+
if (valueWidth < 6) {
|
|
146
|
+
return clampedCursor > 0
|
|
147
|
+
? { before: compactTailByDisplayWidth(beforeCursor, valueWidth), after: "" }
|
|
148
|
+
: { before: "", after: compactEndByDisplayWidth(afterCursor, valueWidth) };
|
|
149
|
+
}
|
|
150
|
+
let start = clampedCursor;
|
|
151
|
+
let end = clampedCursor;
|
|
152
|
+
const renderedWidth = (nextStart, nextEnd) => displayWidth([
|
|
153
|
+
nextStart > 0 ? "..." : "",
|
|
154
|
+
chars.slice(nextStart, nextEnd).join(""),
|
|
155
|
+
nextEnd < chars.length ? "..." : ""
|
|
156
|
+
].join(""));
|
|
157
|
+
while (true) {
|
|
158
|
+
const canExpandLeft = start > 0 && renderedWidth(start - 1, end) <= valueWidth;
|
|
159
|
+
const canExpandRight = end < chars.length && renderedWidth(start, end + 1) <= valueWidth;
|
|
160
|
+
if (!canExpandLeft && !canExpandRight) {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
if (canExpandLeft && canExpandRight) {
|
|
164
|
+
const leftWidth = displayWidth(chars.slice(start, clampedCursor).join(""));
|
|
165
|
+
const rightWidth = displayWidth(chars.slice(clampedCursor, end).join(""));
|
|
166
|
+
if (leftWidth <= rightWidth) {
|
|
167
|
+
start -= 1;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
end += 1;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (canExpandLeft) {
|
|
174
|
+
start -= 1;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
end += 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
before: `${start > 0 ? "..." : ""}${chars.slice(start, clampedCursor).join("")}`,
|
|
182
|
+
after: `${chars.slice(clampedCursor, end).join("")}${end < chars.length ? "..." : ""}`
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function chatInputVisibleValue(value) {
|
|
186
|
+
return Array.from(value).map(chatInputVisibleCharacter).join("");
|
|
187
|
+
}
|
|
188
|
+
function chatInputVisibleCharacter(char) {
|
|
189
|
+
if (char === "\n" || char === "\r") {
|
|
190
|
+
return "↵";
|
|
191
|
+
}
|
|
192
|
+
if (char === "\t") {
|
|
193
|
+
return "⇥";
|
|
194
|
+
}
|
|
195
|
+
return char;
|
|
48
196
|
}
|
|
49
197
|
export function chatPlaceholderDisplayValue(terminalWidth, options = {}) {
|
|
50
|
-
if (options.
|
|
51
|
-
return
|
|
198
|
+
if (options.canRetry) {
|
|
199
|
+
return selectChatPlaceholder(terminalWidth, options.hasActiveTask
|
|
200
|
+
? ["message · ^R retry · ^N new", "^R retry · ^N", "^R retry", "retry"]
|
|
201
|
+
: ["message · ^R retry", "^R retry", "retry"]);
|
|
52
202
|
}
|
|
53
|
-
|
|
54
|
-
|
|
203
|
+
const maxScrollOffset = Math.max(0, options.maxScrollOffset ?? 0);
|
|
204
|
+
const scrollOffset = Math.min(Math.max(0, options.scrollOffset ?? 0), maxScrollOffset);
|
|
205
|
+
if (options.hasTaskResult) {
|
|
206
|
+
return chatTaskResultPlaceholderDisplayValue(terminalWidth, Boolean(options.taskResultExpanded), Boolean(options.hasWorkers), Boolean(options.hasActiveTask), scrollOffset, maxScrollOffset);
|
|
55
207
|
}
|
|
56
|
-
if (
|
|
57
|
-
return
|
|
208
|
+
if (scrollOffset > 0) {
|
|
209
|
+
return chatHistoryPlaceholderDisplayValue(terminalWidth, scrollOffset, maxScrollOffset);
|
|
210
|
+
}
|
|
211
|
+
if (options.hasActiveTask && !options.hasWorkers) {
|
|
212
|
+
return selectChatPlaceholder(terminalWidth, [
|
|
213
|
+
"message · ^N new · ^P project · ^T tasks · ^G routes",
|
|
214
|
+
"message · ^N new · ^P project · ^G routes",
|
|
215
|
+
"message · ^N new · ^P project",
|
|
216
|
+
"message · ^N new",
|
|
217
|
+
"msg · ^N",
|
|
218
|
+
"msg"
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
if (options.hasWorkers) {
|
|
222
|
+
return chatTaskPlaceholderDisplayValue(terminalWidth, maxScrollOffset > 0, options.hasActiveTask);
|
|
223
|
+
}
|
|
224
|
+
if (maxScrollOffset > 0 && terminalWidth >= 22) {
|
|
225
|
+
return selectChatPlaceholder(terminalWidth, ["message · scroll", "message", "msg"]);
|
|
58
226
|
}
|
|
59
|
-
return
|
|
227
|
+
return selectChatPlaceholder(terminalWidth, [
|
|
228
|
+
"message · ^P project · ^T tasks · ^G routes",
|
|
229
|
+
"message · ^P project · ^G routes",
|
|
230
|
+
"message · ^P project",
|
|
231
|
+
"message",
|
|
232
|
+
"msg"
|
|
233
|
+
]);
|
|
234
|
+
}
|
|
235
|
+
function chatTaskResultPlaceholderDisplayValue(terminalWidth, expanded, hasWorkers, hasActiveTask, scrollOffset, maxScrollOffset) {
|
|
236
|
+
const toggle = expanded ? "^D compact" : "^D details";
|
|
237
|
+
const position = expanded && maxScrollOffset > 0
|
|
238
|
+
? scrollOffset > 0 ? `result ${scrollOffset}/${maxScrollOffset}` : "result · scroll"
|
|
239
|
+
: "message";
|
|
240
|
+
const candidates = hasWorkers
|
|
241
|
+
? [
|
|
242
|
+
`${position} · ${toggle} · ^N new · ^W logs · ^B workers · ^T tasks · Tab · ^O attach`,
|
|
243
|
+
`${position} · ${toggle} · ^N new · ^W logs · ^T tasks · Tab · ^O attach`,
|
|
244
|
+
`${position} · ${toggle} · ^W logs · ^B workers · ^T tasks · Tab · ^O attach`,
|
|
245
|
+
`${position} · ${toggle} · ^W logs · ^T tasks · Tab · ^O attach`,
|
|
246
|
+
`${position} · ${toggle} · ^W logs · Tab · ^O attach`,
|
|
247
|
+
`${position} · ${toggle} · ^W logs`,
|
|
248
|
+
`${toggle} · ^W logs`,
|
|
249
|
+
toggle,
|
|
250
|
+
"^D"
|
|
251
|
+
]
|
|
252
|
+
: [
|
|
253
|
+
`${position} · ${toggle}${hasActiveTask ? " · ^N new" : ""}`,
|
|
254
|
+
`${position} · ${toggle}`,
|
|
255
|
+
toggle,
|
|
256
|
+
"^D"
|
|
257
|
+
];
|
|
258
|
+
return selectChatPlaceholder(terminalWidth, candidates);
|
|
60
259
|
}
|
|
61
|
-
function
|
|
260
|
+
function chatHistoryPlaceholderDisplayValue(terminalWidth, offset, maxOffset) {
|
|
62
261
|
if (terminalWidth < 14) {
|
|
63
|
-
return "
|
|
262
|
+
return "back";
|
|
64
263
|
}
|
|
65
|
-
if (terminalWidth <
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
if (terminalWidth < 24) {
|
|
69
|
-
return "msg · ^W · ^O";
|
|
264
|
+
if (terminalWidth < 20) {
|
|
265
|
+
return `back ${offset}`;
|
|
70
266
|
}
|
|
71
267
|
if (terminalWidth < 38) {
|
|
72
|
-
return
|
|
268
|
+
return selectChatPlaceholder(terminalWidth, [
|
|
269
|
+
`back ${offset}/${maxOffset} · PgDn`,
|
|
270
|
+
`back ${offset}/${maxOffset}`,
|
|
271
|
+
`back ${offset}`,
|
|
272
|
+
"back"
|
|
273
|
+
]);
|
|
73
274
|
}
|
|
74
|
-
|
|
75
|
-
|
|
275
|
+
return selectChatPlaceholder(terminalWidth, [
|
|
276
|
+
`message · back ${offset}/${maxOffset} · PgDn latest`,
|
|
277
|
+
`back ${offset}/${maxOffset} · PgDn latest`,
|
|
278
|
+
`back ${offset}/${maxOffset} · PgDn`,
|
|
279
|
+
`back ${offset}/${maxOffset}`,
|
|
280
|
+
`back ${offset}`,
|
|
281
|
+
"back"
|
|
282
|
+
]);
|
|
283
|
+
}
|
|
284
|
+
function chatTaskPlaceholderDisplayValue(terminalWidth, scrollable = false, activeTask = false) {
|
|
285
|
+
if (activeTask && terminalWidth >= 72) {
|
|
286
|
+
const activeCandidates = scrollable
|
|
287
|
+
? [
|
|
288
|
+
"message · scroll · ^N new · ^W logs · ^B workers · ^T tasks · Tab · ^O attach · ^G routes",
|
|
289
|
+
"message · scroll · ^N new · ^W logs · ^B workers · Tab · ^O attach · ^G routes"
|
|
290
|
+
]
|
|
291
|
+
: [
|
|
292
|
+
"message · ^N new · ^W logs · ^B workers · ^T tasks · Tab · ^O attach · ^G routes",
|
|
293
|
+
"message · ^N new · ^W logs · ^B workers · Tab · ^O attach · ^G routes"
|
|
294
|
+
];
|
|
295
|
+
const active = activeCandidates.find((candidate) => displayWidth(candidate) <= chatPlaceholderValueWidth(terminalWidth));
|
|
296
|
+
if (active) {
|
|
297
|
+
return active;
|
|
298
|
+
}
|
|
76
299
|
}
|
|
77
|
-
return
|
|
300
|
+
return selectChatPlaceholder(terminalWidth, scrollable
|
|
301
|
+
? [
|
|
302
|
+
"message · scroll · ^W logs · ^B workers · ^T tasks · Tab · ^O attach · ^G routes",
|
|
303
|
+
"message · scroll · ^W logs · ^B workers · Tab · ^O attach · ^G routes",
|
|
304
|
+
"message · scroll · ^W logs · Tab · ^O attach · ^G routes",
|
|
305
|
+
"message · scroll · ^W logs · Tab · ^O attach",
|
|
306
|
+
"scroll · ^W logs · Tab · ^O attach",
|
|
307
|
+
"scroll · ^W logs · ^O attach",
|
|
308
|
+
"^W logs · ^O attach",
|
|
309
|
+
"message · ^W logs",
|
|
310
|
+
"msg · ^W logs",
|
|
311
|
+
"^W logs",
|
|
312
|
+
"msg"
|
|
313
|
+
]
|
|
314
|
+
: [
|
|
315
|
+
"message · ^W logs · ^B workers · ^T tasks · Tab · ^O attach · ^G routes",
|
|
316
|
+
"message · ^W logs · ^B workers · Tab · ^O attach · ^G routes",
|
|
317
|
+
"message · ^W logs · Tab · ^O attach · ^G routes",
|
|
318
|
+
"message · ^W logs · Tab · ^O attach",
|
|
319
|
+
"message · ^W logs · ^O attach",
|
|
320
|
+
"^W logs · ^O attach",
|
|
321
|
+
"message · ^W logs",
|
|
322
|
+
"msg · ^W logs",
|
|
323
|
+
"^W logs",
|
|
324
|
+
"msg"
|
|
325
|
+
]);
|
|
326
|
+
}
|
|
327
|
+
function selectChatPlaceholder(terminalWidth, candidates) {
|
|
328
|
+
const valueWidth = chatPlaceholderValueWidth(terminalWidth);
|
|
329
|
+
return candidates.find((candidate) => displayWidth(candidate) <= valueWidth)
|
|
330
|
+
?? candidates.at(-1)
|
|
331
|
+
?? "";
|
|
332
|
+
}
|
|
333
|
+
function chatPlaceholderValueWidth(terminalWidth) {
|
|
334
|
+
return Math.max(1, terminalWidth - (terminalWidth >= 10 ? 6 : 4));
|
|
78
335
|
}
|
|
79
336
|
export function chatBusyDisplayValue(terminalWidth) {
|
|
80
337
|
if (terminalWidth < 14) {
|
|
@@ -83,28 +340,283 @@ export function chatBusyDisplayValue(terminalWidth) {
|
|
|
83
340
|
if (terminalWidth < 22) {
|
|
84
341
|
return "busy";
|
|
85
342
|
}
|
|
86
|
-
|
|
343
|
+
if (terminalWidth >= 34) {
|
|
344
|
+
return "working · Esc stop";
|
|
345
|
+
}
|
|
346
|
+
return "working";
|
|
347
|
+
}
|
|
348
|
+
function routeFallbackInputHints(width) {
|
|
349
|
+
if (width < 10) {
|
|
350
|
+
return { label: "route", detail: "" };
|
|
351
|
+
}
|
|
352
|
+
if (width < 14) {
|
|
353
|
+
return { label: "choose", detail: "" };
|
|
354
|
+
}
|
|
355
|
+
if (width < 20) {
|
|
356
|
+
return { label: "1M", detail: " · 2P" };
|
|
357
|
+
}
|
|
358
|
+
if (width < 28) {
|
|
359
|
+
return { label: "1 Main", detail: " · 2 Pair" };
|
|
360
|
+
}
|
|
361
|
+
if (width < 40) {
|
|
362
|
+
return { label: "1 Main", detail: " · 2 Parallel" };
|
|
363
|
+
}
|
|
364
|
+
if (width < 54) {
|
|
365
|
+
return { label: "route", detail: " · 1 Main · 2 Parallel · Esc" };
|
|
366
|
+
}
|
|
367
|
+
if (width < 75) {
|
|
368
|
+
return { label: "route failed", detail: " · 1 Main · 2 Parallel · R · Esc" };
|
|
369
|
+
}
|
|
370
|
+
return { label: "route failed", detail: " · 1 Main · 2 Parallel · R retry · Esc cancel" };
|
|
371
|
+
}
|
|
372
|
+
export function chatStartingDisplayValue(terminalWidth) {
|
|
373
|
+
if (terminalWidth < 8) {
|
|
374
|
+
return "";
|
|
375
|
+
}
|
|
376
|
+
return terminalWidth < 12 ? "start" : "starting";
|
|
87
377
|
}
|
|
88
378
|
function workerInputHints(width) {
|
|
89
|
-
if (width <
|
|
379
|
+
if (width < 10) {
|
|
90
380
|
return { label: "log", detail: "" };
|
|
91
381
|
}
|
|
92
|
-
if (width <
|
|
93
|
-
return { label: "
|
|
382
|
+
if (width < 16) {
|
|
383
|
+
return { label: "Esc chat", detail: "" };
|
|
384
|
+
}
|
|
385
|
+
if (width < 17) {
|
|
386
|
+
return { label: "log", detail: " · Esc chat" };
|
|
94
387
|
}
|
|
95
|
-
if (width <
|
|
96
|
-
return { label: "
|
|
388
|
+
if (width < 22) {
|
|
389
|
+
return { label: "logs", detail: " · Esc chat" };
|
|
97
390
|
}
|
|
98
391
|
if (width < 28) {
|
|
99
|
-
return { label: "logs", detail: " · Pg ·
|
|
392
|
+
return { label: "logs", detail: " · Pg · Esc chat" };
|
|
393
|
+
}
|
|
394
|
+
if (width < 32) {
|
|
395
|
+
return { label: "logs", detail: " · Pg · Tab · Esc chat" };
|
|
396
|
+
}
|
|
397
|
+
if (width < 44) {
|
|
398
|
+
return { label: "logs", detail: " · scroll · Tab · Esc chat" };
|
|
399
|
+
}
|
|
400
|
+
if (width < 54) {
|
|
401
|
+
return { label: "logs", detail: " · scroll · Tab · ^O attach · Esc chat" };
|
|
100
402
|
}
|
|
101
|
-
if (width <
|
|
102
|
-
return { label: "logs", detail: " ·
|
|
403
|
+
if (width < 71) {
|
|
404
|
+
return { label: "logs", detail: " · scroll · ^F find · Tab · ^O attach · Esc chat" };
|
|
405
|
+
}
|
|
406
|
+
if (width < 84) {
|
|
407
|
+
return { label: "logs", detail: " · scroll · ^F find · E err · D diff · Tab · ^O attach · Esc chat" };
|
|
408
|
+
}
|
|
409
|
+
return { label: "logs", detail: " · scroll · ^F find · E err · D diff · Tab · ^B workers · ^O attach · Esc chat" };
|
|
410
|
+
}
|
|
411
|
+
function statusDetailInputHints(width) {
|
|
412
|
+
return selectInputHints(width, [
|
|
413
|
+
{ label: "status", detail: " · ^S/Esc back · ^C exit" },
|
|
414
|
+
{ label: "status", detail: " · ^S back · ^C exit" },
|
|
415
|
+
{ label: "status", detail: " · ^S back" },
|
|
416
|
+
{ label: "status", detail: "" },
|
|
417
|
+
{ label: "st", detail: "" }
|
|
418
|
+
]);
|
|
419
|
+
}
|
|
420
|
+
function workerOverviewInputHints(width) {
|
|
421
|
+
if (width < 16) {
|
|
422
|
+
return { label: "wrk", detail: "" };
|
|
423
|
+
}
|
|
424
|
+
if (width < 20) {
|
|
425
|
+
return { label: "wrk", detail: " · Esc back" };
|
|
426
|
+
}
|
|
427
|
+
if (width < 28) {
|
|
428
|
+
return { label: "workers", detail: " · Esc back" };
|
|
429
|
+
}
|
|
430
|
+
if (width < 41) {
|
|
431
|
+
return { label: "workers", detail: " · Up/Dn · Esc back" };
|
|
432
|
+
}
|
|
433
|
+
if (width < 53) {
|
|
434
|
+
return { label: "workers", detail: " · Up/Dn · Enter logs · Esc back" };
|
|
103
435
|
}
|
|
104
436
|
if (width < 72) {
|
|
105
|
-
return { label: "
|
|
437
|
+
return { label: "workers", detail: " · Up/Dn · Enter logs · ^O attach · Esc back" };
|
|
438
|
+
}
|
|
439
|
+
if (width < 86) {
|
|
440
|
+
return { label: "workers", detail: " · Up/Dn · Enter logs · F board · C flow · ^O attach · Esc back" };
|
|
441
|
+
}
|
|
442
|
+
return { label: "workers", detail: " · Up/Dn select · Enter logs · F features · C timeline · ^O attach · Esc back" };
|
|
443
|
+
}
|
|
444
|
+
function featureBoardInputHints(width, options) {
|
|
445
|
+
if (options.assignment) {
|
|
446
|
+
return selectInputHints(width, [
|
|
447
|
+
{ label: "assign provider", detail: " · A Actor · C Critic · M/Esc done" },
|
|
448
|
+
{ label: "assign", detail: " · A Actor · C Critic · Esc done" },
|
|
449
|
+
{ label: "assign", detail: " · A actor · C critic" },
|
|
450
|
+
{ label: "provider", detail: " · A · C · Esc" },
|
|
451
|
+
{ label: "provider", detail: "" },
|
|
452
|
+
{ label: "M", detail: "" }
|
|
453
|
+
]);
|
|
454
|
+
}
|
|
455
|
+
if (options.confirmPause) {
|
|
456
|
+
return selectInputHints(width, [
|
|
457
|
+
{ label: "pause feature?", detail: " · P confirm · Esc keep" },
|
|
458
|
+
{ label: "pause?", detail: " · P confirm · Esc keep" },
|
|
459
|
+
{ label: "pause?", detail: " · Esc keep" },
|
|
460
|
+
{ label: "Esc keep", detail: "" },
|
|
461
|
+
{ label: "hold?", detail: "" },
|
|
462
|
+
{ label: "?", detail: "" }
|
|
463
|
+
]);
|
|
464
|
+
}
|
|
465
|
+
if (options.confirmCancel) {
|
|
466
|
+
return selectInputHints(width, [
|
|
467
|
+
{ label: "cancel feature?", detail: " · X confirm · Esc keep" },
|
|
468
|
+
{ label: "cancel?", detail: " · X confirm · Esc keep" },
|
|
469
|
+
{ label: "cancel?", detail: " · Esc keep" },
|
|
470
|
+
{ label: "Esc keep", detail: "" },
|
|
471
|
+
{ label: "stop?", detail: "" },
|
|
472
|
+
{ label: "?", detail: "" }
|
|
473
|
+
]);
|
|
106
474
|
}
|
|
107
|
-
|
|
475
|
+
if (options.canCancel || options.canPause) {
|
|
476
|
+
const controls = [
|
|
477
|
+
...(options.canPause ? ["P pause"] : []),
|
|
478
|
+
...(options.canCancel ? ["X cancel"] : [])
|
|
479
|
+
].join(" · ");
|
|
480
|
+
return selectInputHints(width, [
|
|
481
|
+
{ label: "features", detail: ` · Up/Dn select · Enter timeline · ${controls} · R refresh · Esc workers` },
|
|
482
|
+
{ label: "features", detail: ` · Up/Dn select · ${controls} · R refresh · Esc workers` },
|
|
483
|
+
{ label: "features", detail: ` · Up/Dn select · ${controls} · Esc workers` },
|
|
484
|
+
{ label: "features", detail: ` · ${controls} · Esc workers` },
|
|
485
|
+
{ label: "ft", detail: ` · ${controls} · Esc workers` },
|
|
486
|
+
{ label: "f", detail: ` · ${controls} · Esc workers` },
|
|
487
|
+
{ label: "features", detail: ` · ${controls}` },
|
|
488
|
+
{ label: "ft", detail: ` · ${controls}` },
|
|
489
|
+
{ label: "f", detail: ` · ${controls}` },
|
|
490
|
+
{ label: "features", detail: "" },
|
|
491
|
+
{ label: "ft", detail: "" },
|
|
492
|
+
{ label: "f", detail: "" }
|
|
493
|
+
]);
|
|
494
|
+
}
|
|
495
|
+
if (options.canRetry) {
|
|
496
|
+
return selectInputHints(width, [
|
|
497
|
+
{ label: "features", detail: ` · Up/Dn select · Enter timeline · ${options.canReassign ? "M provider · " : ""}^R retry task · R refresh · Esc workers` },
|
|
498
|
+
{ label: "features", detail: ` · Up/Dn select · ${options.canReassign ? "M provider · " : ""}^R retry task · R refresh · Esc workers` },
|
|
499
|
+
{ label: "features", detail: ` · Up/Dn select · ${options.canReassign ? "M provider · " : ""}^R retry · Esc workers` },
|
|
500
|
+
{ label: "features", detail: " · ^R retry · Esc workers" },
|
|
501
|
+
{ label: "features", detail: " · Esc workers" },
|
|
502
|
+
{ label: "features", detail: "" },
|
|
503
|
+
{ label: "ft", detail: "" },
|
|
504
|
+
{ label: "f", detail: "" }
|
|
505
|
+
]);
|
|
506
|
+
}
|
|
507
|
+
return selectInputHints(width, [
|
|
508
|
+
{ label: "features", detail: " · Up/Dn select · Enter timeline · R refresh · Esc workers" },
|
|
509
|
+
{ label: "features", detail: " · Up/Dn select · Enter timeline · Esc workers" },
|
|
510
|
+
{ label: "features", detail: " · Up/Dn select · Esc workers" },
|
|
511
|
+
{ label: "features", detail: " · Esc workers" },
|
|
512
|
+
{ label: "features", detail: "" },
|
|
513
|
+
{ label: "ft", detail: "" },
|
|
514
|
+
{ label: "f", detail: "" }
|
|
515
|
+
]);
|
|
516
|
+
}
|
|
517
|
+
function collaborationTimelineInputHints(width, unresolvedOnly, back) {
|
|
518
|
+
const backAction = `Esc ${back}`;
|
|
519
|
+
const filterAction = unresolvedOnly ? "U all" : "U unresolved";
|
|
520
|
+
const compactFilterAction = unresolvedOnly ? "U all" : "U open";
|
|
521
|
+
return selectInputHints(width, [
|
|
522
|
+
{
|
|
523
|
+
label: "timeline",
|
|
524
|
+
detail: ` · Up/Dn event · Enter detail · Tab feature · ${filterAction} · R refresh · ${backAction}`
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
label: "timeline",
|
|
528
|
+
detail: ` · Up/Dn event · Enter detail · Tab feature · ${compactFilterAction} · R refresh · ${backAction}`
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
label: "timeline",
|
|
532
|
+
detail: ` · Up/Dn event · Enter detail · Tab feature · ${compactFilterAction} · ${backAction}`
|
|
533
|
+
},
|
|
534
|
+
{ label: "timeline", detail: ` · Up/Dn event · Enter detail · Tab feature · ${backAction}` },
|
|
535
|
+
{ label: "timeline", detail: ` · Up/Dn event · Enter detail · ${backAction}` },
|
|
536
|
+
{ label: "timeline", detail: ` · Enter detail · ${backAction}` },
|
|
537
|
+
{ label: "timeline", detail: ` · ${backAction}` },
|
|
538
|
+
{ label: backAction, detail: "" },
|
|
539
|
+
{ label: "flow", detail: "" },
|
|
540
|
+
{ label: "tl", detail: "" },
|
|
541
|
+
{ label: "t", detail: "" }
|
|
542
|
+
]);
|
|
543
|
+
}
|
|
544
|
+
function collaborationDetailInputHints(width) {
|
|
545
|
+
return selectInputHints(width, [
|
|
546
|
+
{ label: "event detail", detail: " · scroll · Enter/Esc timeline" },
|
|
547
|
+
{ label: "event", detail: " · Pg scroll · Enter/Esc timeline" },
|
|
548
|
+
{ label: "event", detail: " · Pg scroll · Esc timeline" },
|
|
549
|
+
{ label: "event", detail: " · Esc timeline" },
|
|
550
|
+
{ label: "Esc timeline", detail: "" },
|
|
551
|
+
{ label: "event", detail: "" },
|
|
552
|
+
{ label: "e", detail: "" }
|
|
553
|
+
]);
|
|
554
|
+
}
|
|
555
|
+
function taskSessionsInputHints(width, includeArchived) {
|
|
556
|
+
const archivedAction = includeArchived ? "H hide archived" : "H archived";
|
|
557
|
+
return selectInputHints(width, [
|
|
558
|
+
{ label: "sessions", detail: ` · Up/Dn select · Enter restore · I inspect · R rename · A archive · D delete · E export · ${archivedAction} · Esc back` },
|
|
559
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · I inspect · R rename · A archive · D delete · E export · Esc back" },
|
|
560
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · I inspect · R rename · A archive · D delete · Esc back" },
|
|
561
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · I inspect · R rename · A archive · Esc back" },
|
|
562
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · I inspect · R rename · Esc back" },
|
|
563
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · R rename · Esc back" },
|
|
564
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · I inspect · Esc back" },
|
|
565
|
+
{ label: "sessions", detail: " · Up/Dn select · Enter restore · Esc back" },
|
|
566
|
+
{ label: "sessions", detail: " · Up/Dn select · Esc back" },
|
|
567
|
+
{ label: "sessions", detail: " · Esc back" },
|
|
568
|
+
{ label: "Esc back", detail: "" },
|
|
569
|
+
{ label: "sessions", detail: "" },
|
|
570
|
+
{ label: "ses", detail: "" },
|
|
571
|
+
{ label: "s", detail: "" }
|
|
572
|
+
]);
|
|
573
|
+
}
|
|
574
|
+
function taskSessionDetailInputHints(width, hasNative, canFork) {
|
|
575
|
+
const nativeActions = hasNative
|
|
576
|
+
? `${canFork ? "C continue · B branch" : "C continue"} · `
|
|
577
|
+
: "";
|
|
578
|
+
return selectInputHints(width, [
|
|
579
|
+
{ label: "session", detail: ` · Up/Dn worker · Enter logs · ${nativeActions}R refresh · Esc tasks` },
|
|
580
|
+
{ label: "session", detail: ` · Up/Dn worker · Enter logs · ${nativeActions}Esc tasks` },
|
|
581
|
+
{ label: "session", detail: ` · Up/Dn · Enter logs · ${nativeActions}Esc tasks` },
|
|
582
|
+
{ label: "session", detail: ` · Enter logs · ${nativeActions}Esc tasks` },
|
|
583
|
+
{ label: "session", detail: ` · ${hasNative ? "C continue · " : ""}Esc tasks` },
|
|
584
|
+
{ label: "session", detail: " · Esc tasks" },
|
|
585
|
+
{ label: "Esc tasks", detail: "" },
|
|
586
|
+
{ label: "session", detail: "" },
|
|
587
|
+
{ label: "ses", detail: "" },
|
|
588
|
+
{ label: "s", detail: "" }
|
|
589
|
+
]);
|
|
590
|
+
}
|
|
591
|
+
function taskSessionDeleteInputHints(width, title) {
|
|
592
|
+
const safeTitle = title.replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
|
|
593
|
+
return selectInputHints(width, [
|
|
594
|
+
{ label: "delete", detail: ` · ${safeTitle} · D confirm · Esc cancel` },
|
|
595
|
+
{ label: "delete", detail: " · D confirm · Esc cancel" },
|
|
596
|
+
{ label: "D confirm", detail: " · Esc cancel" },
|
|
597
|
+
{ label: "D confirm", detail: "" },
|
|
598
|
+
{ label: "D", detail: "" }
|
|
599
|
+
]);
|
|
600
|
+
}
|
|
601
|
+
function workerSearchInputSuffix(width, matchIndex, matchCount) {
|
|
602
|
+
const count = Math.max(0, Math.trunc(matchCount));
|
|
603
|
+
const index = count > 0
|
|
604
|
+
? Math.min(count - 1, Math.max(0, Math.trunc(matchIndex))) + 1
|
|
605
|
+
: 0;
|
|
606
|
+
const position = `${index}/${count}`;
|
|
607
|
+
if (width < 16) {
|
|
608
|
+
return "";
|
|
609
|
+
}
|
|
610
|
+
if (width < 24) {
|
|
611
|
+
return ` · ${position}`;
|
|
612
|
+
}
|
|
613
|
+
if (width < 36) {
|
|
614
|
+
return ` · ${position} · Esc`;
|
|
615
|
+
}
|
|
616
|
+
if (width < 52) {
|
|
617
|
+
return ` · ${position} · Enter · Esc`;
|
|
618
|
+
}
|
|
619
|
+
return ` · ${position} · Enter next · Up/Dn · Esc logs`;
|
|
108
620
|
}
|
|
109
621
|
function nativeInputHints(width, closed = false) {
|
|
110
622
|
if (closed) {
|
|
@@ -117,13 +629,10 @@ function nativeInputHints(width, closed = false) {
|
|
|
117
629
|
if (width < 24) {
|
|
118
630
|
return { label: "closed", detail: " · ^]" };
|
|
119
631
|
}
|
|
120
|
-
if (width <
|
|
632
|
+
if (width < 27) {
|
|
121
633
|
return { label: "closed", detail: " · Pg · ^]" };
|
|
122
634
|
}
|
|
123
|
-
|
|
124
|
-
return { label: "closed", detail: " · Pg/wheel · ^]" };
|
|
125
|
-
}
|
|
126
|
-
return { label: "closed", detail: " · wheel/Pg · ^] back" };
|
|
635
|
+
return { label: "closed", detail: " · scroll · ^] logs" };
|
|
127
636
|
}
|
|
128
637
|
if (width < 12) {
|
|
129
638
|
return { label: "nat", detail: " ^]" };
|
|
@@ -131,11 +640,26 @@ function nativeInputHints(width, closed = false) {
|
|
|
131
640
|
if (width < 24) {
|
|
132
641
|
return { label: "native", detail: " · ^]" };
|
|
133
642
|
}
|
|
134
|
-
if (width <
|
|
643
|
+
if (width < 27) {
|
|
135
644
|
return { label: "native", detail: " · Pg · ^]" };
|
|
136
645
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return
|
|
646
|
+
return { label: "native", detail: " · scroll · ^] logs" };
|
|
647
|
+
}
|
|
648
|
+
function routerInputHints(width) {
|
|
649
|
+
return selectInputHints(width, [
|
|
650
|
+
{ label: "routes", detail: " · scroll · Tab scope · ^G refresh · Esc chat" },
|
|
651
|
+
{ label: "routes", detail: " · scroll · ^G refresh · Esc chat" },
|
|
652
|
+
{ label: "routes", detail: " · Pg scroll · Esc chat" },
|
|
653
|
+
{ label: "routes", detail: " · Esc chat" },
|
|
654
|
+
{ label: "Esc chat", detail: "" },
|
|
655
|
+
{ label: "routes", detail: "" },
|
|
656
|
+
{ label: "rt", detail: "" },
|
|
657
|
+
{ label: "r", detail: "" }
|
|
658
|
+
]);
|
|
659
|
+
}
|
|
660
|
+
function selectInputHints(width, candidates) {
|
|
661
|
+
const contentWidth = Math.max(1, Math.trunc(width) - (width > 1 ? 2 : 0));
|
|
662
|
+
return candidates.find((candidate) => displayWidth(`${candidate.label}${candidate.detail}`) <= contentWidth)
|
|
663
|
+
?? candidates.at(-1)
|
|
664
|
+
?? { label: "", detail: "" };
|
|
141
665
|
}
|