parallel-codex-tui 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -8
- package/dist/cli.js +22 -2
- package/dist/core/session-index.js +123 -10
- package/dist/core/session-manager.js +15 -4
- package/dist/core/task-report.js +510 -0
- package/dist/core/task-search.js +142 -0
- package/dist/orchestrator/orchestrator.js +26 -4
- package/dist/supervisor/client.js +442 -0
- package/dist/supervisor/protocol.js +177 -0
- package/dist/supervisor/runner.js +238 -0
- package/dist/supervisor/store.js +213 -0
- package/dist/tui/App.js +169 -36
- package/dist/tui/AppShell.js +7 -3
- package/dist/tui/InputBar.js +20 -6
- package/dist/tui/TaskSessionsView.js +30 -9
- package/dist/version.js +1 -1
- package/dist/workers/mock-adapter.js +18 -0
- package/package.json +1 -1
package/dist/tui/App.js
CHANGED
|
@@ -7,6 +7,7 @@ import { copyTextToClipboard } from "../core/clipboard.js";
|
|
|
7
7
|
import { readJson } from "../core/file-store.js";
|
|
8
8
|
import { CONFIGURABLE_ROLES, configuredRoleSelection } from "../core/role-configuration.js";
|
|
9
9
|
import { WorkerStatusSchema } from "../domain/schemas.js";
|
|
10
|
+
import { isSupervisorDetachedError } from "../supervisor/client.js";
|
|
10
11
|
import { effectiveWorkerWatchdog, formatRoutePendingStatus, formatRoutePendingSummaryStatus, formatRouteStatus, formatRouteSummaryStatus, formatStatusLine, formatWorkerRuntimeStatus } from "./status-line.js";
|
|
11
12
|
import { applyChatInputChunk, insertChatPaste } from "./chat-input.js";
|
|
12
13
|
import { chatRequestHistory, navigateChatDraftHistory } from "./chat-history.js";
|
|
@@ -62,6 +63,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
62
63
|
const [inputCursor, setInputCursor] = useState(0);
|
|
63
64
|
const [inputReady, setInputReady] = useState(false);
|
|
64
65
|
const [terminalSize, setTerminalSize] = useState(readTerminalSize);
|
|
66
|
+
const [, setBackgroundRunRevision] = useState(0);
|
|
65
67
|
const [messages, setMessages] = useState(() => [...initialMessages]);
|
|
66
68
|
const [taskResultExpanded, setTaskResultExpanded] = useState(() => (Boolean(initialTaskId) && latestTaskResultMessageIndex(initialMessages, initialTaskId) >= 0));
|
|
67
69
|
const [busy, setBusy] = useState(false);
|
|
@@ -119,6 +121,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
119
121
|
const [taskSessionsError, setTaskSessionsError] = useState(null);
|
|
120
122
|
const [taskSessionsNotice, setTaskSessionsNotice] = useState(null);
|
|
121
123
|
const [taskSessionsIncludeArchived, setTaskSessionsIncludeArchived] = useState(false);
|
|
124
|
+
const [taskSessionQuery, setTaskSessionQuery] = useState("");
|
|
122
125
|
const [taskSessionAction, setTaskSessionAction] = useState(null);
|
|
123
126
|
const [taskSessionDetails, setTaskSessionDetails] = useState(null);
|
|
124
127
|
const [taskSessionDetailSelectedWorkerIndex, setTaskSessionDetailSelectedWorkerIndex] = useState(0);
|
|
@@ -147,6 +150,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
147
150
|
const copyTextByViewRef = useRef({ chat: "", worker: "" });
|
|
148
151
|
const messagesRef = useRef([...initialMessages]);
|
|
149
152
|
const activeRunControllerRef = useRef(null);
|
|
153
|
+
const backgroundRestoreStartedRef = useRef(false);
|
|
150
154
|
const activeTaskIdRef = useRef(initialTaskId);
|
|
151
155
|
const nativeInputRef = useRef(nativeInput);
|
|
152
156
|
const inputRef = useRef(input);
|
|
@@ -174,6 +178,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
174
178
|
const mainConversationActionRef = useRef(mainConversationAction);
|
|
175
179
|
const taskSessionsLoadingRef = useRef(taskSessionsLoading);
|
|
176
180
|
const taskSessionsIncludeArchivedRef = useRef(taskSessionsIncludeArchived);
|
|
181
|
+
const taskSessionQueryRef = useRef("");
|
|
177
182
|
const taskSessionActionRef = useRef(taskSessionAction);
|
|
178
183
|
const taskSessionDetailsRef = useRef(null);
|
|
179
184
|
const taskSessionDetailSelectedWorkerIndexRef = useRef(0);
|
|
@@ -268,6 +273,8 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
268
273
|
&& !busy
|
|
269
274
|
&& canRetryTask
|
|
270
275
|
&& selectedBoardFeature?.state !== "approved";
|
|
276
|
+
const backgroundRunAttached = orchestrator.backgroundRunAttached?.() ?? false;
|
|
277
|
+
const backgroundRunControllable = orchestrator.backgroundRunControllable?.() ?? backgroundRunAttached;
|
|
271
278
|
const visibleStatus = statusLineWithWorkerRefs(status, workers);
|
|
272
279
|
const visibleRouteStatus = routePending
|
|
273
280
|
? formatRoutePendingStatus(routePending, routeElapsedMs)
|
|
@@ -288,6 +295,9 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
288
295
|
: roleConfigurationSnapshot.future
|
|
289
296
|
: configuredRoleSelection(config);
|
|
290
297
|
const roleConfigurationHasOverride = roleConfigurationScopeHasOverride(roleConfigurationSnapshot, roleConfigurationScope);
|
|
298
|
+
useEffect(() => orchestrator.subscribeBackgroundRunState?.(() => {
|
|
299
|
+
setBackgroundRunRevision((current) => current + 1);
|
|
300
|
+
}), [orchestrator]);
|
|
291
301
|
useEffect(() => {
|
|
292
302
|
inputRef.current = input;
|
|
293
303
|
}, [input]);
|
|
@@ -453,6 +463,9 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
453
463
|
useEffect(() => {
|
|
454
464
|
taskSessionsIncludeArchivedRef.current = taskSessionsIncludeArchived;
|
|
455
465
|
}, [taskSessionsIncludeArchived]);
|
|
466
|
+
useEffect(() => {
|
|
467
|
+
taskSessionQueryRef.current = taskSessionQuery;
|
|
468
|
+
}, [taskSessionQuery]);
|
|
456
469
|
useEffect(() => {
|
|
457
470
|
taskSessionActionRef.current = taskSessionAction;
|
|
458
471
|
}, [taskSessionAction]);
|
|
@@ -628,6 +641,70 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
628
641
|
active = false;
|
|
629
642
|
};
|
|
630
643
|
}, [activeTaskId, initialTaskId, initialWorkers, orchestrator]);
|
|
644
|
+
useEffect(() => {
|
|
645
|
+
if (!orchestrator.restorePendingRun || backgroundRestoreStartedRef.current) {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
backgroundRestoreStartedRef.current = true;
|
|
649
|
+
const controller = new AbortController();
|
|
650
|
+
activeRunControllerRef.current = controller;
|
|
651
|
+
let active = true;
|
|
652
|
+
async function restoreBackgroundRun() {
|
|
653
|
+
busyRef.current = true;
|
|
654
|
+
setBusy(true);
|
|
655
|
+
try {
|
|
656
|
+
const result = await orchestrator.restorePendingRun?.({
|
|
657
|
+
cwd,
|
|
658
|
+
...createRunCallbacks(controller, { announceRoute: false })
|
|
659
|
+
});
|
|
660
|
+
if (!active || !result) {
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const taskId = result.taskId ?? activeTaskIdRef.current;
|
|
664
|
+
activeTaskIdRef.current = taskId;
|
|
665
|
+
setActiveTaskId(taskId);
|
|
666
|
+
setActiveMode(taskId ? "complex" : result.mode);
|
|
667
|
+
setCanRetryTask(taskId ? await orchestrator.canRetryTask(taskId) : false);
|
|
668
|
+
await refreshRoleConfigurationState(taskId);
|
|
669
|
+
if (!messagesRef.current.some((message) => message.from === "system" && message.text === result.summary && message.taskId === (taskId ?? undefined))) {
|
|
670
|
+
await appendVisibleMessage({ from: "system", text: result.summary }, taskId ?? undefined, { persist: false });
|
|
671
|
+
}
|
|
672
|
+
if (result.mode === "complex" && parseTaskResultSummary(result.summary)) {
|
|
673
|
+
setTaskResultExpanded(true);
|
|
674
|
+
}
|
|
675
|
+
await orchestrator.acknowledgeBackgroundRun?.();
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
if (!active || isSupervisorDetachedError(error)) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
const taskId = activeTaskIdRef.current;
|
|
682
|
+
const text = isAbortError(error)
|
|
683
|
+
? "cancelled · request stopped"
|
|
684
|
+
: error instanceof Error ? error.message : String(error);
|
|
685
|
+
if (!messagesRef.current.some((message) => message.from === "system" && message.text === text && message.taskId === (taskId ?? undefined))) {
|
|
686
|
+
await appendVisibleMessage({ from: "system", text }, taskId ?? undefined, { persist: false });
|
|
687
|
+
}
|
|
688
|
+
await orchestrator.acknowledgeBackgroundRun?.();
|
|
689
|
+
setCanRetryTask(taskId ? await orchestrator.canRetryTask(taskId) : false);
|
|
690
|
+
}
|
|
691
|
+
finally {
|
|
692
|
+
if (activeRunControllerRef.current === controller) {
|
|
693
|
+
activeRunControllerRef.current = null;
|
|
694
|
+
}
|
|
695
|
+
if (active) {
|
|
696
|
+
setRoutePending(null);
|
|
697
|
+
setRouteAnnouncement(null);
|
|
698
|
+
busyRef.current = false;
|
|
699
|
+
setBusy(false);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
void restoreBackgroundRun();
|
|
704
|
+
return () => {
|
|
705
|
+
active = false;
|
|
706
|
+
};
|
|
707
|
+
}, [cwd, orchestrator]);
|
|
631
708
|
useEffect(() => {
|
|
632
709
|
if (workers.length === 0 || !status) {
|
|
633
710
|
return;
|
|
@@ -763,8 +840,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
763
840
|
process.stdout.write("\x1b[?2004h\x1b[?1006l\x1b[?1003l\x1b[?1002l\x1b[?1000l");
|
|
764
841
|
const commitChatInputUpdate = (update, previousValue, previousCursor) => {
|
|
765
842
|
if (update.exit) {
|
|
766
|
-
|
|
767
|
-
exitRef.current();
|
|
843
|
+
requestAppExit();
|
|
768
844
|
return false;
|
|
769
845
|
}
|
|
770
846
|
if (busyRef.current) {
|
|
@@ -877,8 +953,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
877
953
|
if (currentView === "chat" && routeFallbackPromptRef.current) {
|
|
878
954
|
const fallbackChunks = tokenizeRawInput(chunk);
|
|
879
955
|
if (fallbackChunks.some((fallbackChunk) => isExitShortcut(fallbackChunk, {}))) {
|
|
880
|
-
|
|
881
|
-
exitRef.current();
|
|
956
|
+
requestAppExit();
|
|
882
957
|
return;
|
|
883
958
|
}
|
|
884
959
|
if (fallbackChunks.some((fallbackChunk) => isStatusDetailsShortcut(fallbackChunk, {}))) {
|
|
@@ -928,8 +1003,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
928
1003
|
if (currentView === "roles") {
|
|
929
1004
|
const roleChunks = tokenizeRawInput(chunk);
|
|
930
1005
|
if (roleChunks.some((roleChunk) => isExitShortcut(roleChunk, {}))) {
|
|
931
|
-
|
|
932
|
-
exitRef.current();
|
|
1006
|
+
requestAppExit();
|
|
933
1007
|
return;
|
|
934
1008
|
}
|
|
935
1009
|
if (roleChunks.some((roleChunk) => isStatusDetailsShortcut(roleChunk, {}))) {
|
|
@@ -1044,8 +1118,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1044
1118
|
}
|
|
1045
1119
|
if (currentView === "status") {
|
|
1046
1120
|
if (isExitShortcut(chunk, {})) {
|
|
1047
|
-
|
|
1048
|
-
exitRef.current();
|
|
1121
|
+
requestAppExit();
|
|
1049
1122
|
return;
|
|
1050
1123
|
}
|
|
1051
1124
|
if (isStatusDetailsShortcut(chunk, {}) || chunk === "\x1b") {
|
|
@@ -1063,8 +1136,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1063
1136
|
}
|
|
1064
1137
|
if (currentView === "sessions") {
|
|
1065
1138
|
if (isExitShortcut(chunk, {})) {
|
|
1066
|
-
|
|
1067
|
-
exitRef.current();
|
|
1139
|
+
requestAppExit();
|
|
1068
1140
|
return;
|
|
1069
1141
|
}
|
|
1070
1142
|
if (taskSessionDetailsRef.current) {
|
|
@@ -1246,10 +1318,38 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1246
1318
|
const sessionAction = taskSessionActionRef.current;
|
|
1247
1319
|
if (sessionAction) {
|
|
1248
1320
|
if (chunk === "\x1b") {
|
|
1321
|
+
if (sessionAction.type === "search") {
|
|
1322
|
+
const preferred = taskSessionsRef.current[selectedTaskSessionIndexRef.current]?.id ?? null;
|
|
1323
|
+
updateTaskSessionAction(null);
|
|
1324
|
+
setTaskSessionsError(null);
|
|
1325
|
+
void refreshTaskSessionsRef.current(preferred, sessionAction.previousQuery);
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1249
1328
|
updateTaskSessionAction(null);
|
|
1250
1329
|
setTaskSessionsError(null);
|
|
1251
1330
|
return;
|
|
1252
1331
|
}
|
|
1332
|
+
if (sessionAction.type === "search") {
|
|
1333
|
+
const update = applyChatInputChunk(sessionAction.value, chunk, sessionAction.cursor);
|
|
1334
|
+
const preferred = taskSessionsRef.current[selectedTaskSessionIndexRef.current]?.id ?? null;
|
|
1335
|
+
if (update.submit !== null) {
|
|
1336
|
+
updateTaskSessionAction(null);
|
|
1337
|
+
setTaskSessionsError(null);
|
|
1338
|
+
void refreshTaskSessionsRef.current(preferred, update.submit);
|
|
1339
|
+
}
|
|
1340
|
+
else {
|
|
1341
|
+
updateTaskSessionAction({
|
|
1342
|
+
...sessionAction,
|
|
1343
|
+
value: update.value,
|
|
1344
|
+
cursor: update.cursor
|
|
1345
|
+
});
|
|
1346
|
+
if (update.value !== sessionAction.value) {
|
|
1347
|
+
setTaskSessionsError(null);
|
|
1348
|
+
void refreshTaskSessionsRef.current(preferred, update.value);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1253
1353
|
if (taskSessionsLoadingRef.current) {
|
|
1254
1354
|
return;
|
|
1255
1355
|
}
|
|
@@ -1286,6 +1386,17 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1286
1386
|
if (taskSessionsLoadingRef.current) {
|
|
1287
1387
|
return;
|
|
1288
1388
|
}
|
|
1389
|
+
if (isWorkerSearchShortcut(chunk, {})) {
|
|
1390
|
+
updateTaskSessionAction({
|
|
1391
|
+
type: "search",
|
|
1392
|
+
value: taskSessionQueryRef.current,
|
|
1393
|
+
cursor: Array.from(taskSessionQueryRef.current).length,
|
|
1394
|
+
previousQuery: taskSessionQueryRef.current
|
|
1395
|
+
});
|
|
1396
|
+
setTaskSessionsError(null);
|
|
1397
|
+
setTaskSessionsNotice(null);
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1289
1400
|
if (isRouterDiagnosticsShortcut(chunk, {})) {
|
|
1290
1401
|
void openRouterDiagnosticsRef.current();
|
|
1291
1402
|
return;
|
|
@@ -1303,6 +1414,11 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1303
1414
|
return;
|
|
1304
1415
|
}
|
|
1305
1416
|
const selectedSession = taskSessionsRef.current[selectedTaskSessionIndexRef.current];
|
|
1417
|
+
if ((chunk === "x" || chunk === "X") && taskSessionQueryRef.current.trim()) {
|
|
1418
|
+
void refreshTaskSessionsRef.current(selectedSession?.id ?? null, "");
|
|
1419
|
+
setTaskSessionsNotice("Task search cleared");
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1306
1422
|
if (chunk === "r" || chunk === "R") {
|
|
1307
1423
|
if (selectedSession) {
|
|
1308
1424
|
updateTaskSessionAction({
|
|
@@ -1373,8 +1489,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1373
1489
|
if (currentView === "features") {
|
|
1374
1490
|
const featureChunks = tokenizeRawInput(chunk);
|
|
1375
1491
|
if (featureChunks.some((featureChunk) => isExitShortcut(featureChunk, {}))) {
|
|
1376
|
-
|
|
1377
|
-
exitRef.current();
|
|
1492
|
+
requestAppExit();
|
|
1378
1493
|
return;
|
|
1379
1494
|
}
|
|
1380
1495
|
const pendingCancel = featureCancelPromptRef.current;
|
|
@@ -1526,8 +1641,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1526
1641
|
if (currentView === "collaboration") {
|
|
1527
1642
|
const timelineChunks = tokenizeRawInput(chunk);
|
|
1528
1643
|
if (timelineChunks.some((timelineChunk) => isExitShortcut(timelineChunk, {}))) {
|
|
1529
|
-
|
|
1530
|
-
exitRef.current();
|
|
1644
|
+
requestAppExit();
|
|
1531
1645
|
return;
|
|
1532
1646
|
}
|
|
1533
1647
|
for (const timelineChunk of timelineChunks) {
|
|
@@ -1617,8 +1731,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1617
1731
|
}
|
|
1618
1732
|
if (currentView === "workers") {
|
|
1619
1733
|
if (isExitShortcut(chunk, {})) {
|
|
1620
|
-
|
|
1621
|
-
exitRef.current();
|
|
1734
|
+
requestAppExit();
|
|
1622
1735
|
return;
|
|
1623
1736
|
}
|
|
1624
1737
|
if (isWorkerOverviewShortcut(chunk, {}) || chunk === "\x1b") {
|
|
@@ -1681,8 +1794,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1681
1794
|
if (currentView === "router") {
|
|
1682
1795
|
const routerChunks = tokenizeRawInput(chunk);
|
|
1683
1796
|
if (routerChunks.some((routerChunk) => isExitShortcut(routerChunk, {}))) {
|
|
1684
|
-
|
|
1685
|
-
exitRef.current();
|
|
1797
|
+
requestAppExit();
|
|
1686
1798
|
return;
|
|
1687
1799
|
}
|
|
1688
1800
|
for (const routerChunk of routerChunks) {
|
|
@@ -1719,8 +1831,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1719
1831
|
if (currentView === "worker") {
|
|
1720
1832
|
for (const workerChunk of tokenizeRawInput(chunk)) {
|
|
1721
1833
|
if (isExitShortcut(workerChunk, {})) {
|
|
1722
|
-
|
|
1723
|
-
exitRef.current();
|
|
1834
|
+
requestAppExit();
|
|
1724
1835
|
return;
|
|
1725
1836
|
}
|
|
1726
1837
|
if (workerSearchRef.current.open) {
|
|
@@ -1975,6 +2086,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1975
2086
|
nativeAttachRequestSequenceRef.current += 1;
|
|
1976
2087
|
nativeAttachRef.current?.process.kill();
|
|
1977
2088
|
nativeAttachRef.current = null;
|
|
2089
|
+
orchestrator.detachBackgroundRuns?.();
|
|
1978
2090
|
activeRunControllerRef.current?.abort();
|
|
1979
2091
|
collaborationLoadSequenceRef.current += 1;
|
|
1980
2092
|
routerLoadSequenceRef.current += 1;
|
|
@@ -1990,8 +2102,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
1990
2102
|
return;
|
|
1991
2103
|
}
|
|
1992
2104
|
const shutdown = () => {
|
|
1993
|
-
|
|
1994
|
-
exitRef.current();
|
|
2105
|
+
requestAppExit();
|
|
1995
2106
|
};
|
|
1996
2107
|
if (shutdownSignal.aborted) {
|
|
1997
2108
|
shutdown();
|
|
@@ -2000,6 +2111,11 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2000
2111
|
shutdownSignal.addEventListener("abort", shutdown, { once: true });
|
|
2001
2112
|
return () => shutdownSignal.removeEventListener("abort", shutdown);
|
|
2002
2113
|
}, [shutdownSignal]);
|
|
2114
|
+
function requestAppExit() {
|
|
2115
|
+
orchestrator.detachBackgroundRuns?.();
|
|
2116
|
+
activeRunControllerRef.current?.abort();
|
|
2117
|
+
exitRef.current();
|
|
2118
|
+
}
|
|
2003
2119
|
async function copyVisibleView() {
|
|
2004
2120
|
const payload = visibleClipboardPayload(viewRef.current);
|
|
2005
2121
|
if (!payload?.text.trim()) {
|
|
@@ -2147,8 +2263,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2147
2263
|
useInput((inputKey, key) => {
|
|
2148
2264
|
if (view === "worker") {
|
|
2149
2265
|
if (isExitShortcut(inputKey, key)) {
|
|
2150
|
-
|
|
2151
|
-
exitRef.current();
|
|
2266
|
+
requestAppExit();
|
|
2152
2267
|
return;
|
|
2153
2268
|
}
|
|
2154
2269
|
if (isNewConversationShortcut(inputKey, key) && !busy) {
|
|
@@ -2370,14 +2485,14 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2370
2485
|
function settleRouteFallbackChoice(choice) {
|
|
2371
2486
|
routeFallbackResolverRef.current?.(choice);
|
|
2372
2487
|
}
|
|
2373
|
-
async function appendVisibleMessage(message, taskId) {
|
|
2488
|
+
async function appendVisibleMessage(message, taskId, options = {}) {
|
|
2374
2489
|
const visibleMessage = taskId ? { ...message, taskId } : message;
|
|
2375
2490
|
setMessages((current) => {
|
|
2376
2491
|
const next = [...current, visibleMessage];
|
|
2377
2492
|
messagesRef.current = next;
|
|
2378
2493
|
return next;
|
|
2379
2494
|
});
|
|
2380
|
-
if (!persistChatMessage) {
|
|
2495
|
+
if (!persistChatMessage || options.persist === false) {
|
|
2381
2496
|
return;
|
|
2382
2497
|
}
|
|
2383
2498
|
try {
|
|
@@ -2464,13 +2579,17 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2464
2579
|
: false);
|
|
2465
2580
|
await refreshRoleConfigurationState(nextMemory.activeTaskId);
|
|
2466
2581
|
setRouteAnnouncement(null);
|
|
2467
|
-
await appendVisibleMessage({ from: "system", text: result.summary }, nextMemory.activeTaskId ?? undefined);
|
|
2582
|
+
await appendVisibleMessage({ from: "system", text: result.summary }, nextMemory.activeTaskId ?? undefined, { persist: !orchestrator.persistsRunResults });
|
|
2583
|
+
await orchestrator.acknowledgeBackgroundRun?.();
|
|
2468
2584
|
if (result.mode === "complex" && parseTaskResultSummary(result.summary)) {
|
|
2469
2585
|
setTaskResultExpanded(true);
|
|
2470
2586
|
}
|
|
2471
2587
|
}
|
|
2472
2588
|
catch (error) {
|
|
2473
2589
|
setRouteAnnouncement(null);
|
|
2590
|
+
if (isSupervisorDetachedError(error)) {
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2474
2593
|
const retryTaskId = activeTaskIdRef.current;
|
|
2475
2594
|
if (retryTaskId) {
|
|
2476
2595
|
setCanRetryTask(await orchestrator.canRetryTask(retryTaskId));
|
|
@@ -2479,7 +2598,8 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2479
2598
|
await appendVisibleMessage({
|
|
2480
2599
|
from: "system",
|
|
2481
2600
|
text: isAbortError(error) ? "cancelled · request stopped" : error instanceof Error ? error.message : String(error)
|
|
2482
|
-
}, retryTaskId ?? undefined);
|
|
2601
|
+
}, retryTaskId ?? undefined, { persist: !orchestrator.persistsRunResults });
|
|
2602
|
+
await orchestrator.acknowledgeBackgroundRun?.();
|
|
2483
2603
|
}
|
|
2484
2604
|
finally {
|
|
2485
2605
|
if (activeRunControllerRef.current === controller) {
|
|
@@ -2525,19 +2645,24 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2525
2645
|
setCanRetryTask(false);
|
|
2526
2646
|
await refreshRoleConfigurationState(taskId);
|
|
2527
2647
|
setRouteAnnouncement(null);
|
|
2528
|
-
await appendVisibleMessage({ from: "system", text: result.summary }, taskId);
|
|
2648
|
+
await appendVisibleMessage({ from: "system", text: result.summary }, taskId, { persist: !orchestrator.persistsRunResults });
|
|
2649
|
+
await orchestrator.acknowledgeBackgroundRun?.();
|
|
2529
2650
|
if (parseTaskResultSummary(result.summary)) {
|
|
2530
2651
|
setTaskResultExpanded(true);
|
|
2531
2652
|
}
|
|
2532
2653
|
}
|
|
2533
2654
|
catch (error) {
|
|
2534
2655
|
setRouteAnnouncement(null);
|
|
2656
|
+
if (isSupervisorDetachedError(error)) {
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2535
2659
|
setCanRetryTask(await orchestrator.canRetryTask(taskId));
|
|
2536
2660
|
await refreshRoleConfigurationState(taskId);
|
|
2537
2661
|
await appendVisibleMessage({
|
|
2538
2662
|
from: "system",
|
|
2539
2663
|
text: isAbortError(error) ? "cancelled · retry stopped" : error instanceof Error ? error.message : String(error)
|
|
2540
|
-
}, taskId);
|
|
2664
|
+
}, taskId, { persist: !orchestrator.persistsRunResults });
|
|
2665
|
+
await orchestrator.acknowledgeBackgroundRun?.();
|
|
2541
2666
|
}
|
|
2542
2667
|
finally {
|
|
2543
2668
|
if (activeRunControllerRef.current === controller) {
|
|
@@ -2656,11 +2781,16 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2656
2781
|
setTaskSessionDetailNotice(null);
|
|
2657
2782
|
updateTaskSessionAction(null);
|
|
2658
2783
|
updateMainConversationAction(null);
|
|
2784
|
+
taskSessionQueryRef.current = "";
|
|
2785
|
+
setTaskSessionQuery("");
|
|
2659
2786
|
sessionCenterModeRef.current = "tasks";
|
|
2660
2787
|
setSessionCenterMode("tasks");
|
|
2661
2788
|
await refreshTaskSessions(activeTaskIdRef.current);
|
|
2662
2789
|
}
|
|
2663
|
-
async function refreshTaskSessions(preferredTaskId = null) {
|
|
2790
|
+
async function refreshTaskSessions(preferredTaskId = null, query = taskSessionQueryRef.current) {
|
|
2791
|
+
const normalizedQuery = query.replace(/[\u0000-\u001f\u007f]/g, " ").slice(0, 1000);
|
|
2792
|
+
taskSessionQueryRef.current = normalizedQuery;
|
|
2793
|
+
setTaskSessionQuery(normalizedQuery);
|
|
2664
2794
|
taskSessionsLoadingRef.current = true;
|
|
2665
2795
|
setTaskSessionsLoading(true);
|
|
2666
2796
|
const sequence = taskSessionsLoadSequenceRef.current + 1;
|
|
@@ -2670,7 +2800,8 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
2670
2800
|
throw new Error("Task sessions are unavailable");
|
|
2671
2801
|
}
|
|
2672
2802
|
const tasks = await loadTaskSessions({
|
|
2673
|
-
includeArchived: taskSessionsIncludeArchivedRef.current
|
|
2803
|
+
includeArchived: taskSessionsIncludeArchivedRef.current,
|
|
2804
|
+
...(normalizedQuery.trim() ? { query: normalizedQuery } : {})
|
|
2674
2805
|
});
|
|
2675
2806
|
if (taskSessionsLoadSequenceRef.current !== sequence) {
|
|
2676
2807
|
return;
|
|
@@ -3519,7 +3650,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
3519
3650
|
if (view === "workspace") {
|
|
3520
3651
|
return (_jsx(Box, { flexDirection: "column", height: terminalSize.rows, children: _jsx(WorkspacePicker, { cwd: cwd, choices: workspaceChoices, terminalHeight: terminalSize.rows, terminalWidth: terminalWidth, onCancel: closeWorkspacePicker, onSelect: (workspace) => void selectWorkspace(workspace) }) }));
|
|
3521
3652
|
}
|
|
3522
|
-
return (_jsx(AppShell, { view: view, cwd: cwd, taskId: activeTaskId, statusText: [visibleTaskStatus, visibleRouteSummary, configChange?.compact].filter(Boolean).join(" | "), contentHeight: contentHeight, showStatusBar: config.ui.showStatusBar, input: _jsx(InputBar, { mode: view === "worker" && workerSearch.open ? "worker-search" : view, ready: inputReady, busy: busy, routeFallback: Boolean(routeFallbackPrompt), collaborationDetail: collaborationDetailOpen, collaborationUnresolved: collaborationUnresolvedOnly, collaborationBack: collaborationReturnViewRef.current, featureCanCancel: featureCanCancel, featureCanPause: featureCanCancel, featureCanReassign: featureCanReassign, featureCancelConfirm: featureCancelPrompt?.action === "cancel", featurePauseConfirm: featureCancelPrompt?.action === "pause", featureAssignment: Boolean(featureAssignmentPrompt), featureEditingModel: featureAssignmentPrompt?.modelEdit ?? null, taskSessionAction: sessionCenterMode === "conversations"
|
|
3653
|
+
return (_jsx(AppShell, { view: view, cwd: cwd, taskId: activeTaskId, busy: busy, detachable: backgroundRunAttached, controllable: backgroundRunControllable, statusText: [visibleTaskStatus, visibleRouteSummary, configChange?.compact].filter(Boolean).join(" | "), contentHeight: contentHeight, showStatusBar: config.ui.showStatusBar, input: _jsx(InputBar, { mode: view === "worker" && workerSearch.open ? "worker-search" : view, ready: inputReady, busy: busy, busyDetachable: backgroundRunAttached, busyControllable: backgroundRunControllable, routeFallback: Boolean(routeFallbackPrompt), collaborationDetail: collaborationDetailOpen, collaborationUnresolved: collaborationUnresolvedOnly, collaborationBack: collaborationReturnViewRef.current, featureCanCancel: featureCanCancel, featureCanPause: featureCanCancel, featureCanReassign: featureCanReassign, featureCancelConfirm: featureCancelPrompt?.action === "cancel", featurePauseConfirm: featureCancelPrompt?.action === "pause", featureAssignment: Boolean(featureAssignmentPrompt), featureEditingModel: featureAssignmentPrompt?.modelEdit ?? null, taskSessionAction: sessionCenterMode === "conversations"
|
|
3523
3654
|
? mainConversationAction?.type === "rename"
|
|
3524
3655
|
? { type: "rename", value: mainConversationAction.value, cursor: mainConversationAction.cursor }
|
|
3525
3656
|
: mainConversationAction?.type === "delete"
|
|
@@ -3529,9 +3660,11 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
3529
3660
|
? { type: "rename", value: taskSessionAction.value, cursor: taskSessionAction.cursor }
|
|
3530
3661
|
: taskSessionAction?.type === "delete"
|
|
3531
3662
|
? { type: "delete", title: taskSessionAction.title }
|
|
3532
|
-
:
|
|
3663
|
+
: taskSessionAction?.type === "search"
|
|
3664
|
+
? { type: "search", value: taskSessionAction.value, cursor: taskSessionAction.cursor }
|
|
3665
|
+
: null, taskSessionsIncludeArchived: sessionCenterMode === "conversations"
|
|
3533
3666
|
? mainConversationsIncludeArchived
|
|
3534
|
-
: taskSessionsIncludeArchived, mainConversationSessions: sessionCenterMode === "conversations" && !taskSessionDetails, taskSessionDetail: Boolean(taskSessionDetails), taskSessionDetailHasNative: taskSessionDetailHasNative, taskSessionDetailCanFork: taskSessionDetailCanFork, canRetry: canRetryTask, hasWorkers: workers.length > 0, hasActiveTask: Boolean(activeTaskId), hasTaskResult: hasTaskResult, taskResultExpanded: taskResultExpanded, chatScrollOffset: chatScrollOffset, chatMaxScrollOffset: chatMaxScrollOffset, nativeClosed: view === "native" && nativeAttach?.closedCode !== null, searchMatchIndex: workerSearch.matchIndex, searchMatchCount: workerNavigationTargets.searchOffsets.length, clipboardNotice: clipboardNotice, roleScope: roleConfigurationScope, roleEditingModel: roleModelEdit, roleCanApply: roleConfigurationScope !== "task" || Boolean(activeTaskId), roleSaving: roleConfigurationSaving, roleHasOverride: roleConfigurationHasOverride, value: workerSearch.open && view === "worker"
|
|
3667
|
+
: taskSessionsIncludeArchived, taskSessionQuery: taskSessionQuery, mainConversationSessions: sessionCenterMode === "conversations" && !taskSessionDetails, taskSessionDetail: Boolean(taskSessionDetails), taskSessionDetailHasNative: taskSessionDetailHasNative, taskSessionDetailCanFork: taskSessionDetailCanFork, canRetry: canRetryTask, hasWorkers: workers.length > 0, hasActiveTask: Boolean(activeTaskId), hasTaskResult: hasTaskResult, taskResultExpanded: taskResultExpanded, chatScrollOffset: chatScrollOffset, chatMaxScrollOffset: chatMaxScrollOffset, nativeClosed: view === "native" && nativeAttach?.closedCode !== null, searchMatchIndex: workerSearch.matchIndex, searchMatchCount: workerNavigationTargets.searchOffsets.length, clipboardNotice: clipboardNotice, roleScope: roleConfigurationScope, roleEditingModel: roleModelEdit, roleCanApply: roleConfigurationScope !== "task" || Boolean(activeTaskId), roleSaving: roleConfigurationSaving, roleHasOverride: roleConfigurationHasOverride, value: workerSearch.open && view === "worker"
|
|
3535
3668
|
? workerSearch.query
|
|
3536
3669
|
: view === "native" || view === "router" || view === "workers" || view === "features" || view === "sessions" || view === "collaboration" || view === "status" || view === "roles" ? "" : input, cursor: workerSearch.open && view === "worker"
|
|
3537
3670
|
? workerSearch.cursor
|
|
@@ -3539,7 +3672,7 @@ export function App({ config, orchestrator, cwd, initialTaskId = null, initialRo
|
|
|
3539
3672
|
? { type: "rename", title: mainConversationAction.title }
|
|
3540
3673
|
: mainConversationAction?.type === "delete"
|
|
3541
3674
|
? { type: "delete", title: mainConversationAction.title }
|
|
3542
|
-
: null, loading: taskSessionsLoading, error: taskSessionsError, height: contentHeight, terminalWidth: terminalWidth })) : (_jsx(TaskSessionsView, { tasks: taskSessions, activeTaskId: activeTaskId, selectedIndex: selectedTaskSessionIndex, includeArchived: taskSessionsIncludeArchived, notice: taskSessionsNotice, action: taskSessionAction?.type === "rename"
|
|
3675
|
+
: null, loading: taskSessionsLoading, error: taskSessionsError, height: contentHeight, terminalWidth: terminalWidth })) : (_jsx(TaskSessionsView, { tasks: taskSessions, activeTaskId: activeTaskId, selectedIndex: selectedTaskSessionIndex, includeArchived: taskSessionsIncludeArchived, query: taskSessionQuery, notice: taskSessionsNotice, action: taskSessionAction?.type === "rename"
|
|
3543
3676
|
? { type: "rename", title: taskSessionAction.title }
|
|
3544
3677
|
: taskSessionAction?.type === "delete"
|
|
3545
3678
|
? { type: "delete", title: taskSessionAction.title }
|
package/dist/tui/AppShell.js
CHANGED
|
@@ -6,8 +6,8 @@ import { compactEndByDisplayWidth, displayWidth } from "./display-width.js";
|
|
|
6
6
|
import { TUI_THEME } from "./theme.js";
|
|
7
7
|
const APP_HEADER_ROOMY_SEPARATOR = " · ";
|
|
8
8
|
const APP_HEADER_COMPACT_SEPARATOR = " ";
|
|
9
|
-
export function AppShell({ view, cwd, taskId, statusText, contentHeight = 20, terminalWidth = process.stdout.columns || 120, showStatusBar = true, children, input, error = null }) {
|
|
10
|
-
const header = headerParts({ view, cwd, taskId, terminalWidth });
|
|
9
|
+
export function AppShell({ view, cwd, taskId, statusText, contentHeight = 20, terminalWidth = process.stdout.columns || 120, showStatusBar = true, busy = false, detachable = false, controllable = true, children, input, error = null }) {
|
|
10
|
+
const header = headerParts({ view, cwd, taskId, terminalWidth, busy, detachable, controllable });
|
|
11
11
|
const headerSegments = headerDisplaySegments(header);
|
|
12
12
|
const headerSeparatorText = headerSeparator(terminalWidth);
|
|
13
13
|
const headerLeadingWidth = terminalWidth > 1 ? 1 : 0;
|
|
@@ -186,7 +186,11 @@ function headerParts(input) {
|
|
|
186
186
|
view: nano ? "" : input.terminalWidth <= 24 && input.view === "native" ? "nat" : narrow ? shortViewLabel(input.view) : viewLabel(input.view),
|
|
187
187
|
task: showTask ? ultraNarrow ? ultraCompactTaskId(task) : narrow ? task : `#${task}` : "",
|
|
188
188
|
project: tiny || ultraNarrow ? "" : compactHeaderProject(input.cwd, veryNarrow ? 10 : narrow ? 16 : 40),
|
|
189
|
-
shortcut:
|
|
189
|
+
shortcut: input.busy && input.detachable
|
|
190
|
+
? input.controllable
|
|
191
|
+
? narrow ? "^C detach" : "Esc stop · ^C detach"
|
|
192
|
+
: narrow ? "^C detach" : "observe · ^C detach"
|
|
193
|
+
: narrow ? shortShortcutHint(input.view) : shortcutHint(input.view)
|
|
190
194
|
}, contentWidth, separator);
|
|
191
195
|
}
|
|
192
196
|
function fitHeaderParts(parts, contentWidth, separator) {
|
package/dist/tui/InputBar.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { compactEndByDisplayWidth, compactTailByDisplayWidth, displayWidth } from "./display-width.js";
|
|
4
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, featureEditingModel = null, taskSessionAction = null, taskSessionsIncludeArchived = false, mainConversationSessions = 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, clipboardNotice = null, roleScope = "next", roleEditingModel = null, roleCanApply = true, roleSaving = false, roleHasOverride = false, value, cursor, terminalWidth: providedTerminalWidth, onChange, onSubmit }) {
|
|
5
|
+
export function InputBar({ mode, ready = true, busy = false, busyDetachable = false, busyControllable = true, routeFallback = false, collaborationDetail = false, collaborationUnresolved = false, collaborationBack = "workers", featureCanCancel = false, featureCanPause = false, featureCanReassign = false, featureCancelConfirm = false, featurePauseConfirm = false, featureAssignment = false, featureEditingModel = null, taskSessionAction = null, taskSessionsIncludeArchived = false, taskSessionQuery = "", mainConversationSessions = 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, clipboardNotice = null, roleScope = "next", roleEditingModel = null, roleCanApply = true, roleSaving = false, roleHasOverride = false, value, cursor, terminalWidth: providedTerminalWidth, onChange, onSubmit }) {
|
|
6
6
|
const terminalWidth = providedTerminalWidth ?? process.stdout.columns ?? 120;
|
|
7
7
|
const fillRail = providedTerminalWidth !== undefined || typeof process.stdout.columns === "number";
|
|
8
8
|
if (clipboardNotice) {
|
|
@@ -42,6 +42,13 @@ export function InputBar({ mode, ready = true, busy = false, routeFallback = fal
|
|
|
42
42
|
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] }));
|
|
43
43
|
}
|
|
44
44
|
if (mode === "sessions") {
|
|
45
|
+
if (taskSessionAction?.type === "search") {
|
|
46
|
+
const prefix = terminalWidth < 12 ? "/ " : "find > ";
|
|
47
|
+
const valueWidth = Math.max(1, terminalWidth - displayWidth(prefix) - 3);
|
|
48
|
+
const display = chatInputDisplayParts(taskSessionAction.value, taskSessionAction.cursor, valueWidth);
|
|
49
|
+
const textWidth = displayWidth(`${prefix}${display.before}|${display.after}`);
|
|
50
|
+
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 })] }));
|
|
51
|
+
}
|
|
45
52
|
if (taskSessionAction?.type === "rename") {
|
|
46
53
|
const prefix = terminalWidth < 12 ? "> " : "rename > ";
|
|
47
54
|
const valueWidth = Math.max(1, terminalWidth - displayWidth(prefix) - 3);
|
|
@@ -61,7 +68,7 @@ export function InputBar({ mode, ready = true, busy = false, routeFallback = fal
|
|
|
61
68
|
const hints = mainConversationSessionsInputHints(terminalWidth, taskSessionsIncludeArchived);
|
|
62
69
|
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] }));
|
|
63
70
|
}
|
|
64
|
-
const hints = taskSessionsInputHints(terminalWidth, taskSessionsIncludeArchived);
|
|
71
|
+
const hints = taskSessionsInputHints(terminalWidth, taskSessionsIncludeArchived, Boolean(taskSessionQuery.trim()));
|
|
65
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] }));
|
|
66
73
|
}
|
|
67
74
|
if (mode === "collaboration") {
|
|
@@ -106,7 +113,7 @@ export function InputBar({ mode, ready = true, busy = false, routeFallback = fal
|
|
|
106
113
|
const hints = routeFallbackInputHints(terminalWidth);
|
|
107
114
|
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] }));
|
|
108
115
|
}
|
|
109
|
-
const busyText = chatBusyDisplayValue(terminalWidth);
|
|
116
|
+
const busyText = chatBusyDisplayValue(terminalWidth, busyDetachable, busyControllable);
|
|
110
117
|
const prompt = busy ? "run" : ">";
|
|
111
118
|
if (busy) {
|
|
112
119
|
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] }));
|
|
@@ -363,13 +370,19 @@ function selectChatPlaceholder(terminalWidth, candidates) {
|
|
|
363
370
|
function chatPlaceholderValueWidth(terminalWidth) {
|
|
364
371
|
return Math.max(1, terminalWidth - (terminalWidth >= 10 ? 6 : 4));
|
|
365
372
|
}
|
|
366
|
-
export function chatBusyDisplayValue(terminalWidth) {
|
|
373
|
+
export function chatBusyDisplayValue(terminalWidth, detachable = false, controllable = true) {
|
|
367
374
|
if (terminalWidth < 14) {
|
|
368
375
|
return "";
|
|
369
376
|
}
|
|
370
377
|
if (terminalWidth < 22) {
|
|
371
378
|
return "busy";
|
|
372
379
|
}
|
|
380
|
+
if (detachable && !controllable) {
|
|
381
|
+
return terminalWidth >= 34 ? "observing · ^C detach" : "^C detach";
|
|
382
|
+
}
|
|
383
|
+
if (terminalWidth >= 48 && detachable) {
|
|
384
|
+
return "working · Esc stop · ^C detach";
|
|
385
|
+
}
|
|
373
386
|
if (terminalWidth >= 34) {
|
|
374
387
|
return "working · Esc stop";
|
|
375
388
|
}
|
|
@@ -596,10 +609,11 @@ function collaborationDetailInputHints(width) {
|
|
|
596
609
|
{ label: "e", detail: "" }
|
|
597
610
|
]);
|
|
598
611
|
}
|
|
599
|
-
function taskSessionsInputHints(width, includeArchived) {
|
|
612
|
+
function taskSessionsInputHints(width, includeArchived, hasQuery) {
|
|
600
613
|
const archivedAction = includeArchived ? "H hide archived" : "H archived";
|
|
614
|
+
const searchAction = hasQuery ? "^F edit · X clear" : "^F find";
|
|
601
615
|
return selectInputHints(width, [
|
|
602
|
-
{ label: "sessions", detail: ` · Up/Dn select · Enter restore · C conversations · I inspect · R rename · A archive · D delete · E export · ${archivedAction} · Esc back` },
|
|
616
|
+
{ label: "sessions", detail: ` · Up/Dn select · Enter restore · C conversations · I inspect · R rename · A archive · D delete · E export · ${archivedAction} · Esc back · ${searchAction}` },
|
|
603
617
|
{ label: "sessions", detail: " · Up/Dn select · Enter restore · C conversations · I inspect · R rename · A archive · D delete · E export · Esc back" },
|
|
604
618
|
{ label: "sessions", detail: " · Up/Dn select · Enter restore · C chats · I inspect · R rename · A archive · D delete · Esc back" },
|
|
605
619
|
{ label: "sessions", detail: " · Up/Dn select · Enter restore · C chats · I inspect · R rename · A archive · Esc back" },
|