neoctl 0.2.10 → 0.2.12
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/dist/context/compaction.js +3 -3
- package/dist/context/compaction.js.map +1 -1
- package/dist/context/prompts.js +5 -1
- package/dist/context/prompts.js.map +1 -1
- package/dist/core/image-note-prompt.d.ts +8 -0
- package/dist/core/image-note-prompt.js +20 -0
- package/dist/core/image-note-prompt.js.map +1 -0
- package/dist/core/image-notes.d.ts +21 -0
- package/dist/core/image-notes.js +112 -0
- package/dist/core/image-notes.js.map +1 -0
- package/dist/core/image-registry.d.ts +5 -0
- package/dist/core/image-registry.js +41 -3
- package/dist/core/image-registry.js.map +1 -1
- package/dist/core/query-engine.js +6 -1
- package/dist/core/query-engine.js.map +1 -1
- package/dist/core/query.js +189 -1
- package/dist/core/query.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/model/anthropic-mapper.js +3 -1
- package/dist/model/anthropic-mapper.js.map +1 -1
- package/dist/model/openai-mappers.js +3 -1
- package/dist/model/openai-mappers.js.map +1 -1
- package/dist/repl/index.js +286 -264
- package/dist/repl/index.js.map +1 -1
- package/dist/tools/builtins/image-generation-tool.d.ts +3 -0
- package/dist/tools/builtins/image-generation-tool.js +63 -17
- package/dist/tools/builtins/image-generation-tool.js.map +1 -1
- package/dist/tools/builtins/image-loader-tool.d.ts +7 -0
- package/dist/tools/builtins/image-loader-tool.js +29 -1
- package/dist/tools/builtins/image-loader-tool.js.map +1 -1
- package/dist/tools/builtins/image-note-tool.d.ts +29 -0
- package/dist/tools/builtins/image-note-tool.js +179 -0
- package/dist/tools/builtins/image-note-tool.js.map +1 -0
- package/dist/tools/smoke-tool-system.js +4 -2
- package/dist/tools/smoke-tool-system.js.map +1 -1
- package/dist/web/html.js +8 -14
- package/dist/web/html.js.map +1 -1
- package/dist/web/index.d.ts +0 -5
- package/dist/web/index.js +7 -41
- package/dist/web/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/install-ripgrep.cjs +196 -196
- package/vendor/ripgrep/darwin-arm64/COPYING +3 -3
- package/vendor/ripgrep/darwin-arm64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/darwin-arm64/UNLICENSE +24 -24
- package/vendor/ripgrep/darwin-arm64/manifest.json +7 -7
- package/vendor/ripgrep/darwin-x64/COPYING +3 -3
- package/vendor/ripgrep/darwin-x64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/darwin-x64/UNLICENSE +24 -24
- package/vendor/ripgrep/darwin-x64/manifest.json +7 -7
- package/vendor/ripgrep/linux-arm64/COPYING +3 -3
- package/vendor/ripgrep/linux-arm64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/linux-arm64/UNLICENSE +24 -24
- package/vendor/ripgrep/linux-arm64/manifest.json +7 -7
- package/vendor/ripgrep/linux-x64/COPYING +3 -3
- package/vendor/ripgrep/linux-x64/LICENSE-MIT +21 -21
- package/vendor/ripgrep/linux-x64/UNLICENSE +24 -24
- package/vendor/ripgrep/linux-x64/manifest.json +7 -7
- package/vendor/ripgrep/win32-arm64/manifest.json +7 -7
- package/dist/tips.d.ts +0 -10
- package/dist/tips.js +0 -168
- package/dist/tips.js.map +0 -1
package/dist/repl/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import { searchTool } from "../tools/builtins/search-tool.js";
|
|
|
22
22
|
import { planTool } from "../tools/builtins/plan-tool.js";
|
|
23
23
|
import { createOpenAIImageGenerationTool } from "../tools/builtins/image-generation-tool.js";
|
|
24
24
|
import { createLoadImageTool } from "../tools/builtins/image-loader-tool.js";
|
|
25
|
+
import { createImageNoteTool } from "../tools/builtins/image-note-tool.js";
|
|
25
26
|
import { createSecretTools } from "../tools/builtins/secret-tools.js";
|
|
26
27
|
import { SecretStore } from "../secrets/secret-store.js";
|
|
27
28
|
import { InMemorySecretRedactionRegistry } from "../secrets/secret-redaction.js";
|
|
@@ -30,12 +31,11 @@ import { AgentActivityStore } from "../agents/agent-activity.js";
|
|
|
30
31
|
import { createTaskTools } from "../tasks/task-tools.js";
|
|
31
32
|
import { TaskStore } from "../tasks/task-store.js";
|
|
32
33
|
import { cliHelpText, isModelReasoningArgument, isValidReplCommandLine, parseCliReplCommandArgs, parseReplCommand, helpText, replCommandDefinitions } from "./commands.js";
|
|
33
|
-
import {
|
|
34
|
+
import { markdownRenderKey, MarkdownText } from "./markdown-renderer.js";
|
|
34
35
|
import { DefaultContextManager } from "../context/context-manager.js";
|
|
35
36
|
import { buildEffectiveSystemPrompt } from "../context/prompts.js";
|
|
36
37
|
import { writeSessionMarkdownExport } from "../session/session-export.js";
|
|
37
38
|
import { readClipboard } from "./clipboard.js";
|
|
38
|
-
import { formatTipLine, initialTipIndex, tipAt } from "../tips.js";
|
|
39
39
|
import { openDirectory } from "../open-directory.js";
|
|
40
40
|
import { runWebServer } from "../web/index.js";
|
|
41
41
|
import { getNeoctlHome } from "../paths.js";
|
|
@@ -258,6 +258,7 @@ async function createRuntime() {
|
|
|
258
258
|
tools.register(grepTool);
|
|
259
259
|
tools.register(searchTool);
|
|
260
260
|
tools.register(createLoadImageTool());
|
|
261
|
+
tools.register(createImageNoteTool());
|
|
261
262
|
if (modelConfig?.provider === "openai")
|
|
262
263
|
tools.register(createOpenAIImageGenerationTool());
|
|
263
264
|
tools.register(planTool);
|
|
@@ -523,15 +524,12 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
523
524
|
const activeAbortController = useRef(undefined);
|
|
524
525
|
const interruptArmed = useRef(false);
|
|
525
526
|
const history = useRef([]);
|
|
526
|
-
const toolLineIds = useRef(new Map());
|
|
527
|
-
const pendingToolResultTimers = useRef(new Map());
|
|
528
527
|
const [lines, setLines] = useState(() => initialLines(runtime, lineId));
|
|
529
528
|
const [input, setInput] = useState("");
|
|
530
529
|
const [queuedInput, setQueuedInput] = useState(undefined);
|
|
531
530
|
const queuedAttachmentsRef = useRef(undefined);
|
|
532
531
|
const [cursor, setCursor] = useState(0);
|
|
533
532
|
const [promptPlaceholder, setPromptPlaceholder] = useState(undefined);
|
|
534
|
-
const [tipIndex, setTipIndex] = useState(() => initialTipIndex(runtime.engine.snapshot().session?.sessionId ?? process.cwd()));
|
|
535
533
|
const [busy, setBusy] = useState(false);
|
|
536
534
|
const [status, setStatus] = useState(() => initialStatus(runtime));
|
|
537
535
|
const sessionTitleRef = useRef(sessionTerminalTitle(runtime.engine.snapshot().session));
|
|
@@ -720,11 +718,9 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
720
718
|
}, PASTE_STATUS_DISPLAY_MS);
|
|
721
719
|
pasteStatusTimerRef.current = timer;
|
|
722
720
|
};
|
|
723
|
-
const advanceTip = () => setTipIndex((current) => current + 1);
|
|
724
721
|
const insertAtCursor = (value) => {
|
|
725
722
|
const currentText = inputRef.current;
|
|
726
723
|
const currentCursor = cursorRef.current;
|
|
727
|
-
advanceTip();
|
|
728
724
|
setPromptState(`${currentText.slice(0, currentCursor)}${value}${currentText.slice(currentCursor)}`, currentCursor + value.length);
|
|
729
725
|
};
|
|
730
726
|
const insertAttachmentLabel = (attachment) => {
|
|
@@ -852,8 +848,6 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
852
848
|
assistantLineId.current = undefined;
|
|
853
849
|
thinkingLineId.current = undefined;
|
|
854
850
|
finalizedThinkingLineId.current = undefined;
|
|
855
|
-
toolLineIds.current.clear();
|
|
856
|
-
clearPendingToolResultTimers();
|
|
857
851
|
};
|
|
858
852
|
const resumeSnapshot = (snapshot, metrics) => {
|
|
859
853
|
resetForegroundView(metrics);
|
|
@@ -888,47 +882,15 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
888
882
|
finalizedThinkingLineId.current = id;
|
|
889
883
|
thinkingLineId.current = undefined;
|
|
890
884
|
};
|
|
891
|
-
const finalizeToolLine = (id) => {
|
|
892
|
-
if (id === undefined)
|
|
893
|
-
return;
|
|
894
|
-
setLines((current) => current.map((line) => line.id === id ? { ...line, live: false, pendingReplacement: false } : line));
|
|
895
|
-
};
|
|
896
|
-
const cancelPendingToolResultTimer = (toolUseId) => {
|
|
897
|
-
const timer = pendingToolResultTimers.current.get(toolUseId);
|
|
898
|
-
if (timer === undefined)
|
|
899
|
-
return;
|
|
900
|
-
clearTimeout(timer);
|
|
901
|
-
pendingToolResultTimers.current.delete(toolUseId);
|
|
902
|
-
};
|
|
903
|
-
const scheduleToolResultReplacement = (toolUseId, lineId, line) => {
|
|
904
|
-
cancelPendingToolResultTimer(toolUseId);
|
|
905
|
-
const timer = setTimeout(() => {
|
|
906
|
-
pendingToolResultTimers.current.delete(toolUseId);
|
|
907
|
-
replaceLine(lineId, { ...line, pendingReplacement: false });
|
|
908
|
-
}, TOOL_RESULT_REPLACEMENT_DELAY_MS);
|
|
909
|
-
pendingToolResultTimers.current.set(toolUseId, timer);
|
|
910
|
-
};
|
|
911
|
-
const clearPendingToolResultTimers = () => {
|
|
912
|
-
for (const timer of pendingToolResultTimers.current.values())
|
|
913
|
-
clearTimeout(timer);
|
|
914
|
-
pendingToolResultTimers.current.clear();
|
|
915
|
-
};
|
|
916
885
|
useEffect(() => {
|
|
917
886
|
return () => {
|
|
918
|
-
clearPendingToolResultTimers();
|
|
919
887
|
if (pasteStatusTimerRef.current)
|
|
920
888
|
clearTimeout(pasteStatusTimerRef.current);
|
|
921
889
|
};
|
|
922
890
|
}, []);
|
|
923
|
-
const finalizeActiveToolLines = () => {
|
|
924
|
-
for (const id of toolLineIds.current.values())
|
|
925
|
-
finalizeToolLine(id);
|
|
926
|
-
toolLineIds.current.clear();
|
|
927
|
-
};
|
|
928
891
|
const finalizeForegroundView = () => {
|
|
929
892
|
finalizeLiveLine(assistantLineId.current);
|
|
930
893
|
finalizeThinkingLine();
|
|
931
|
-
finalizeActiveToolLines();
|
|
932
894
|
assistantLineId.current = undefined;
|
|
933
895
|
finalizedThinkingLineId.current = undefined;
|
|
934
896
|
};
|
|
@@ -938,22 +900,12 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
938
900
|
runtime.usage.add(event.usage);
|
|
939
901
|
if (event.type === "state")
|
|
940
902
|
return;
|
|
941
|
-
if (event.type === "context.metrics" ||
|
|
903
|
+
if (event.type === "context.metrics" ||
|
|
904
|
+
event.type === "usage" ||
|
|
905
|
+
event.type === "tool_call.delta" ||
|
|
906
|
+
event.type === "assistant.delta" ||
|
|
907
|
+
event.type === "thinking.delta")
|
|
942
908
|
return;
|
|
943
|
-
if (event.type === "assistant.delta") {
|
|
944
|
-
finalizeThinkingLine();
|
|
945
|
-
const id = assistantLineId.current ?? append({ kind: "assistant", text: "", live: true });
|
|
946
|
-
assistantLineId.current = id;
|
|
947
|
-
updateLine(id, (text) => text + event.text);
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
if (event.type === "thinking.delta") {
|
|
951
|
-
const id = thinkingLineId.current ?? finalizedThinkingLineId.current ?? append(thinkingLine("", true));
|
|
952
|
-
thinkingLineId.current = id;
|
|
953
|
-
finalizedThinkingLineId.current = undefined;
|
|
954
|
-
updateLine(id, (text) => text + event.text);
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
909
|
if (event.type === "message") {
|
|
958
910
|
let replacedStreamingContent = false;
|
|
959
911
|
if (event.message.role === "assistant" && assistantLineId.current !== undefined) {
|
|
@@ -979,7 +931,7 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
979
931
|
if (replacedStreamingContent)
|
|
980
932
|
return;
|
|
981
933
|
if (event.message.role === "tool_result") {
|
|
982
|
-
renderToolResultMessage(event.message, append
|
|
934
|
+
renderToolResultMessage(event.message, append);
|
|
983
935
|
return;
|
|
984
936
|
}
|
|
985
937
|
if (event.message.role !== "assistant") {
|
|
@@ -998,23 +950,15 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
998
950
|
if (event.type === "tool.started") {
|
|
999
951
|
finalizeLiveLine(assistantLineId.current);
|
|
1000
952
|
finalizeThinkingLine();
|
|
1001
|
-
const id = append({ ...formatToolUse(event.toolUse), live: true });
|
|
1002
|
-
toolLineIds.current.set(event.toolUse.id, id);
|
|
1003
953
|
return;
|
|
1004
954
|
}
|
|
1005
|
-
if (event.type === "tool.finished")
|
|
1006
|
-
const id = toolLineIds.current.get(event.toolUse.id);
|
|
1007
|
-
if (id !== undefined) {
|
|
1008
|
-
replaceLine(id, formatToolFinishedWithoutResult(event.toolUse, event.ok));
|
|
1009
|
-
}
|
|
955
|
+
if (event.type === "tool.finished")
|
|
1010
956
|
return;
|
|
1011
|
-
}
|
|
1012
957
|
if (event.type === "retrying")
|
|
1013
958
|
return;
|
|
1014
959
|
if (event.type === "terminal") {
|
|
1015
960
|
finalizeLiveLine(assistantLineId.current);
|
|
1016
961
|
finalizeThinkingLine();
|
|
1017
|
-
finalizeActiveToolLines();
|
|
1018
962
|
assistantLineId.current = undefined;
|
|
1019
963
|
return;
|
|
1020
964
|
}
|
|
@@ -1190,8 +1134,6 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1190
1134
|
assistantLineId.current = undefined;
|
|
1191
1135
|
thinkingLineId.current = undefined;
|
|
1192
1136
|
finalizedThinkingLineId.current = undefined;
|
|
1193
|
-
toolLineIds.current.clear();
|
|
1194
|
-
clearPendingToolResultTimers();
|
|
1195
1137
|
append(systemLine(snapshot ? `new session ${snapshot.sessionId}` : "new session"));
|
|
1196
1138
|
return;
|
|
1197
1139
|
}
|
|
@@ -1347,13 +1289,10 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1347
1289
|
}
|
|
1348
1290
|
};
|
|
1349
1291
|
useEffect(() => {
|
|
1350
|
-
setTipIndex(initialTipIndex(runtime.engine.snapshot().session?.sessionId ?? process.cwd()));
|
|
1351
1292
|
setLines(initialLines(runtime, lineId));
|
|
1352
1293
|
assistantLineId.current = undefined;
|
|
1353
1294
|
thinkingLineId.current = undefined;
|
|
1354
1295
|
finalizedThinkingLineId.current = undefined;
|
|
1355
|
-
toolLineIds.current.clear();
|
|
1356
|
-
clearPendingToolResultTimers();
|
|
1357
1296
|
setStatus(initialStatus(runtime));
|
|
1358
1297
|
setSessionsBrowser(undefined);
|
|
1359
1298
|
setSkillsBrowser(undefined);
|
|
@@ -1371,9 +1310,8 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1371
1310
|
const width = terminalSize.columns;
|
|
1372
1311
|
const inputLockedByQueue = busy && queuedInput !== undefined;
|
|
1373
1312
|
const prompt = promptPrefix(busy);
|
|
1374
|
-
const currentTip = tipAt(tipIndex);
|
|
1375
1313
|
const compactLiveLayout = terminalSize.rows <= COMPACT_LIVE_LAYOUT_ROWS && (agentActivities.length > 0 || backgroundTasks.length > 0 || busy);
|
|
1376
|
-
const activePlaceholder = input.length === 0 && !compactLiveLayout ? promptPlaceholder
|
|
1314
|
+
const activePlaceholder = input.length === 0 && !compactLiveLayout ? promptPlaceholder : undefined;
|
|
1377
1315
|
const promptDisplayText = input;
|
|
1378
1316
|
const promptDisplayCursor = cursor;
|
|
1379
1317
|
const promptLayoutText = activePlaceholder ? ` ${activePlaceholder}` : promptDisplayText;
|
|
@@ -1386,31 +1324,11 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1386
1324
|
if (selectedSlashCompletionIndex !== slashCompletionIndexRef.current) {
|
|
1387
1325
|
slashCompletionIndexRef.current = selectedSlashCompletionIndex;
|
|
1388
1326
|
}
|
|
1389
|
-
const promptHeight = promptTextView(promptLayoutText, promptLayoutCursor, width, prompt).length + slashCompletionViewHeight(slashCompletions) + (queuedInput !== undefined ? QUEUED_INPUT_RENDER_ROWS : 0) + (pasteStatus ? 1 : 0);
|
|
1390
1327
|
const firstDynamicLineIndex = lines.findIndex((line) => lineNeedsDynamicRender(line, messageContentWidth(width)));
|
|
1391
1328
|
const staticLines = firstDynamicLineIndex === -1 ? lines : lines.slice(0, firstDynamicLineIndex);
|
|
1392
1329
|
const dynamicLines = firstDynamicLineIndex === -1 ? [] : lines.slice(firstDynamicLineIndex);
|
|
1393
|
-
const
|
|
1330
|
+
const visibleDynamicLines = dynamicLines;
|
|
1394
1331
|
const nonAgentBackgroundTasks = backgroundTasks.filter((task) => task.type !== "agent");
|
|
1395
|
-
const statusRenderRows = STATUS_BAR_RENDER_ROWS + (showForegroundExecDetachHint && foregroundExecDetachHandle ? FOREGROUND_EXEC_DETACH_HINT_RENDER_ROWS : 0) + subagentRows + backgroundTaskStatusRenderRows(subagentRows > 0 ? nonAgentBackgroundTasks.length : backgroundTasks.length);
|
|
1396
|
-
const managementBrowserHeight = sessionsBrowser
|
|
1397
|
-
? sessionsBrowserViewHeight(sessionsBrowser)
|
|
1398
|
-
: skillsBrowser
|
|
1399
|
-
? skillsBrowserViewHeight(skillsBrowser)
|
|
1400
|
-
: secretsBrowser
|
|
1401
|
-
? secretsBrowserViewHeight(secretsBrowser)
|
|
1402
|
-
: 0;
|
|
1403
|
-
const loginFormHeight = loginForm ? loginFormViewHeight(loginForm) : 0;
|
|
1404
|
-
const maxDynamicBlocks = compactLiveLayout ? COMPACT_LIVE_DYNAMIC_BLOCKS : Number.POSITIVE_INFINITY;
|
|
1405
|
-
const visibleDynamicLines = dynamicLines.length > maxDynamicBlocks ? dynamicLines.slice(-maxDynamicBlocks) : dynamicLines;
|
|
1406
|
-
const visibleDynamicMarginOverhead = visibleDynamicLines.reduce((sum, _, i) => {
|
|
1407
|
-
const blockIndex = staticLines.length + i;
|
|
1408
|
-
return sum + (blockIndex > 0 ? MESSAGE_BLOCK_SPACING_LINES : 0);
|
|
1409
|
-
}, 0);
|
|
1410
|
-
const liveLineCount = Math.max(1, visibleDynamicLines.length);
|
|
1411
|
-
const reservedRows = promptHeight + statusRenderRows + managementBrowserHeight + loginFormHeight + visibleDynamicMarginOverhead + FULLSCREEN_RENDER_GUARD_ROWS;
|
|
1412
|
-
const dynamicRowsBudget = Math.max(MIN_LIVE_VIEWPORT_LINES, terminalSize.rows - reservedRows);
|
|
1413
|
-
const liveViewportLines = Math.max(MIN_LIVE_VIEWPORT_LINES, Math.floor(dynamicRowsBudget / liveLineCount));
|
|
1414
1332
|
useInput((value, key) => {
|
|
1415
1333
|
if (isTerminalFocusInSequence(value)) {
|
|
1416
1334
|
terminalFocusedRef.current = true;
|
|
@@ -1644,10 +1562,8 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1644
1562
|
if (key.backspace || key.delete) {
|
|
1645
1563
|
const currentText = inputRef.current;
|
|
1646
1564
|
const currentCursor = cursorRef.current;
|
|
1647
|
-
if (currentText.length === 0)
|
|
1648
|
-
setTipIndex((current) => current + 1);
|
|
1565
|
+
if (currentText.length === 0)
|
|
1649
1566
|
return;
|
|
1650
|
-
}
|
|
1651
1567
|
if (currentCursor > 0) {
|
|
1652
1568
|
setPromptState(`${currentText.slice(0, currentCursor - 1)}${currentText.slice(currentCursor)}`, currentCursor - 1);
|
|
1653
1569
|
}
|
|
@@ -1659,10 +1575,8 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1659
1575
|
setSlashCompletionSelection((slashCompletionIndexRef.current + completionCount - SLASH_COMPLETION_PAGE_SIZE) % completionCount);
|
|
1660
1576
|
return;
|
|
1661
1577
|
}
|
|
1662
|
-
if (inputRef.current.length === 0)
|
|
1663
|
-
setTipIndex((current) => current - 1);
|
|
1578
|
+
if (inputRef.current.length === 0)
|
|
1664
1579
|
return;
|
|
1665
|
-
}
|
|
1666
1580
|
setPromptState(inputRef.current, cursorRef.current - 1);
|
|
1667
1581
|
return;
|
|
1668
1582
|
}
|
|
@@ -1672,32 +1586,24 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1672
1586
|
setSlashCompletionSelection((slashCompletionIndexRef.current + SLASH_COMPLETION_PAGE_SIZE) % completionCount);
|
|
1673
1587
|
return;
|
|
1674
1588
|
}
|
|
1675
|
-
if (inputRef.current.length === 0)
|
|
1676
|
-
setTipIndex((current) => current + 1);
|
|
1589
|
+
if (inputRef.current.length === 0)
|
|
1677
1590
|
return;
|
|
1678
|
-
}
|
|
1679
1591
|
setPromptState(inputRef.current, cursorRef.current + 1);
|
|
1680
1592
|
return;
|
|
1681
1593
|
}
|
|
1682
1594
|
if (key.home) {
|
|
1683
|
-
if (inputRef.current.length
|
|
1684
|
-
setTipIndex(0);
|
|
1685
|
-
else
|
|
1595
|
+
if (inputRef.current.length > 0)
|
|
1686
1596
|
setPromptState(inputRef.current, 0);
|
|
1687
1597
|
return;
|
|
1688
1598
|
}
|
|
1689
1599
|
if (key.end) {
|
|
1690
|
-
if (inputRef.current.length
|
|
1691
|
-
setTipIndex((current) => current + 1);
|
|
1692
|
-
else
|
|
1600
|
+
if (inputRef.current.length > 0)
|
|
1693
1601
|
setPromptState(inputRef.current, inputRef.current.length);
|
|
1694
1602
|
return;
|
|
1695
1603
|
}
|
|
1696
1604
|
if (key.upArrow) {
|
|
1697
|
-
if (inputRef.current.length === 0 && history.current.length === 0)
|
|
1698
|
-
setTipIndex((current) => current - 1);
|
|
1605
|
+
if (inputRef.current.length === 0 && history.current.length === 0)
|
|
1699
1606
|
return;
|
|
1700
|
-
}
|
|
1701
1607
|
const completionCount = slashCompletionSelectableCount(inputRef.current, cursorRef.current, skillCompletions, secretCompletions);
|
|
1702
1608
|
if (completionCount > 0) {
|
|
1703
1609
|
setSlashCompletionSelection((slashCompletionIndexRef.current + completionCount - 1) % completionCount);
|
|
@@ -1711,10 +1617,8 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1711
1617
|
return;
|
|
1712
1618
|
}
|
|
1713
1619
|
if (key.downArrow) {
|
|
1714
|
-
if (inputRef.current.length === 0 && historyIndexRef.current === undefined)
|
|
1715
|
-
setTipIndex((current) => current + 1);
|
|
1620
|
+
if (inputRef.current.length === 0 && historyIndexRef.current === undefined)
|
|
1716
1621
|
return;
|
|
1717
|
-
}
|
|
1718
1622
|
const completionCount = slashCompletionSelectableCount(inputRef.current, cursorRef.current, skillCompletions, secretCompletions);
|
|
1719
1623
|
if (completionCount > 0) {
|
|
1720
1624
|
setSlashCompletionSelection((slashCompletionIndexRef.current + 1) % completionCount);
|
|
@@ -1736,10 +1640,8 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1736
1640
|
}
|
|
1737
1641
|
if (key.tab) {
|
|
1738
1642
|
const currentText = inputRef.current;
|
|
1739
|
-
if (currentText.length === 0)
|
|
1740
|
-
setTipIndex((current) => current + 1);
|
|
1643
|
+
if (currentText.length === 0)
|
|
1741
1644
|
return;
|
|
1742
|
-
}
|
|
1743
1645
|
const currentCursor = cursorRef.current;
|
|
1744
1646
|
const completions = slashCommandCompletions(currentText, currentCursor, skillCompletions, secretCompletions);
|
|
1745
1647
|
const completion = completions[Math.min(slashCompletionIndexRef.current, completions.length - 1)];
|
|
@@ -1754,9 +1656,9 @@ function InkRepl({ runtime, initialCommandLine }) {
|
|
|
1754
1656
|
return;
|
|
1755
1657
|
}
|
|
1756
1658
|
});
|
|
1757
|
-
return e(Box, { flexDirection: "column" }, e((Static), { items: staticLines, children: (line, index) => e(MessageBlock, { key: line.id, line, width, blockIndex: index }) }), e(MessageList, { lines: visibleDynamicLines, width,
|
|
1659
|
+
return e(Box, { flexDirection: "column" }, e((Static), { items: staticLines, children: (line, index) => e(MessageBlock, { key: line.id, line, width, blockIndex: index }) }), e(MessageList, { lines: visibleDynamicLines, width, lineIndexOffset: staticLines.length, onMarkdownRenderComplete: markLineRendered }), sessionsBrowser ? e(SessionsBrowser, { state: sessionsBrowser, width }) : null, skillsBrowser ? e(SkillsBrowser, { state: skillsBrowser, width }) : null, secretsBrowser ? e(SecretsBrowser, { state: secretsBrowser, width }) : null, loginForm ? e(LoginFormView, { state: loginForm, width }) : null, e(StatusBar, { status, animationTick, width }), showForegroundExecDetachHint && foregroundExecDetachHandle ? e(ForegroundExecDetachHintLine, { handle: foregroundExecDetachHandle, width }) : null, agentActivities.length > 0 ? e(SubagentLivePanel, { activities: agentActivities, width, terminalRows: terminalSize.rows, compact: compactLiveLayout, animationTick }) : null, agentActivities.length === 0 && backgroundTasks.length > 0 ? e(BackgroundTaskStatusLine, { tasks: backgroundTasks, width }) : null, agentActivities.length > 0 && nonAgentBackgroundTasks.length > 0 ? e(BackgroundTaskStatusLine, { tasks: nonAgentBackgroundTasks, width }) : null, pasteStatus ? e(PasteStatusLine, { text: pasteStatus, width }) : null, queuedInput !== undefined ? e(QueuedInputLine, { text: queuedInput, width }) : null, e(PromptLine, { text: promptDisplayText, cursor: promptDisplayCursor, busy, locked: inputLockedByQueue, placeholder: input.length === 0 && promptPlaceholder !== undefined, ghostText: activePlaceholder, width, prompt, slashCompletions, selectedSlashCompletionIndex, attachments }));
|
|
1758
1660
|
}
|
|
1759
|
-
const MessageList = React.memo(function MessageList({ lines, width,
|
|
1661
|
+
const MessageList = React.memo(function MessageList({ lines, width, lineIndexOffset = 0, onMarkdownRenderComplete }) {
|
|
1760
1662
|
const contentWidth = messageContentWidth(width);
|
|
1761
1663
|
const toolWidth = toolContentWidth(width);
|
|
1762
1664
|
return e(Box, { flexDirection: "column" }, ...lines.map((line, index) => e(MessageBlock, {
|
|
@@ -1766,51 +1668,30 @@ const MessageList = React.memo(function MessageList({ lines, width, liveMaxLines
|
|
|
1766
1668
|
blockIndex: lineIndexOffset + index,
|
|
1767
1669
|
contentWidth,
|
|
1768
1670
|
toolWidth,
|
|
1769
|
-
liveMaxLines,
|
|
1770
1671
|
onMarkdownRenderComplete,
|
|
1771
1672
|
})));
|
|
1772
1673
|
});
|
|
1773
|
-
function MessageBlock({ line, width, blockIndex, contentWidth, toolWidth,
|
|
1774
|
-
return e(Box, { flexDirection: "column", marginTop: blockIndex > 0 ? MESSAGE_BLOCK_SPACING_LINES : 0 }, e(MessageLine, { line, width, contentWidth, toolWidth,
|
|
1674
|
+
function MessageBlock({ line, width, blockIndex, contentWidth, toolWidth, onMarkdownRenderComplete }) {
|
|
1675
|
+
return e(Box, { flexDirection: "column", marginTop: blockIndex > 0 ? MESSAGE_BLOCK_SPACING_LINES : 0 }, e(MessageLine, { line, width, contentWidth, toolWidth, onMarkdownRenderComplete }));
|
|
1775
1676
|
}
|
|
1776
|
-
function MessageLine({ line, width, contentWidth = messageContentWidth(width), toolWidth = toolContentWidth(width),
|
|
1677
|
+
function MessageLine({ line, width, contentWidth = messageContentWidth(width), toolWidth = toolContentWidth(width), onMarkdownRenderComplete }) {
|
|
1777
1678
|
if (line.previewStyle === "summary") {
|
|
1778
1679
|
const useRoleMarker = summaryUsesRoleMarker(line);
|
|
1779
1680
|
const summaryWidth = useRoleMarker ? contentWidth : toolWidth;
|
|
1780
|
-
|
|
1781
|
-
return e(Box, { flexDirection: "row" }, useRoleMarker ? e(Text, { color: markerColorForKind(line.kind) }, messageRoleMarker(line.kind)) : null, e(Box, { flexDirection: "column", width: summaryWidth }, ...renderDisplayText(line, summaryWidth, display.maxLines, display.skipTop)));
|
|
1681
|
+
return e(Box, { flexDirection: "row" }, useRoleMarker ? e(Text, { color: markerColorForKind(line.kind) }, messageRoleMarker(line.kind)) : null, e(Box, { flexDirection: "column", width: summaryWidth }, ...renderDisplayText(line, summaryWidth)));
|
|
1782
1682
|
}
|
|
1783
1683
|
const useRoleMarker = !titleProvidesToolMarker(line);
|
|
1784
1684
|
const lineWidth = useRoleMarker ? contentWidth : toolWidth;
|
|
1785
|
-
const clipPendingMarkdown = !line.live && onMarkdownRenderComplete !== undefined && lineNeedsDynamicRender(line, lineWidth);
|
|
1786
|
-
const display = displayWindowForLine(line, lineWidth, line.live || clipPendingMarkdown ? liveMaxLines : undefined);
|
|
1787
1685
|
const contentNodes = [];
|
|
1788
1686
|
if (line.title)
|
|
1789
1687
|
contentNodes.push(renderBlockTitle(line));
|
|
1790
1688
|
if (line.bodyTitle)
|
|
1791
1689
|
contentNodes.push(e(Text, { key: `body-title-${line.id}`, bold: true }, line.bodyTitle));
|
|
1792
|
-
contentNodes.push(...renderDisplayText(line, lineWidth,
|
|
1690
|
+
contentNodes.push(...renderDisplayText(line, lineWidth, undefined, 0, onMarkdownRenderComplete));
|
|
1793
1691
|
return e(Box, { flexDirection: "row" }, useRoleMarker ? e(Text, { color: markerColorForKind(line.kind) }, messageRoleMarker(line.kind)) : null, e(Box, { flexDirection: "column", width: lineWidth }, ...contentNodes));
|
|
1794
1692
|
}
|
|
1795
|
-
function displayWindowForLine(line, width, maxLines) {
|
|
1796
|
-
if (maxLines === undefined)
|
|
1797
|
-
return { skipTop: 0 };
|
|
1798
|
-
const safeMaxLines = Math.max(1, maxLines);
|
|
1799
|
-
const lineCount = estimateRenderedLineCount(line, width);
|
|
1800
|
-
return {
|
|
1801
|
-
maxLines: safeMaxLines,
|
|
1802
|
-
skipTop: Math.max(0, lineCount - safeMaxLines),
|
|
1803
|
-
};
|
|
1804
|
-
}
|
|
1805
|
-
function estimateRenderedLineCount(line, width) {
|
|
1806
|
-
if (line.previewStyle === "summary")
|
|
1807
|
-
return renderSummaryLines(line, width).length;
|
|
1808
|
-
if (line.format === "ansi")
|
|
1809
|
-
return wrapAnsi(line.text, Math.max(10, width), { hard: true, trim: false }).split("\n").length;
|
|
1810
|
-
return estimateMarkdownLineCount(line.text, width);
|
|
1811
|
-
}
|
|
1812
1693
|
function lineNeedsDynamicRender(line, width) {
|
|
1813
|
-
if (line.live
|
|
1694
|
+
if (line.live)
|
|
1814
1695
|
return true;
|
|
1815
1696
|
if (line.previewStyle === "summary" || line.format === "ansi")
|
|
1816
1697
|
return false;
|
|
@@ -1861,10 +1742,10 @@ function summaryUsesRoleMarker(line) {
|
|
|
1861
1742
|
return line.previewStyle === "summary" && (line.kind === "system" || line.kind === "meta");
|
|
1862
1743
|
}
|
|
1863
1744
|
function titleProvidesToolMarker(line) {
|
|
1864
|
-
return line.kind === "tool" && !!line.title
|
|
1745
|
+
return line.kind === "tool" && !!line.title;
|
|
1865
1746
|
}
|
|
1866
1747
|
function titleStatusMarker(status) {
|
|
1867
|
-
return status === "success" ? "
|
|
1748
|
+
return status === "success" ? "\u2713" : "\u2717";
|
|
1868
1749
|
}
|
|
1869
1750
|
function titleStatusColor(status) {
|
|
1870
1751
|
return status === "success" ? "green" : "red";
|
|
@@ -1894,7 +1775,7 @@ function renderSummaryBlock(line, width, maxLines, skipTop = 0) {
|
|
|
1894
1775
|
}
|
|
1895
1776
|
if (line.format === "ansi") {
|
|
1896
1777
|
const baseStyle = detail
|
|
1897
|
-
? {
|
|
1778
|
+
? {}
|
|
1898
1779
|
: { color: colorForKind(line.kind), bold: true };
|
|
1899
1780
|
return e(Text, { key: `summary-${line.id}-${index}` }, ...renderAnsiInline(text, baseStyle));
|
|
1900
1781
|
}
|
|
@@ -2127,7 +2008,7 @@ function SubagentLivePanel({ activities, width: terminalWidth, terminalRows, com
|
|
|
2127
2008
|
if (!selected)
|
|
2128
2009
|
return null;
|
|
2129
2010
|
const activeCount = activities.filter((activity) => activity.status === "running" || activity.status === "pending").length;
|
|
2130
|
-
const header =
|
|
2011
|
+
const header = `◆ subagents: ${activeCount} active${activities.length > activeCount ? ` · ${activities.length - activeCount} recent` : ""}`;
|
|
2131
2012
|
if (rows <= 1) {
|
|
2132
2013
|
return e(Text, { color: "yellow" }, fitToWidth(`${header} · ${compactAgentSummary(selected, width - header.length - 3)}`, width));
|
|
2133
2014
|
}
|
|
@@ -2242,7 +2123,7 @@ function spinnerFrame(tick) {
|
|
|
2242
2123
|
}
|
|
2243
2124
|
function BackgroundTaskStatusLine({ tasks, width: terminalWidth }) {
|
|
2244
2125
|
const width = statusBarWidth(terminalWidth);
|
|
2245
|
-
const summary =
|
|
2126
|
+
const summary = `◆ background tools: ${tasks.length} task${tasks.length === 1 ? "" : "s"}`;
|
|
2246
2127
|
const detailTasks = tasks.slice(0, 2);
|
|
2247
2128
|
return e(Box, { flexDirection: "column", width, overflow: "hidden" }, e(Text, { color: "yellow" }, fitToWidth(summary, width)), ...detailTasks.map((task, index) => e(Text, { key: `bg-task-${task.taskId}-${index}`, color: "yellow" }, fitToWidth(` ${task.type}:${truncateMiddle(task.description || task.agentId || task.taskId, Math.max(12, width - 30))} · ${task.status} · ${formatElapsed(Date.now() - new Date(task.createdAt).getTime())}`, width))));
|
|
2248
2129
|
}
|
|
@@ -3034,27 +2915,12 @@ function renderMessage(message, append, activeAssistantId, options = {}) {
|
|
|
3034
2915
|
}
|
|
3035
2916
|
return rendered;
|
|
3036
2917
|
}
|
|
3037
|
-
function renderToolResultMessage(message, append
|
|
2918
|
+
function renderToolResultMessage(message, append) {
|
|
3038
2919
|
let rendered = false;
|
|
3039
2920
|
for (const block of message.blocks) {
|
|
3040
2921
|
if (block.type !== "tool_result")
|
|
3041
2922
|
continue;
|
|
3042
|
-
|
|
3043
|
-
const id = activeToolLineIds.get(block.toolUseId);
|
|
3044
|
-
if (id === undefined) {
|
|
3045
|
-
append(line);
|
|
3046
|
-
}
|
|
3047
|
-
else {
|
|
3048
|
-
replaceLine(id, {
|
|
3049
|
-
kind: line.kind,
|
|
3050
|
-
title: toolTitle(block.name, "finished"),
|
|
3051
|
-
titleStatus: block.ok ? "success" : "failure",
|
|
3052
|
-
live: true,
|
|
3053
|
-
pendingReplacement: true,
|
|
3054
|
-
});
|
|
3055
|
-
activeToolLineIds.delete(block.toolUseId);
|
|
3056
|
-
scheduleReplacement(block.toolUseId, id, line);
|
|
3057
|
-
}
|
|
2923
|
+
append(formatToolResultLine(block.name, block.output, block.ok));
|
|
3058
2924
|
rendered = true;
|
|
3059
2925
|
}
|
|
3060
2926
|
return rendered;
|
|
@@ -3243,13 +3109,7 @@ async function handleDeleteSessionCommand(sessionId, current, runtime, setBrowse
|
|
|
3243
3109
|
}
|
|
3244
3110
|
}
|
|
3245
3111
|
function initialLines(runtime, lineId) {
|
|
3246
|
-
const
|
|
3247
|
-
const suffix = session
|
|
3248
|
-
? ` Session: ${session.sessionId}${session.resumedMessages > 0 ? ` (${session.resumedMessages} resumed messages)` : ""}.`
|
|
3249
|
-
: "";
|
|
3250
|
-
const lines = [
|
|
3251
|
-
{ id: 0, kind: "system", title: "System", text: `Interactive UI enabled. Type /help for commands.${suffix}\n${formatTipLine(tipAt(initialTipIndex(session?.sessionId ?? process.cwd())))}`, previewStyle: "summary" },
|
|
3252
|
-
];
|
|
3112
|
+
const lines = [];
|
|
3253
3113
|
lineId.current = 0;
|
|
3254
3114
|
if (runtime.envNotice)
|
|
3255
3115
|
lines.push({ id: ++lineId.current, kind: "system", title: "Config", text: runtime.envNotice, format: "plain", previewStyle: "summary" });
|
|
@@ -3891,7 +3751,7 @@ function formatToolUse(toolUse) {
|
|
|
3891
3751
|
if (toolUse.name === "plan" && isPlanToolPayload(toolUse.input)) {
|
|
3892
3752
|
return {
|
|
3893
3753
|
kind: "tool",
|
|
3894
|
-
title: toolTitle(toolUse.name
|
|
3754
|
+
title: toolTitle(toolUse.name),
|
|
3895
3755
|
bodyTitle: planToolBodyTitle(toolUse.input),
|
|
3896
3756
|
text: formatPlanToolPayload(toolUse.input),
|
|
3897
3757
|
};
|
|
@@ -3899,7 +3759,7 @@ function formatToolUse(toolUse) {
|
|
|
3899
3759
|
const description = toolUse.name === "exec" ? execDescriptionFromInput(toolUse.input) : undefined;
|
|
3900
3760
|
return {
|
|
3901
3761
|
kind: "tool",
|
|
3902
|
-
title: toolTitle(toolUse.name
|
|
3762
|
+
title: toolTitle(toolUse.name),
|
|
3903
3763
|
bodyTitle: description,
|
|
3904
3764
|
text: formatJson(toolUse.input, 1200),
|
|
3905
3765
|
previewStyle: "summary",
|
|
@@ -3909,7 +3769,7 @@ function formatToolResultLine(toolName, output, ok) {
|
|
|
3909
3769
|
const formatted = formatToolResult(toolName, output, ok);
|
|
3910
3770
|
const line = {
|
|
3911
3771
|
kind: ok ? "tool" : "error",
|
|
3912
|
-
title: toolTitle(toolName
|
|
3772
|
+
title: toolTitle(toolName),
|
|
3913
3773
|
bodyTitle: formatted.bodyTitle,
|
|
3914
3774
|
titleStatus: ok ? "success" : "failure",
|
|
3915
3775
|
text: formatted.text,
|
|
@@ -3925,24 +3785,39 @@ function formatToolResultLine(toolName, output, ok) {
|
|
|
3925
3785
|
}
|
|
3926
3786
|
return line;
|
|
3927
3787
|
}
|
|
3928
|
-
function
|
|
3929
|
-
const inputText = formatJson(toolUse.input, 1200);
|
|
3930
|
-
const description = toolUse.name === "exec" ? execDescriptionFromInput(toolUse.input) : undefined;
|
|
3931
|
-
return {
|
|
3932
|
-
kind: ok ? "tool" : "error",
|
|
3933
|
-
title: toolTitle(toolUse.name, "finished"),
|
|
3934
|
-
bodyTitle: description,
|
|
3935
|
-
titleStatus: ok ? "success" : "failure",
|
|
3936
|
-
text: inputText ? `${ok ? "finished" : "failed"}\n${inputText}` : ok ? "finished" : "failed",
|
|
3937
|
-
previewStyle: "summary",
|
|
3938
|
-
live: true,
|
|
3939
|
-
pendingReplacement: true,
|
|
3940
|
-
};
|
|
3941
|
-
}
|
|
3942
|
-
function toolTitle(toolName, phase) {
|
|
3788
|
+
function toolTitle(toolName) {
|
|
3943
3789
|
if (toolName === "plan")
|
|
3944
|
-
return
|
|
3945
|
-
|
|
3790
|
+
return "\u25c6 plan";
|
|
3791
|
+
const labels = {
|
|
3792
|
+
exec: "command",
|
|
3793
|
+
read: "file read",
|
|
3794
|
+
list: "directory listing",
|
|
3795
|
+
grep: "search",
|
|
3796
|
+
edit: "file edit",
|
|
3797
|
+
write: "file write",
|
|
3798
|
+
search: "web search",
|
|
3799
|
+
plan: "plan",
|
|
3800
|
+
agent: "subagent",
|
|
3801
|
+
load_image: "image load",
|
|
3802
|
+
image_note: "image note",
|
|
3803
|
+
image2: "image generation",
|
|
3804
|
+
secret_list: "secret list",
|
|
3805
|
+
secret_info: "secret info",
|
|
3806
|
+
secret_request: "secret request",
|
|
3807
|
+
skill: "skill",
|
|
3808
|
+
skill_list: "skill list",
|
|
3809
|
+
skill_read: "skill read",
|
|
3810
|
+
skill_validate: "skill validation",
|
|
3811
|
+
skill_create: "skill create",
|
|
3812
|
+
skill_update: "skill update",
|
|
3813
|
+
TaskList: "task list",
|
|
3814
|
+
TaskGet: "task detail",
|
|
3815
|
+
TaskOutput: "task output",
|
|
3816
|
+
TaskStop: "task stop",
|
|
3817
|
+
TaskResume: "task resume",
|
|
3818
|
+
SendMessage: "task message",
|
|
3819
|
+
};
|
|
3820
|
+
return `\u25c6 ${labels[toolName] ?? `tool: ${toolName}`}`;
|
|
3946
3821
|
}
|
|
3947
3822
|
function execDescriptionFromInput(input) {
|
|
3948
3823
|
if (!isRecord(input))
|
|
@@ -3991,10 +3866,10 @@ function formatPlanItem(item, depth = 0) {
|
|
|
3991
3866
|
}
|
|
3992
3867
|
function planItemMarker(status) {
|
|
3993
3868
|
if (status === "completed")
|
|
3994
|
-
return "
|
|
3869
|
+
return "\u2713";
|
|
3995
3870
|
if (status === "in_progress")
|
|
3996
|
-
return "
|
|
3997
|
-
return "
|
|
3871
|
+
return "\u25b6";
|
|
3872
|
+
return "\u25cb";
|
|
3998
3873
|
}
|
|
3999
3874
|
function escapePlanMarkdown(text) {
|
|
4000
3875
|
return text.replace(/([\\`*_{}[\]()#+.!|>~-])/g, "\\$1");
|
|
@@ -4078,24 +3953,109 @@ function formatToolResult(toolName, output, ok) {
|
|
|
4078
3953
|
return { text: output, format: "ansi" };
|
|
4079
3954
|
}
|
|
4080
3955
|
if (toolName === "list" && isRecord(output)) {
|
|
4081
|
-
return { text: formatListToolResult(output, ok) };
|
|
3956
|
+
return { text: formatListToolResult(output, ok), format: "ansi" };
|
|
4082
3957
|
}
|
|
4083
3958
|
if (toolName === "read" && isRecord(output)) {
|
|
4084
|
-
return { text: formatReadToolResult(output, ok) };
|
|
3959
|
+
return { text: formatReadToolResult(output, ok), format: "ansi" };
|
|
4085
3960
|
}
|
|
4086
3961
|
if (toolName === "grep" && isRecord(output)) {
|
|
4087
|
-
return { text: formatGrepToolResult(output, ok) };
|
|
3962
|
+
return { text: formatGrepToolResult(output, ok), format: "ansi" };
|
|
4088
3963
|
}
|
|
4089
3964
|
if (toolName === "search" && isRecord(output)) {
|
|
4090
3965
|
return { text: formatWebSearchToolResult(output, ok), summaryMaxLines: EXPANDED_SUMMARY_MAX_LINES };
|
|
4091
3966
|
}
|
|
4092
3967
|
if (toolName === "image2" && isRecord(output)) {
|
|
4093
|
-
return { text: formatImageGenerationToolResult(output, ok), summaryMaxLines:
|
|
3968
|
+
return { text: formatImageGenerationToolResult(output, ok), format: "ansi", summaryMaxLines: 8 };
|
|
3969
|
+
}
|
|
3970
|
+
if (toolName === "image_note" && isRecord(output)) {
|
|
3971
|
+
return { text: formatImageNoteToolResult(output, ok), format: "ansi", summaryMaxLines: 16 };
|
|
4094
3972
|
}
|
|
4095
3973
|
if (toolName === "plan" && isPlanToolPayload(output)) {
|
|
4096
3974
|
return { text: formatPlanToolPayload(output), bodyTitle: planToolBodyTitle(output), full: true };
|
|
4097
3975
|
}
|
|
4098
|
-
return { text:
|
|
3976
|
+
return { text: formatGenericToolResult(output, ok), format: "ansi", summaryMaxLines: FALLBACK_PREVIEW_LINES };
|
|
3977
|
+
}
|
|
3978
|
+
function formatGenericToolResult(output, ok) {
|
|
3979
|
+
if (typeof output === "string")
|
|
3980
|
+
return previewGenericString(output);
|
|
3981
|
+
if (!isRecord(output))
|
|
3982
|
+
return `${ok ? "completed" : "failed"}\n${formatReplData(output, 1200)}`;
|
|
3983
|
+
const error = typeof output.error === "string" ? output.error : undefined;
|
|
3984
|
+
if (error)
|
|
3985
|
+
return ["failed", error].join("\n");
|
|
3986
|
+
const status = typeof output.status === "string" ? output.status : undefined;
|
|
3987
|
+
const lines = [status ? `${ok ? "completed" : "failed"}: ${status}` : ok ? "completed" : "failed"];
|
|
3988
|
+
const entries = Object.entries(output)
|
|
3989
|
+
.filter(([key, value]) => value !== undefined && !LOW_VALUE_FALLBACK_FIELDS.has(key))
|
|
3990
|
+
.slice(0, 24);
|
|
3991
|
+
for (const [key, value] of entries) {
|
|
3992
|
+
if (key === "status")
|
|
3993
|
+
continue;
|
|
3994
|
+
const label = formatFallbackLabel(key);
|
|
3995
|
+
if (isReplScalar(value))
|
|
3996
|
+
lines.push(`${dimAnsi(label)} ${formatReplValue(value)}`);
|
|
3997
|
+
else
|
|
3998
|
+
lines.push(`${dimAnsi(label)} ${truncate(formatReplValue(value), 500)}`);
|
|
3999
|
+
}
|
|
4000
|
+
if (entries.length === 0 && !status)
|
|
4001
|
+
lines.push(dimAnsi("no additional details"));
|
|
4002
|
+
return lines.slice(0, FALLBACK_PREVIEW_LINES).join("\n");
|
|
4003
|
+
}
|
|
4004
|
+
function formatFallbackLabel(key) {
|
|
4005
|
+
const labels = {
|
|
4006
|
+
task_id: "task",
|
|
4007
|
+
taskId: "task",
|
|
4008
|
+
agent_id: "agent",
|
|
4009
|
+
agentId: "agent",
|
|
4010
|
+
output_file: "output file",
|
|
4011
|
+
outputFile: "output file",
|
|
4012
|
+
can_read_output_file: "output readable",
|
|
4013
|
+
returnedEntries: "entries shown",
|
|
4014
|
+
totalFiles: "files",
|
|
4015
|
+
totalDirectories: "directories",
|
|
4016
|
+
updated_at: "updated",
|
|
4017
|
+
created_at: "created",
|
|
4018
|
+
};
|
|
4019
|
+
return labels[key] ?? key.replace(/_/gu, " ");
|
|
4020
|
+
}
|
|
4021
|
+
function formatEditOperation(operation) {
|
|
4022
|
+
const normalized = operation.trim().toLowerCase();
|
|
4023
|
+
if (normalized === "created" || normalized === "create")
|
|
4024
|
+
return "file created";
|
|
4025
|
+
if (normalized === "written" || normalized === "write")
|
|
4026
|
+
return "file written";
|
|
4027
|
+
if (normalized === "deleted" || normalized === "delete")
|
|
4028
|
+
return "file deleted";
|
|
4029
|
+
return "file updated";
|
|
4030
|
+
}
|
|
4031
|
+
function previewTextLines(text, maxLines, label) {
|
|
4032
|
+
const lines = text.replace(/\r\n/g, "\n").split("\n");
|
|
4033
|
+
const preview = lines.slice(0, maxLines);
|
|
4034
|
+
if (lines.length <= maxLines)
|
|
4035
|
+
return preview;
|
|
4036
|
+
return [...preview, dimAnsi(`showing first ${maxLines} of ${lines.length} ${label} lines`)];
|
|
4037
|
+
}
|
|
4038
|
+
function previewGenericString(text) {
|
|
4039
|
+
return previewTextLines(text, FALLBACK_PREVIEW_LINES, "output").join("\n");
|
|
4040
|
+
}
|
|
4041
|
+
function formatCommandPreview(command) {
|
|
4042
|
+
const normalized = command.replace(/\r\n/g, "\n").trimEnd();
|
|
4043
|
+
const lines = normalized.split("\n");
|
|
4044
|
+
if (lines.length === 1 && stripAnsi(normalized).length <= EXEC_COMMAND_PREVIEW_CHARS)
|
|
4045
|
+
return [normalized];
|
|
4046
|
+
const firstLine = lines[0]?.trim() ?? "";
|
|
4047
|
+
const summary = lines.length > 1
|
|
4048
|
+
? `command omitted: ${lines.length} lines, ${normalized.length} chars`
|
|
4049
|
+
: `command omitted: ${normalized.length} chars`;
|
|
4050
|
+
const preview = firstLine ? truncate(firstLine, EXEC_COMMAND_PREVIEW_CHARS) : "(empty command)";
|
|
4051
|
+
return [dimAnsi(summary), preview];
|
|
4052
|
+
}
|
|
4053
|
+
function formatDuration(durationMs) {
|
|
4054
|
+
if (!Number.isFinite(durationMs))
|
|
4055
|
+
return "?ms";
|
|
4056
|
+
if (durationMs < 1000)
|
|
4057
|
+
return `${Math.max(0, Math.round(durationMs))}ms`;
|
|
4058
|
+
return `${Number((durationMs / 1000).toFixed(durationMs < 10_000 ? 1 : 0))}s`;
|
|
4099
4059
|
}
|
|
4100
4060
|
function isEditToolOutput(value) {
|
|
4101
4061
|
return (typeof value.path === "string" &&
|
|
@@ -4115,8 +4075,12 @@ function isEditPatchHunk(value) {
|
|
|
4115
4075
|
value.lines.every((line) => typeof line === "string"));
|
|
4116
4076
|
}
|
|
4117
4077
|
function formatEditToolDiff(output, ok) {
|
|
4078
|
+
const replacementText = output.replacements === 1 ? "1 replacement" : `${output.replacements} replacements`;
|
|
4079
|
+
const operation = ok ? formatEditOperation(output.operation) : "file edit failed";
|
|
4118
4080
|
const lines = [
|
|
4119
|
-
|
|
4081
|
+
operation,
|
|
4082
|
+
output.path,
|
|
4083
|
+
dimAnsi(replacementText),
|
|
4120
4084
|
`\x1b[2;31m--- ${output.path}\x1b[0m`,
|
|
4121
4085
|
`\x1b[2;32m+++ ${output.path}\x1b[0m`,
|
|
4122
4086
|
];
|
|
@@ -4190,20 +4154,19 @@ function formatExecToolResult(output, ok) {
|
|
|
4190
4154
|
: `exit ${output.exitCode ?? output.signal ?? "unknown"}`;
|
|
4191
4155
|
const description = typeof output.description === "string" ? output.description.trim() : "";
|
|
4192
4156
|
const lines = [
|
|
4193
|
-
"
|
|
4194
|
-
...(
|
|
4195
|
-
`status: ${status}`,
|
|
4196
|
-
`duration: ${output.durationMs}ms`,
|
|
4197
|
-
`command: ${output.command}`,
|
|
4157
|
+
`${ok && output.exitCode === 0 && !output.timedOut ? "command completed" : "command failed"}: ${status} in ${formatDuration(output.durationMs)}`,
|
|
4158
|
+
...formatCommandPreview(output.command),
|
|
4198
4159
|
];
|
|
4160
|
+
if (description)
|
|
4161
|
+
lines.push("", dimAnsi("purpose"), description);
|
|
4199
4162
|
const stdout = output.stdout.replace(/\s+$/u, "");
|
|
4200
4163
|
const stderr = output.stderr.replace(/\s+$/u, "");
|
|
4201
4164
|
if (stdout)
|
|
4202
|
-
lines.push("stdout
|
|
4165
|
+
lines.push("", dimAnsi("stdout"), ...previewTextLines(stdout, EXEC_STDOUT_PREVIEW_LINES, "stdout"));
|
|
4203
4166
|
if (stderr)
|
|
4204
|
-
lines.push("stderr
|
|
4167
|
+
lines.push("", dimAnsi("stderr"), ...previewTextLines(stderr, EXEC_STDERR_PREVIEW_LINES, "stderr"));
|
|
4205
4168
|
if (!stdout && !stderr)
|
|
4206
|
-
lines.push(
|
|
4169
|
+
lines.push("", dimAnsi("no output captured"));
|
|
4207
4170
|
return lines.join("\n");
|
|
4208
4171
|
}
|
|
4209
4172
|
function isRecord(value) {
|
|
@@ -4229,42 +4192,87 @@ function formatImageGenerationToolResult(output, ok) {
|
|
|
4229
4192
|
lines.push(`source images: ${sourceImages}`);
|
|
4230
4193
|
const duration = imageGenerationDuration(output);
|
|
4231
4194
|
if (duration !== undefined)
|
|
4232
|
-
lines.push(`duration: ${duration}ms`);
|
|
4195
|
+
lines.push(dimAnsi(`duration: ${duration}ms`));
|
|
4196
|
+
const prompt = typeof output.prompt === "string" ? output.prompt.trim() : "";
|
|
4197
|
+
if (prompt)
|
|
4198
|
+
lines.push("", dimAnsi("prompt"), ...previewTextLines(prompt, IMAGE_PROMPT_PREVIEW_LINES, "prompt"));
|
|
4233
4199
|
return lines.join("\n");
|
|
4234
4200
|
}
|
|
4201
|
+
function formatImageNoteToolResult(output, ok) {
|
|
4202
|
+
const failed = Array.isArray(output.failed) ? output.failed.filter(isImageNoteFailureLike) : [];
|
|
4203
|
+
const recorded = Array.isArray(output.recorded) ? output.recorded.filter(isImageNoteRecordLike) : [];
|
|
4204
|
+
const lines = [`${recorded.length} note${recorded.length === 1 ? "" : "s"} recorded`];
|
|
4205
|
+
for (const item of recorded.slice(0, IMAGE_NOTE_PREVIEW_COUNT)) {
|
|
4206
|
+
lines.push("", item.imageRef);
|
|
4207
|
+
const note = item.note;
|
|
4208
|
+
if (typeof note.caption === "string" && note.caption.trim())
|
|
4209
|
+
lines.push(`${dimAnsi("caption")} ${note.caption.trim()}`);
|
|
4210
|
+
if (typeof note.purpose === "string" && note.purpose.trim())
|
|
4211
|
+
lines.push(`${dimAnsi("purpose")} ${note.purpose.trim()}`);
|
|
4212
|
+
if (Array.isArray(note.detectedText) && note.detectedText.length > 0)
|
|
4213
|
+
lines.push(`${dimAnsi("text")} ${note.detectedText.filter((value) => typeof value === "string" && value.trim().length > 0).join("; ")}`);
|
|
4214
|
+
if (Array.isArray(note.tags) && note.tags.length > 0)
|
|
4215
|
+
lines.push(`${dimAnsi("tags")} ${note.tags.filter((value) => typeof value === "string" && value.trim().length > 0).join(", ")}`);
|
|
4216
|
+
if (typeof note.retention === "string")
|
|
4217
|
+
lines.push(`${dimAnsi("retention")} ${note.retention}${typeof note.ttlTurns === "number" ? `, ${note.ttlTurns} turns` : ""}`);
|
|
4218
|
+
}
|
|
4219
|
+
if (recorded.length > IMAGE_NOTE_PREVIEW_COUNT)
|
|
4220
|
+
lines.push(dimAnsi(`showing first ${IMAGE_NOTE_PREVIEW_COUNT} of ${recorded.length} notes`));
|
|
4221
|
+
if (!ok || failed.length > 0) {
|
|
4222
|
+
lines.push("", dimAnsi("failed"));
|
|
4223
|
+
for (const failure of failed.slice(0, 5))
|
|
4224
|
+
lines.push(`${failure.imageRef}: ${failure.error}`);
|
|
4225
|
+
if (failed.length > 5)
|
|
4226
|
+
lines.push(dimAnsi(`${failed.length - 5} more failures`));
|
|
4227
|
+
}
|
|
4228
|
+
return lines.join("\n");
|
|
4229
|
+
}
|
|
4230
|
+
function isImageNoteRecordLike(value) {
|
|
4231
|
+
return isRecord(value) && typeof value.imageRef === "string" && isRecord(value.note);
|
|
4232
|
+
}
|
|
4233
|
+
function isImageNoteFailureLike(value) {
|
|
4234
|
+
return isRecord(value) && typeof value.imageRef === "string" && typeof value.error === "string";
|
|
4235
|
+
}
|
|
4235
4236
|
function imageGenerationDuration(output) {
|
|
4236
4237
|
const value = output.duration ?? output.elapsed ?? output.durationMs ?? output.elapsedMs;
|
|
4237
4238
|
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.round(value)) : undefined;
|
|
4238
4239
|
}
|
|
4239
4240
|
function formatListToolResult(output, ok) {
|
|
4241
|
+
const error = typeof output.error === "string" ? output.error : undefined;
|
|
4242
|
+
if (!ok || error)
|
|
4243
|
+
return ["directory listing failed", error ?? formatReplData(output, 1200)].join("\n");
|
|
4240
4244
|
const pathValue = typeof output.path === "string" ? output.path : "";
|
|
4241
|
-
const typeValue = typeof output.type === "string" ? output.type : "result";
|
|
4242
4245
|
const returnedEntries = typeof output.returnedEntries === "number" ? output.returnedEntries : undefined;
|
|
4243
4246
|
const totalFiles = typeof output.totalFiles === "number" ? output.totalFiles : undefined;
|
|
4244
4247
|
const totalDirectories = typeof output.totalDirectories === "number" ? output.totalDirectories : undefined;
|
|
4245
4248
|
const entries = Array.isArray(output.entries) ? output.entries : [];
|
|
4246
4249
|
const names = entries
|
|
4247
|
-
.map((entry) =>
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4250
|
+
.map((entry) => {
|
|
4251
|
+
if (!isRecord(entry) || typeof entry.name !== "string")
|
|
4252
|
+
return undefined;
|
|
4253
|
+
return entry.type === "directory" ? `${entry.name}/` : entry.name;
|
|
4254
|
+
})
|
|
4255
|
+
.filter((name) => Boolean(name));
|
|
4256
|
+
const lines = pathValue ? [pathValue] : [];
|
|
4253
4257
|
const counts = [
|
|
4254
|
-
returnedEntries !== undefined ? `${returnedEntries} shown` : undefined,
|
|
4258
|
+
returnedEntries !== undefined ? `${returnedEntries} entries shown` : undefined,
|
|
4255
4259
|
totalFiles !== undefined ? `${totalFiles} files` : undefined,
|
|
4256
|
-
totalDirectories !== undefined ? `${totalDirectories}
|
|
4260
|
+
totalDirectories !== undefined ? `${totalDirectories} directories` : undefined,
|
|
4257
4261
|
].filter((value) => Boolean(value));
|
|
4258
4262
|
if (counts.length > 0)
|
|
4259
|
-
lines.push(counts.join("
|
|
4260
|
-
|
|
4261
|
-
lines.push(
|
|
4263
|
+
lines.push(dimAnsi(counts.join(", ")));
|
|
4264
|
+
if (names.length > 0) {
|
|
4265
|
+
lines.push("");
|
|
4266
|
+
lines.push(...names.slice(0, LIST_ENTRY_PREVIEW_COUNT));
|
|
4267
|
+
if (names.length > LIST_ENTRY_PREVIEW_COUNT)
|
|
4268
|
+
lines.push(dimAnsi(`showing first ${LIST_ENTRY_PREVIEW_COUNT} of ${names.length} entries`));
|
|
4269
|
+
}
|
|
4262
4270
|
return lines.join("\n");
|
|
4263
4271
|
}
|
|
4264
4272
|
function formatReadToolResult(output, ok) {
|
|
4265
4273
|
const error = typeof output.error === "string" ? output.error : undefined;
|
|
4266
4274
|
if (!ok || error)
|
|
4267
|
-
return ["failed", error ??
|
|
4275
|
+
return ["file read failed", error ?? formatReplData(output, 1200)].join("\n");
|
|
4268
4276
|
const pathValue = typeof output.path === "string" ? output.path : undefined;
|
|
4269
4277
|
const startLine = typeof output.startLine === "number" ? output.startLine : undefined;
|
|
4270
4278
|
const endLine = typeof output.endLine === "number" ? output.endLine : undefined;
|
|
@@ -4272,17 +4280,23 @@ function formatReadToolResult(output, ok) {
|
|
|
4272
4280
|
const hasMoreBefore = output.hasMoreBefore === true;
|
|
4273
4281
|
const hasMoreAfter = output.hasMoreAfter === true;
|
|
4274
4282
|
const content = typeof output.content === "string" ? output.content.trimEnd() : "";
|
|
4275
|
-
const
|
|
4276
|
-
|
|
4277
|
-
lines.push(`file: ${pathValue}`);
|
|
4283
|
+
const contentLines = content ? content.split("\n") : [];
|
|
4284
|
+
const lines = pathValue ? [pathValue] : [];
|
|
4278
4285
|
if (startLine !== undefined && endLine !== undefined && totalLines !== undefined) {
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
lines.push(
|
|
4286
|
+
lines.push(dimAnsi(`lines ${startLine}-${endLine} of ${totalLines}`));
|
|
4287
|
+
}
|
|
4288
|
+
if (contentLines.length > 0) {
|
|
4289
|
+
lines.push("");
|
|
4290
|
+
lines.push(...contentLines.slice(0, READ_CONTENT_PREVIEW_LINES));
|
|
4291
|
+
if (contentLines.length > READ_CONTENT_PREVIEW_LINES)
|
|
4292
|
+
lines.push(dimAnsi(`showing first ${READ_CONTENT_PREVIEW_LINES} of ${contentLines.length} returned lines`));
|
|
4283
4293
|
}
|
|
4284
|
-
|
|
4285
|
-
|
|
4294
|
+
else {
|
|
4295
|
+
lines.push("", dimAnsi("empty range"));
|
|
4296
|
+
}
|
|
4297
|
+
const more = [hasMoreBefore ? "before" : undefined, hasMoreAfter ? "after" : undefined].filter((value) => Boolean(value));
|
|
4298
|
+
if (more.length > 0)
|
|
4299
|
+
lines.push(dimAnsi(`more content exists ${more.join(" and ")} this range`));
|
|
4286
4300
|
return lines.join("\n");
|
|
4287
4301
|
}
|
|
4288
4302
|
function formatWebSearchToolResult(output, ok) {
|
|
@@ -4320,7 +4334,7 @@ function formatWebSearchToolResult(output, ok) {
|
|
|
4320
4334
|
function formatGrepToolResult(output, ok) {
|
|
4321
4335
|
const error = typeof output.error === "string" ? output.error : undefined;
|
|
4322
4336
|
if (!ok || error)
|
|
4323
|
-
return ["failed", error ??
|
|
4337
|
+
return ["search failed", error ?? formatReplData(output, 1200)].join("\n");
|
|
4324
4338
|
const query = typeof output.query === "string" ? output.query : undefined;
|
|
4325
4339
|
const grepPath = typeof output.grepPath === "string" ? output.grepPath : undefined;
|
|
4326
4340
|
const returnedMatches = typeof output.returnedMatches === "number" ? output.returnedMatches : undefined;
|
|
@@ -4332,39 +4346,40 @@ function formatGrepToolResult(output, ok) {
|
|
|
4332
4346
|
: [];
|
|
4333
4347
|
const transportTruncation = isRecord(output.transportTruncation) ? output.transportTruncation : undefined;
|
|
4334
4348
|
const omittedMatches = typeof transportTruncation?.omittedMatches === "number" ? transportTruncation.omittedMatches : undefined;
|
|
4335
|
-
const
|
|
4349
|
+
const total = totalMatchesKnown ?? returnedMatches ?? matches.length;
|
|
4350
|
+
const lines = [`${total} ${total === 1 ? "match" : "matches"}`];
|
|
4336
4351
|
if (query !== undefined)
|
|
4337
|
-
lines.push(
|
|
4352
|
+
lines.push(`${dimAnsi("query")} ${query}`);
|
|
4338
4353
|
if (grepPath !== undefined)
|
|
4339
|
-
lines.push(
|
|
4340
|
-
const countParts = [
|
|
4341
|
-
`${returnedMatches ?? matches.length} shown`,
|
|
4342
|
-
totalMatchesKnown !== undefined ? `${totalMatchesKnown} known` : undefined,
|
|
4343
|
-
truncated ? "truncated" : undefined,
|
|
4344
|
-
omittedMatches !== undefined && omittedMatches > 0 ? `${omittedMatches} omitted` : undefined,
|
|
4345
|
-
].filter((value) => Boolean(value));
|
|
4346
|
-
lines.push(`matches: ${countParts.join(" · ")}`);
|
|
4354
|
+
lines.push(`${dimAnsi("path")} ${grepPath}`);
|
|
4347
4355
|
if (errors.length > 0) {
|
|
4348
|
-
lines.push("errors
|
|
4349
|
-
lines.push(...errors.slice(0, 5)
|
|
4356
|
+
lines.push("", dimAnsi("errors"));
|
|
4357
|
+
lines.push(...errors.slice(0, 5));
|
|
4350
4358
|
if (errors.length > 5)
|
|
4351
|
-
lines.push(
|
|
4359
|
+
lines.push(dimAnsi(`${errors.length - 5} more errors`));
|
|
4352
4360
|
}
|
|
4353
4361
|
if (matches.length === 0) {
|
|
4354
|
-
lines.push("no matches");
|
|
4362
|
+
lines.push("", dimAnsi("no matches"));
|
|
4355
4363
|
return lines.join("\n");
|
|
4356
4364
|
}
|
|
4357
|
-
lines.push("
|
|
4358
|
-
for (const match of matches) {
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4365
|
+
lines.push("");
|
|
4366
|
+
for (const match of matches.slice(0, GREP_MATCH_PREVIEW_COUNT)) {
|
|
4367
|
+
const before = (match.contextBefore ?? []).slice(-GREP_CONTEXT_PREVIEW_LINES);
|
|
4368
|
+
const after = (match.contextAfter ?? []).slice(0, GREP_CONTEXT_PREVIEW_LINES);
|
|
4369
|
+
for (const context of before)
|
|
4370
|
+
lines.push(dimAnsi(formatGrepContextLine(context, "-")));
|
|
4362
4371
|
lines.push(formatGrepMatchLine(match));
|
|
4363
|
-
for (const context of
|
|
4364
|
-
lines.push(formatGrepContextLine(context, "+"));
|
|
4365
|
-
|
|
4372
|
+
for (const context of after)
|
|
4373
|
+
lines.push(dimAnsi(formatGrepContextLine(context, "+")));
|
|
4374
|
+
lines.push("");
|
|
4366
4375
|
}
|
|
4367
|
-
|
|
4376
|
+
if (matches.length > GREP_MATCH_PREVIEW_COUNT)
|
|
4377
|
+
lines.push(dimAnsi(`showing first ${GREP_MATCH_PREVIEW_COUNT} of ${matches.length} returned matches`));
|
|
4378
|
+
if (truncated)
|
|
4379
|
+
lines.push(dimAnsi("results were truncated"));
|
|
4380
|
+
if (omittedMatches !== undefined && omittedMatches > 0)
|
|
4381
|
+
lines.push(dimAnsi(`${omittedMatches} additional matches omitted by transport`));
|
|
4382
|
+
return lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
4368
4383
|
}
|
|
4369
4384
|
function isGrepMatchLike(value) {
|
|
4370
4385
|
if (!isRecord(value))
|
|
@@ -4671,7 +4686,6 @@ const SESSIONS_DEFAULT_PAGE_SIZE = 10;
|
|
|
4671
4686
|
const TERMINAL_TITLE_WORKING_PREFIX = "● ";
|
|
4672
4687
|
const TERMINAL_TITLE_READY_PREFIX = "✓ ";
|
|
4673
4688
|
const REPL_ANIMATION_INTERVAL_MS = 420;
|
|
4674
|
-
const TOOL_RESULT_REPLACEMENT_DELAY_MS = 2000;
|
|
4675
4689
|
const SUBAGENT_ACTIVITY_UPDATE_DEBOUNCE_MS = 1000;
|
|
4676
4690
|
const SUBAGENT_COMPLETED_LINGER_MS = 8000;
|
|
4677
4691
|
const TOKEN_PULSE_MS = 900;
|
|
@@ -4693,10 +4707,7 @@ const QUEUED_INPUT_RENDER_ROWS = 1;
|
|
|
4693
4707
|
const EMPTY_CTRL_C_EXIT_PLACEHOLDER = "Press Ctrl+C again to exit";
|
|
4694
4708
|
const LONG_CLIPBOARD_TEXT_THRESHOLD = 200;
|
|
4695
4709
|
const PASTE_STATUS_DISPLAY_MS = 2500;
|
|
4696
|
-
const MIN_LIVE_VIEWPORT_LINES = 1;
|
|
4697
|
-
const FULLSCREEN_RENDER_GUARD_ROWS = 3;
|
|
4698
4710
|
const COMPACT_LIVE_LAYOUT_ROWS = 24;
|
|
4699
|
-
const COMPACT_LIVE_DYNAMIC_BLOCKS = 1;
|
|
4700
4711
|
const MESSAGE_BLOCK_SPACING_LINES = 1;
|
|
4701
4712
|
const SUMMARY_BLOCK = {
|
|
4702
4713
|
maxLines: 6,
|
|
@@ -4707,6 +4718,17 @@ const THINKING_MARKER = "◆";
|
|
|
4707
4718
|
const THINKING_SUMMARY_MAX_LINES = 1000;
|
|
4708
4719
|
const EXPANDED_SUMMARY_MAX_LINES = 1000;
|
|
4709
4720
|
const EDIT_TOOL_SUMMARY_MAX_LINES = EXPANDED_SUMMARY_MAX_LINES;
|
|
4721
|
+
const EXEC_COMMAND_PREVIEW_CHARS = 120;
|
|
4722
|
+
const EXEC_STDOUT_PREVIEW_LINES = 40;
|
|
4723
|
+
const EXEC_STDERR_PREVIEW_LINES = 60;
|
|
4724
|
+
const READ_CONTENT_PREVIEW_LINES = 80;
|
|
4725
|
+
const IMAGE_PROMPT_PREVIEW_LINES = 8;
|
|
4726
|
+
const IMAGE_NOTE_PREVIEW_COUNT = 8;
|
|
4727
|
+
const GREP_MATCH_PREVIEW_COUNT = 20;
|
|
4728
|
+
const GREP_CONTEXT_PREVIEW_LINES = 2;
|
|
4729
|
+
const LIST_ENTRY_PREVIEW_COUNT = 12;
|
|
4730
|
+
const FALLBACK_PREVIEW_LINES = 40;
|
|
4731
|
+
const LOW_VALUE_FALLBACK_FIELDS = new Set(["ok", "summary", "metadata", "transportTruncation"]);
|
|
4710
4732
|
function fixed(value, width, align = "right") {
|
|
4711
4733
|
const stripped = stripAnsi(value);
|
|
4712
4734
|
const trimmed = stripped.length > width ? stripped.slice(0, width) : stripped;
|