@kenkaiiii/ggcoder 4.3.212 → 4.3.214
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 +5 -8
- package/dist/cli.d.ts +3 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +112 -61
- package/dist/cli.js.map +1 -1
- package/dist/core/continue-replay-inventory.test.d.ts +2 -0
- package/dist/core/continue-replay-inventory.test.d.ts.map +1 -0
- package/dist/core/continue-replay-inventory.test.js +42 -0
- package/dist/core/continue-replay-inventory.test.js.map +1 -0
- package/dist/core/goal-controller.d.ts +2 -0
- package/dist/core/goal-controller.d.ts.map +1 -1
- package/dist/core/goal-controller.js +283 -24
- package/dist/core/goal-controller.js.map +1 -1
- package/dist/core/goal-controller.test.js +413 -16
- package/dist/core/goal-controller.test.js.map +1 -1
- package/dist/core/goal-lifecycle-smoke.test.js +48 -6
- package/dist/core/goal-lifecycle-smoke.test.js.map +1 -1
- package/dist/core/goal-prerequisites.d.ts +5 -0
- package/dist/core/goal-prerequisites.d.ts.map +1 -1
- package/dist/core/goal-prerequisites.js +37 -0
- package/dist/core/goal-prerequisites.js.map +1 -1
- package/dist/core/goal-prerequisites.test.js +29 -1
- package/dist/core/goal-prerequisites.test.js.map +1 -1
- package/dist/core/goal-references.d.ts +14 -0
- package/dist/core/goal-references.d.ts.map +1 -0
- package/dist/core/goal-references.js +153 -0
- package/dist/core/goal-references.js.map +1 -0
- package/dist/core/goal-references.test.d.ts +2 -0
- package/dist/core/goal-references.test.d.ts.map +1 -0
- package/dist/core/goal-references.test.js +77 -0
- package/dist/core/goal-references.test.js.map +1 -0
- package/dist/core/goal-store.d.ts +25 -0
- package/dist/core/goal-store.d.ts.map +1 -1
- package/dist/core/goal-store.js +150 -36
- package/dist/core/goal-store.js.map +1 -1
- package/dist/core/goal-store.test.js +19 -2
- package/dist/core/goal-store.test.js.map +1 -1
- package/dist/core/goal-verifier.d.ts.map +1 -1
- package/dist/core/goal-verifier.js +4 -1
- package/dist/core/goal-verifier.js.map +1 -1
- package/dist/core/goal-verifier.test.js +43 -0
- package/dist/core/goal-verifier.test.js.map +1 -1
- package/dist/core/goal-worker.d.ts +2 -0
- package/dist/core/goal-worker.d.ts.map +1 -1
- package/dist/core/goal-worker.js +33 -9
- package/dist/core/goal-worker.js.map +1 -1
- package/dist/core/goal-worker.test.js +49 -1
- package/dist/core/goal-worker.test.js.map +1 -1
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +28 -846
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/prompt-commands.test.js +40 -78
- package/dist/core/prompt-commands.test.js.map +1 -1
- package/dist/core/runtime-mode.d.ts +14 -0
- package/dist/core/runtime-mode.d.ts.map +1 -0
- package/dist/core/runtime-mode.js +10 -0
- package/dist/core/runtime-mode.js.map +1 -0
- package/dist/core/session-restore-display.test.d.ts +2 -0
- package/dist/core/session-restore-display.test.d.ts.map +1 -0
- package/dist/core/session-restore-display.test.js +100 -0
- package/dist/core/session-restore-display.test.js.map +1 -0
- package/dist/core/verify-commands.js +4 -4
- package/dist/core/verify-commands.js.map +1 -1
- package/dist/system-prompt.d.ts +2 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +51 -37
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +147 -40
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/tools/bash.d.ts +3 -2
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +11 -4
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +5 -3
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +14 -4
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/edit.test.js +0 -10
- package/dist/tools/edit.test.js.map +1 -1
- package/dist/tools/goal-mode.test.d.ts +2 -0
- package/dist/tools/goal-mode.test.d.ts.map +1 -0
- package/dist/tools/goal-mode.test.js +121 -0
- package/dist/tools/goal-mode.test.js.map +1 -0
- package/dist/tools/goals.d.ts +15 -3
- package/dist/tools/goals.d.ts.map +1 -1
- package/dist/tools/goals.js +336 -26
- package/dist/tools/goals.js.map +1 -1
- package/dist/tools/goals.test.js +346 -6
- package/dist/tools/goals.test.js.map +1 -1
- package/dist/tools/index.d.ts +7 -10
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -19
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/plan-mode.test.js +34 -224
- package/dist/tools/plan-mode.test.js.map +1 -1
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +2 -6
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/subagent.d.ts +3 -2
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +4 -9
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/write.d.ts +5 -3
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +14 -13
- package/dist/tools/write.js.map +1 -1
- package/dist/tools/write.test.js +0 -16
- package/dist/tools/write.test.js.map +1 -1
- package/dist/ui/App.d.ts +145 -28
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +1153 -864
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/activity-phrases.d.ts.map +1 -1
- package/dist/ui/activity-phrases.js +0 -2
- package/dist/ui/activity-phrases.js.map +1 -1
- package/dist/ui/app-state-persistence.test.js +173 -5
- package/dist/ui/app-state-persistence.test.js.map +1 -1
- package/dist/ui/chat-layout-pinning.test.d.ts +2 -0
- package/dist/ui/chat-layout-pinning.test.d.ts.map +1 -0
- package/dist/ui/chat-layout-pinning.test.js +407 -0
- package/dist/ui/chat-layout-pinning.test.js.map +1 -0
- package/dist/ui/components/ActivityIndicator.d.ts +1 -2
- package/dist/ui/components/ActivityIndicator.d.ts.map +1 -1
- package/dist/ui/components/ActivityIndicator.js +63 -94
- package/dist/ui/components/ActivityIndicator.js.map +1 -1
- package/dist/ui/components/AssistantMessage.d.ts +6 -2
- package/dist/ui/components/AssistantMessage.d.ts.map +1 -1
- package/dist/ui/components/AssistantMessage.js +9 -4
- package/dist/ui/components/AssistantMessage.js.map +1 -1
- package/dist/ui/components/AssistantMessage.test.d.ts +2 -0
- package/dist/ui/components/AssistantMessage.test.d.ts.map +1 -0
- package/dist/ui/components/AssistantMessage.test.js +369 -0
- package/dist/ui/components/AssistantMessage.test.js.map +1 -0
- package/dist/ui/components/BackgroundTasksBar.d.ts +1 -3
- package/dist/ui/components/BackgroundTasksBar.d.ts.map +1 -1
- package/dist/ui/components/BackgroundTasksBar.js +2 -4
- package/dist/ui/components/BackgroundTasksBar.js.map +1 -1
- package/dist/ui/components/Banner.d.ts +1 -3
- package/dist/ui/components/Banner.d.ts.map +1 -1
- package/dist/ui/components/Banner.js +7 -3
- package/dist/ui/components/Banner.js.map +1 -1
- package/dist/ui/components/Footer.d.ts +26 -4
- package/dist/ui/components/Footer.d.ts.map +1 -1
- package/dist/ui/components/Footer.js +73 -21
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/GoalOverlay.d.ts +28 -20
- package/dist/ui/components/GoalOverlay.d.ts.map +1 -1
- package/dist/ui/components/GoalOverlay.js +283 -253
- package/dist/ui/components/GoalOverlay.js.map +1 -1
- package/dist/ui/components/InputArea.d.ts +2 -6
- package/dist/ui/components/InputArea.d.ts.map +1 -1
- package/dist/ui/components/InputArea.js +40 -32
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/InputArea.test.js +11 -1
- package/dist/ui/components/InputArea.test.js.map +1 -1
- package/dist/ui/components/Markdown.d.ts +11 -11
- package/dist/ui/components/Markdown.d.ts.map +1 -1
- package/dist/ui/components/Markdown.js +25 -198
- package/dist/ui/components/Markdown.js.map +1 -1
- package/dist/ui/components/PlanOverlay.d.ts.map +1 -1
- package/dist/ui/components/PlanOverlay.js +1 -1
- package/dist/ui/components/PlanOverlay.js.map +1 -1
- package/dist/ui/components/ServerToolExecution.d.ts.map +1 -1
- package/dist/ui/components/ServerToolExecution.js +3 -2
- package/dist/ui/components/ServerToolExecution.js.map +1 -1
- package/dist/ui/components/SlashCommandMenu.d.ts +4 -3
- package/dist/ui/components/SlashCommandMenu.d.ts.map +1 -1
- package/dist/ui/components/SlashCommandMenu.js +38 -26
- package/dist/ui/components/SlashCommandMenu.js.map +1 -1
- package/dist/ui/components/StreamingArea.d.ts +11 -2
- package/dist/ui/components/StreamingArea.d.ts.map +1 -1
- package/dist/ui/components/StreamingArea.js +20 -23
- package/dist/ui/components/StreamingArea.js.map +1 -1
- package/dist/ui/components/StreamingArea.test.d.ts +2 -0
- package/dist/ui/components/StreamingArea.test.d.ts.map +1 -0
- package/dist/ui/components/StreamingArea.test.js +18 -0
- package/dist/ui/components/StreamingArea.test.js.map +1 -0
- package/dist/ui/components/ToolExecution.d.ts.map +1 -1
- package/dist/ui/components/ToolExecution.js +11 -27
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/components/ToolGroupExecution.d.ts.map +1 -1
- package/dist/ui/components/ToolGroupExecution.js +9 -124
- package/dist/ui/components/ToolGroupExecution.js.map +1 -1
- package/dist/ui/components/UserMessage.d.ts.map +1 -1
- package/dist/ui/components/UserMessage.js +15 -10
- package/dist/ui/components/UserMessage.js.map +1 -1
- package/dist/ui/components/UserMessage.test.d.ts +2 -0
- package/dist/ui/components/UserMessage.test.d.ts.map +1 -0
- package/dist/ui/components/UserMessage.test.js +39 -0
- package/dist/ui/components/UserMessage.test.js.map +1 -0
- package/dist/ui/footer-status-layout.test.js +21 -7
- package/dist/ui/footer-status-layout.test.js.map +1 -1
- package/dist/ui/goal-events.d.ts +13 -0
- package/dist/ui/goal-events.d.ts.map +1 -1
- package/dist/ui/goal-events.js +81 -16
- package/dist/ui/goal-events.js.map +1 -1
- package/dist/ui/goal-events.test.js +76 -2
- package/dist/ui/goal-events.test.js.map +1 -1
- package/dist/ui/goal-lifecycle-orchestration.test.js +131 -34
- package/dist/ui/goal-lifecycle-orchestration.test.js.map +1 -1
- package/dist/ui/goal-overlay.test.js +121 -43
- package/dist/ui/goal-overlay.test.js.map +1 -1
- package/dist/ui/goal-summary.d.ts +14 -0
- package/dist/ui/goal-summary.d.ts.map +1 -0
- package/dist/ui/goal-summary.js +194 -0
- package/dist/ui/goal-summary.js.map +1 -0
- package/dist/ui/hooks/useAgentLoop.d.ts +8 -2
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +20 -9
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.test.d.ts +2 -0
- package/dist/ui/hooks/useAgentLoop.test.d.ts.map +1 -0
- package/dist/ui/hooks/useAgentLoop.test.js +8 -0
- package/dist/ui/hooks/useAgentLoop.test.js.map +1 -0
- package/dist/ui/hooks/useTerminalSize.d.ts +5 -9
- package/dist/ui/hooks/useTerminalSize.d.ts.map +1 -1
- package/dist/ui/hooks/useTerminalSize.js +9 -14
- package/dist/ui/hooks/useTerminalSize.js.map +1 -1
- package/dist/ui/live-item-flush.d.ts +2 -2
- package/dist/ui/live-item-flush.d.ts.map +1 -1
- package/dist/ui/live-item-flush.js +8 -4
- package/dist/ui/live-item-flush.js.map +1 -1
- package/dist/ui/long-prompt-regression-harness.test.d.ts +2 -0
- package/dist/ui/long-prompt-regression-harness.test.d.ts.map +1 -0
- package/dist/ui/long-prompt-regression-harness.test.js +195 -0
- package/dist/ui/long-prompt-regression-harness.test.js.map +1 -0
- package/dist/ui/plan-overlay.test.js +7 -29
- package/dist/ui/plan-overlay.test.js.map +1 -1
- package/dist/ui/queued-message.test.d.ts.map +1 -1
- package/dist/ui/queued-message.test.js +76 -14
- package/dist/ui/queued-message.test.js.map +1 -1
- package/dist/ui/render.d.ts +21 -24
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +46 -28
- package/dist/ui/render.js.map +1 -1
- package/dist/ui/render.test.d.ts +2 -0
- package/dist/ui/render.test.d.ts.map +1 -0
- package/dist/ui/render.test.js +16 -0
- package/dist/ui/render.test.js.map +1 -0
- package/dist/ui/scroll-stabilization.test.js +1 -1
- package/dist/ui/scroll-stabilization.test.js.map +1 -1
- package/dist/ui/slash-command-images.test.js +79 -4
- package/dist/ui/slash-command-images.test.js.map +1 -1
- package/dist/ui/terminal-history.d.ts +26 -0
- package/dist/ui/terminal-history.d.ts.map +1 -0
- package/dist/ui/terminal-history.js +910 -0
- package/dist/ui/terminal-history.js.map +1 -0
- package/dist/ui/terminal-history.test.d.ts +2 -0
- package/dist/ui/terminal-history.test.d.ts.map +1 -0
- package/dist/ui/terminal-history.test.js +314 -0
- package/dist/ui/terminal-history.test.js.map +1 -0
- package/dist/ui/tool-group-summary.d.ts +16 -0
- package/dist/ui/tool-group-summary.d.ts.map +1 -0
- package/dist/ui/tool-group-summary.js +123 -0
- package/dist/ui/tool-group-summary.js.map +1 -0
- package/dist/ui/tui-history-parity.test.d.ts +2 -0
- package/dist/ui/tui-history-parity.test.d.ts.map +1 -0
- package/dist/ui/tui-history-parity.test.js +243 -0
- package/dist/ui/tui-history-parity.test.js.map +1 -0
- package/dist/ui/utils/assistant-stream-split.d.ts +6 -0
- package/dist/ui/utils/assistant-stream-split.d.ts.map +1 -0
- package/dist/ui/utils/assistant-stream-split.js +37 -0
- package/dist/ui/utils/assistant-stream-split.js.map +1 -0
- package/dist/ui/utils/assistant-stream-split.test.d.ts +2 -0
- package/dist/ui/utils/assistant-stream-split.test.d.ts.map +1 -0
- package/dist/ui/utils/assistant-stream-split.test.js +58 -0
- package/dist/ui/utils/assistant-stream-split.test.js.map +1 -0
- package/dist/ui/utils/latex-to-unicode.d.ts +22 -0
- package/dist/ui/utils/latex-to-unicode.d.ts.map +1 -0
- package/dist/ui/utils/latex-to-unicode.js +538 -0
- package/dist/ui/utils/latex-to-unicode.js.map +1 -0
- package/dist/ui/utils/markdown-renderer.d.ts +20 -0
- package/dist/ui/utils/markdown-renderer.d.ts.map +1 -0
- package/dist/ui/utils/markdown-renderer.js +327 -0
- package/dist/ui/utils/markdown-renderer.js.map +1 -0
- package/dist/ui/utils/markdown-table.d.ts +9 -0
- package/dist/ui/utils/markdown-table.d.ts.map +1 -0
- package/dist/ui/utils/markdown-table.js +95 -0
- package/dist/ui/utils/markdown-table.js.map +1 -0
- package/dist/ui/utils/text-utils.d.ts +8 -0
- package/dist/ui/utils/text-utils.d.ts.map +1 -0
- package/dist/ui/utils/text-utils.js +16 -0
- package/dist/ui/utils/text-utils.js.map +1 -0
- package/dist/ui/utils/token-to-ansi.js +19 -9
- package/dist/ui/utils/token-to-ansi.js.map +1 -1
- package/dist/ui/utils/user-message-display.d.ts +7 -0
- package/dist/ui/utils/user-message-display.d.ts.map +1 -0
- package/dist/ui/utils/user-message-display.js +26 -0
- package/dist/ui/utils/user-message-display.js.map +1 -0
- package/dist/utils/format.js +0 -9
- package/dist/utils/format.js.map +1 -1
- package/package.json +9 -4
- package/dist/tools/enter-plan.d.ts +0 -8
- package/dist/tools/enter-plan.d.ts.map +0 -1
- package/dist/tools/enter-plan.js +0 -30
- package/dist/tools/enter-plan.js.map +0 -1
- package/dist/tools/exit-plan.d.ts +0 -8
- package/dist/tools/exit-plan.d.ts.map +0 -1
- package/dist/tools/exit-plan.js +0 -36
- package/dist/tools/exit-plan.js.map +0 -1
- package/dist/tools/tasks.d.ts +0 -16
- package/dist/tools/tasks.d.ts.map +0 -1
- package/dist/tools/tasks.js +0 -133
- package/dist/tools/tasks.js.map +0 -1
- package/dist/ui/components/EyesOverlay.d.ts +0 -10
- package/dist/ui/components/EyesOverlay.d.ts.map +0 -1
- package/dist/ui/components/EyesOverlay.js +0 -220
- package/dist/ui/components/EyesOverlay.js.map +0 -1
- package/dist/ui/components/TaskOverlay.d.ts +0 -10
- package/dist/ui/components/TaskOverlay.d.ts.map +0 -1
- package/dist/ui/components/TaskOverlay.js +0 -267
- package/dist/ui/components/TaskOverlay.js.map +0 -1
|
@@ -0,0 +1,910 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import stringWidth from "string-width";
|
|
3
|
+
import wrapAnsi from "wrap-ansi";
|
|
4
|
+
import { getModel } from "../core/model-registry.js";
|
|
5
|
+
import { LANGUAGE_DISPLAY_NAMES } from "../core/language-detector.js";
|
|
6
|
+
import { BLACK_CIRCLE, RETURN_SYMBOL } from "./constants/figures.js";
|
|
7
|
+
import { getUserMessageDisplayParts } from "./utils/user-message-display.js";
|
|
8
|
+
import { buildToolGroupSummary, segmentsToPlainText } from "./tool-group-summary.js";
|
|
9
|
+
import { renderMarkdownToAnsiLines } from "./utils/markdown-renderer.js";
|
|
10
|
+
const LOGO_LINES = [" ▄▀▀▀ ▄▀▀▀", " █ ▀█ █ ▀█", " ▀▄▄▀ ▀▄▄▀"];
|
|
11
|
+
const GRADIENT = [
|
|
12
|
+
"#60a5fa",
|
|
13
|
+
"#6da1f9",
|
|
14
|
+
"#7a9df7",
|
|
15
|
+
"#8799f5",
|
|
16
|
+
"#9495f3",
|
|
17
|
+
"#a18ff1",
|
|
18
|
+
"#a78bfa",
|
|
19
|
+
"#a18ff1",
|
|
20
|
+
"#9495f3",
|
|
21
|
+
"#8799f5",
|
|
22
|
+
"#7a9df7",
|
|
23
|
+
"#6da1f9",
|
|
24
|
+
];
|
|
25
|
+
const GAP = " ";
|
|
26
|
+
const LOGO_WIDTH = 9;
|
|
27
|
+
const SIDE_BY_SIDE_MIN = LOGO_WIDTH + GAP.length + 20;
|
|
28
|
+
const MAX_OUTPUT_LINES = 4;
|
|
29
|
+
const RESPONSE_LEFT_PADDING = " ";
|
|
30
|
+
const USER_MESSAGE_BACKGROUND = "#374151";
|
|
31
|
+
const USER_MESSAGE_PREFIX = "> ";
|
|
32
|
+
const USER_MESSAGE_TOP_FILL = "▄";
|
|
33
|
+
const USER_MESSAGE_BOTTOM_FILL = "▀";
|
|
34
|
+
const USER_MESSAGE_HORIZONTAL_PADDING = 2;
|
|
35
|
+
const ANSI_ESCAPE_PATTERN = new RegExp(String.raw `\u001B\[[0-?]*[ -/]*[@-~]`, "gu");
|
|
36
|
+
const COMPACT_TOOLS = new Set(["read", "grep", "find", "ls", "source_path"]);
|
|
37
|
+
const STATE_TOOLS = new Set(["tasks", "goals"]);
|
|
38
|
+
const SERVER_STYLE_TOOLS = new Set(["web_search"]);
|
|
39
|
+
function isAgentSpacingKind(kind) {
|
|
40
|
+
return [
|
|
41
|
+
"assistant",
|
|
42
|
+
"queued",
|
|
43
|
+
"goal_progress",
|
|
44
|
+
"tool_start",
|
|
45
|
+
"tool_done",
|
|
46
|
+
"tool_group",
|
|
47
|
+
"server_tool_start",
|
|
48
|
+
"server_tool_done",
|
|
49
|
+
"subagent_group",
|
|
50
|
+
"info",
|
|
51
|
+
"error",
|
|
52
|
+
"stopped",
|
|
53
|
+
"plan_transition",
|
|
54
|
+
"goal_agent_transition",
|
|
55
|
+
"thinking_transition",
|
|
56
|
+
"model_transition",
|
|
57
|
+
"theme_transition",
|
|
58
|
+
"plan_event",
|
|
59
|
+
].includes(kind);
|
|
60
|
+
}
|
|
61
|
+
export function createTerminalHistoryPrinter({ stream = process.stdout, } = {}) {
|
|
62
|
+
const printed = new Set();
|
|
63
|
+
let previousPrintedKind = null;
|
|
64
|
+
return {
|
|
65
|
+
print(items, context, options) {
|
|
66
|
+
const writeOutput = options?.write ?? ((data) => void stream.write(data));
|
|
67
|
+
for (const item of items) {
|
|
68
|
+
if (!options?.force && printed.has(item.id))
|
|
69
|
+
continue;
|
|
70
|
+
const output = serializeCompletedItemToTerminalHistory(item, context);
|
|
71
|
+
const endsWithBlankLine = item.kind === "banner";
|
|
72
|
+
const formatted = formatHistoryWrite(output, {
|
|
73
|
+
leadingSeparator: previousPrintedKind !== null &&
|
|
74
|
+
isAgentSpacingKind(previousPrintedKind) &&
|
|
75
|
+
isAgentSpacingKind(item.kind),
|
|
76
|
+
trailingBlankLine: endsWithBlankLine,
|
|
77
|
+
});
|
|
78
|
+
if (formatted.length === 0)
|
|
79
|
+
continue;
|
|
80
|
+
printed.add(item.id);
|
|
81
|
+
writeOutput(formatted);
|
|
82
|
+
previousPrintedKind = item.kind;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
clear() {
|
|
86
|
+
printed.clear();
|
|
87
|
+
previousPrintedKind = null;
|
|
88
|
+
},
|
|
89
|
+
resetPrinted() {
|
|
90
|
+
printed.clear();
|
|
91
|
+
previousPrintedKind = null;
|
|
92
|
+
},
|
|
93
|
+
get printedIds() {
|
|
94
|
+
return printed;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function serializeCompletedItemToTerminalHistory(item, context) {
|
|
99
|
+
switch (item.kind) {
|
|
100
|
+
case "banner":
|
|
101
|
+
return renderBanner(context);
|
|
102
|
+
case "user":
|
|
103
|
+
return renderUser(item.text, item.imageCount, item.pasteInfo, context);
|
|
104
|
+
case "queued":
|
|
105
|
+
return renderQueued(item.text, item.imageCount, context);
|
|
106
|
+
case "assistant":
|
|
107
|
+
return renderAssistant(item.text, item.thinking, item.thinkingMs, context, item.continuation);
|
|
108
|
+
case "tool_start":
|
|
109
|
+
return renderToolStart(item.name, item.args, item.progressOutput, context);
|
|
110
|
+
case "tool_done":
|
|
111
|
+
return renderToolDone(item.name, item.args, item.result, item.isError, item.durationMs, context);
|
|
112
|
+
case "tool_group":
|
|
113
|
+
return renderToolGroup(item.tools, context);
|
|
114
|
+
case "server_tool_start":
|
|
115
|
+
return renderServerToolStart(item.name, item.input, context);
|
|
116
|
+
case "server_tool_done":
|
|
117
|
+
return renderServerToolDone(item.name, item.input, item.resultType, item.durationMs, context);
|
|
118
|
+
case "subagent_group":
|
|
119
|
+
return renderSubAgentGroup(item.agents, item.aborted, context);
|
|
120
|
+
case "goal":
|
|
121
|
+
return renderGoal(item.title, item.workerId, context);
|
|
122
|
+
case "goal_progress":
|
|
123
|
+
return renderGoalProgress(item, context);
|
|
124
|
+
case "error":
|
|
125
|
+
return renderError(item.headline, item.message, item.guidance, context);
|
|
126
|
+
case "info":
|
|
127
|
+
return renderStatusLine("○", normalizeStatusText(item.text), context, context.theme.commandColor, false);
|
|
128
|
+
case "style_pack":
|
|
129
|
+
return renderStylePack(item.added, item.showSetupHint, context);
|
|
130
|
+
case "setup_hint":
|
|
131
|
+
return renderSetupHint(context);
|
|
132
|
+
case "update_notice":
|
|
133
|
+
return line(context, context.theme.commandColor, `✨ ${item.text}`, true);
|
|
134
|
+
case "compacting":
|
|
135
|
+
return renderCompacting(context);
|
|
136
|
+
case "compacted":
|
|
137
|
+
return renderCompacted(item.originalCount, item.newCount, item.tokensBefore, item.tokensAfter, context);
|
|
138
|
+
case "duration":
|
|
139
|
+
return dim(context, `✻ ${item.verb} ${formatDuration(item.durationMs)}`);
|
|
140
|
+
case "plan_transition":
|
|
141
|
+
return renderStatusLine("●", normalizeStatusText(item.text), context, context.theme.commandColor, true);
|
|
142
|
+
case "goal_agent_transition":
|
|
143
|
+
return renderStatusLine("●", normalizeStatusText(item.text), context, context.theme.commandColor, true);
|
|
144
|
+
case "thinking_transition":
|
|
145
|
+
return renderStatusLine("✻", item.active ? "Thinking ON" : "Thinking OFF", context, item.active ? context.theme.commandColor : context.theme.textDim, true);
|
|
146
|
+
case "model_transition":
|
|
147
|
+
return renderStatusLine("▸", `${dim(context, "Switched to ")}${color(context.theme.commandColor, item.modelName, true)}`, context, context.theme.commandColor, true, true);
|
|
148
|
+
case "theme_transition":
|
|
149
|
+
return renderStatusLine("◐", `${dim(context, "Theme switched to ")}${color(context.theme.commandColor, item.themeName, true)}`, context, context.theme.commandColor, true, true);
|
|
150
|
+
case "plan_event":
|
|
151
|
+
return renderPlanEvent(item.event, item.detail, context);
|
|
152
|
+
case "stopped":
|
|
153
|
+
return renderStatusLine("⊘", normalizeStatusText(item.text), context, context.theme.commandColor, true);
|
|
154
|
+
case "step_done":
|
|
155
|
+
return renderStepDone(item.stepNum, item.description, context);
|
|
156
|
+
case "tombstone":
|
|
157
|
+
return "";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function normalizeStatusText(text) {
|
|
161
|
+
return text.replace(/\\n/g, "\n").replace(/^\n+|\n+$/g, "");
|
|
162
|
+
}
|
|
163
|
+
function renderStatusLine(glyph, text, context, glyphColor, bold, textAlreadyStyled = false) {
|
|
164
|
+
const prefix = ` ${color(glyphColor, glyph, true)} `;
|
|
165
|
+
const continuation = " ";
|
|
166
|
+
const body = textAlreadyStyled
|
|
167
|
+
? text
|
|
168
|
+
: color(bold ? glyphColor : context.theme.textDim, text, bold);
|
|
169
|
+
return prefixFirstLine(body, prefix, continuation);
|
|
170
|
+
}
|
|
171
|
+
function formatHistoryWrite(output, options) {
|
|
172
|
+
const trimmed = output.replace(/\n+$/u, "");
|
|
173
|
+
if (trimmed.length === 0)
|
|
174
|
+
return "";
|
|
175
|
+
const leading = options.leadingSeparator ? "\n" : "";
|
|
176
|
+
const trailing = options.trailingBlankLine ? "\n\n" : "\n";
|
|
177
|
+
return `${leading}${trimmed}${trailing}`;
|
|
178
|
+
}
|
|
179
|
+
function renderBanner(context) {
|
|
180
|
+
const modelInfo = getModel(context.model);
|
|
181
|
+
const modelName = modelInfo?.name ?? context.model;
|
|
182
|
+
const home = process.env.HOME ?? "";
|
|
183
|
+
const displayPath = home && context.cwd.startsWith(home) ? `~${context.cwd.slice(home.length)}` : context.cwd;
|
|
184
|
+
const logo = LOGO_LINES.map((lineText) => gradientLine(lineText));
|
|
185
|
+
if (context.columns < SIDE_BY_SIDE_MIN) {
|
|
186
|
+
return block([
|
|
187
|
+
"",
|
|
188
|
+
...logo,
|
|
189
|
+
"",
|
|
190
|
+
`${color(context.theme.primary, "GG Coder", true)}${dim(context, ` v${context.version}`)}`,
|
|
191
|
+
`${color(context.theme.secondary, modelName)} ${dim(context, truncatePlain(displayPath, context.columns))}`,
|
|
192
|
+
`${color(context.theme.primary, "/goal")} ${dim(context, "start goal · ")}${color(context.theme.primary, "Shift+Tab")} ${dim(context, "toggle thinking")}`,
|
|
193
|
+
"",
|
|
194
|
+
]);
|
|
195
|
+
}
|
|
196
|
+
return block([
|
|
197
|
+
"",
|
|
198
|
+
`${logo[0]}${GAP}${color(context.theme.primary, "GG Coder", true)}${dim(context, ` v${context.version} · By `)}${color(context.theme.text, "Ken Kai", true)}`,
|
|
199
|
+
`${logo[1]}${GAP}${color(context.theme.secondary, modelName)} ${dim(context, truncatePlain(displayPath, Math.max(10, context.columns - LOGO_WIDTH - GAP.length - stringWidth(modelName) - 2)))}`,
|
|
200
|
+
`${logo[2]}${GAP}${color(context.theme.primary, "/goal")} ${dim(context, "start goal · ")}${color(context.theme.primary, "Shift+Tab")} ${dim(context, "toggle thinking")}`,
|
|
201
|
+
"",
|
|
202
|
+
]);
|
|
203
|
+
}
|
|
204
|
+
function stripAnsi(value) {
|
|
205
|
+
return value.replace(ANSI_ESCAPE_PATTERN, "");
|
|
206
|
+
}
|
|
207
|
+
function renderUser(text, imageCount, pasteInfo, context) {
|
|
208
|
+
const imageBadges = Array.from({ length: imageCount ?? 0 }, (_, index) => userChipSegment(`[Image #${index + 1}]`, context.theme.accent));
|
|
209
|
+
const userMessageText = context.theme.commandColor;
|
|
210
|
+
const separator = userChipSegment(" ", userMessageText);
|
|
211
|
+
const content = [
|
|
212
|
+
...getUserMessageDisplayParts(text, pasteInfo).map((part) => userChipSegment(part.text, part.kind === "paste" ? context.theme.textDim : userMessageText)),
|
|
213
|
+
...imageBadges,
|
|
214
|
+
]
|
|
215
|
+
.filter((part) => part.length > 0)
|
|
216
|
+
.join(separator);
|
|
217
|
+
const messageWidth = Math.max(10, context.columns);
|
|
218
|
+
const contentWidth = Math.max(1, messageWidth - USER_MESSAGE_HORIZONTAL_PADDING - USER_MESSAGE_PREFIX.length);
|
|
219
|
+
const wrapped = wrapAnsi(content || userChipSegment("(empty)", userMessageText), contentWidth, {
|
|
220
|
+
hard: true,
|
|
221
|
+
wordWrap: true,
|
|
222
|
+
});
|
|
223
|
+
const top = chalk.hex(USER_MESSAGE_BACKGROUND)(USER_MESSAGE_TOP_FILL.repeat(messageWidth));
|
|
224
|
+
const bottom = chalk.hex(USER_MESSAGE_BACKGROUND)(USER_MESSAGE_BOTTOM_FILL.repeat(messageWidth));
|
|
225
|
+
const rows = wrapped.split("\n").map((lineText, index) => {
|
|
226
|
+
const prefix = index === 0
|
|
227
|
+
? userChipSegment(USER_MESSAGE_PREFIX, userMessageText, true)
|
|
228
|
+
: userChipSegment(" ".repeat(USER_MESSAGE_PREFIX.length), userMessageText);
|
|
229
|
+
const line = `${userChipSegment(" ", userMessageText)}${prefix}${lineText}`;
|
|
230
|
+
const fillWidth = Math.max(0, messageWidth - stringWidth(stripAnsi(line)));
|
|
231
|
+
return `${line}${userChipSegment(" ".repeat(fillWidth), userMessageText)}`;
|
|
232
|
+
});
|
|
233
|
+
return [top, ...rows, bottom].join("\n");
|
|
234
|
+
}
|
|
235
|
+
function renderQueued(text, imageCount, context) {
|
|
236
|
+
const suffix = imageCount ? ` (+${imageCount} image${imageCount > 1 ? "s" : ""})` : "";
|
|
237
|
+
return prefixFirstLine(wrapPlain(`${dim(context, "Queued: ")}${color(context.theme.text, text || "(empty)")}${color(context.theme.text, suffix)}`, context.columns - 4), ` ${color(context.theme.warning, "•", true)} `, " ");
|
|
238
|
+
}
|
|
239
|
+
function renderAssistant(text, thinking, thinkingMs, context, continuation = false) {
|
|
240
|
+
const lines = [];
|
|
241
|
+
if (thinking?.trim()) {
|
|
242
|
+
const label = `✦ Thought${thinkingMs ? ` for ${formatDuration(thinkingMs)}` : ""}`;
|
|
243
|
+
lines.push(color(context.theme.textMuted, label));
|
|
244
|
+
lines.push(dim(context, indent(wrapPlain(thinking.trim(), context.columns - 2), " ")));
|
|
245
|
+
}
|
|
246
|
+
const body = renderMarkdownToAnsiLines({
|
|
247
|
+
text,
|
|
248
|
+
theme: context.theme,
|
|
249
|
+
width: Math.max(10, context.columns - 4),
|
|
250
|
+
})
|
|
251
|
+
.join("\n")
|
|
252
|
+
.replace(/^\n+|\n+$/g, "");
|
|
253
|
+
if (body.length > 0) {
|
|
254
|
+
lines.push(continuation
|
|
255
|
+
? indent(body, " ")
|
|
256
|
+
: prefixFirstLine(body, ` ${color(context.theme.primary, BLACK_CIRCLE)} `, " "));
|
|
257
|
+
}
|
|
258
|
+
return block(lines);
|
|
259
|
+
}
|
|
260
|
+
function renderToolStart(name, args, progressOutput, context) {
|
|
261
|
+
if (SERVER_STYLE_TOOLS.has(name)) {
|
|
262
|
+
const { label, detail } = getToolHeaderParts(name, args);
|
|
263
|
+
return block([
|
|
264
|
+
toolHeader("running", label, detail, context, { quoteDetail: true }),
|
|
265
|
+
...messageResponse([dim(context, "· Searching...")], context),
|
|
266
|
+
]);
|
|
267
|
+
}
|
|
268
|
+
if (COMPACT_TOOLS.has(name)) {
|
|
269
|
+
return toolHeader("running", getCompactRunningLabel(name, args), "", context);
|
|
270
|
+
}
|
|
271
|
+
if (STATE_TOOLS.has(name)) {
|
|
272
|
+
const { label, detail } = getToolHeaderParts(name, args);
|
|
273
|
+
return stateToolHeader("running", label, detail, "", context);
|
|
274
|
+
}
|
|
275
|
+
const { label, detail } = getToolHeaderParts(name, args);
|
|
276
|
+
const header = name === "bash" && progressOutput?.trim()
|
|
277
|
+
? toolHeader("running", `· ${label}`, detail, context)
|
|
278
|
+
: toolHeader("running", label, detail, context);
|
|
279
|
+
if (name !== "bash" || !progressOutput?.trim())
|
|
280
|
+
return header;
|
|
281
|
+
return block([
|
|
282
|
+
header,
|
|
283
|
+
...messageResponse(outputPreview(progressOutput, context, context.theme.textMuted, { tail: true }), context),
|
|
284
|
+
]);
|
|
285
|
+
}
|
|
286
|
+
function renderToolDone(name, args, result, isError, durationMs, context) {
|
|
287
|
+
if (SERVER_STYLE_TOOLS.has(name)) {
|
|
288
|
+
return renderServerStyleToolDone(name, args, result, isError, context);
|
|
289
|
+
}
|
|
290
|
+
if (COMPACT_TOOLS.has(name) && !isError) {
|
|
291
|
+
return toolHeader("done", getCompactDoneLabel(name, args, result), "", context);
|
|
292
|
+
}
|
|
293
|
+
if (STATE_TOOLS.has(name)) {
|
|
294
|
+
const { label, detail } = getToolHeaderParts(name, args);
|
|
295
|
+
return stateToolHeader(isError ? "error" : "done", label, detail, getInlineSummary(name, result, isError), context);
|
|
296
|
+
}
|
|
297
|
+
const { label, detail } = getToolHeaderParts(name, args);
|
|
298
|
+
const inline = getInlineSummary(name, result, isError);
|
|
299
|
+
const suffix = inline.length > 0 && toolResultPreview(name, result, isError, context).length === 0
|
|
300
|
+
? inline
|
|
301
|
+
: "";
|
|
302
|
+
const header = toolHeader(isError ? "error" : "done", label, detail, context, { suffix });
|
|
303
|
+
const preview = toolResultPreview(name, result, isError, context);
|
|
304
|
+
if (name === "edit" && !isError) {
|
|
305
|
+
const diff = extractDiff(result);
|
|
306
|
+
if (diff)
|
|
307
|
+
return block([header, ...messageResponse(renderDiffPreview(diff, args, context), context)]);
|
|
308
|
+
}
|
|
309
|
+
return block(preview.length > 0 ? [header, ...messageResponse(preview, context)] : [header]);
|
|
310
|
+
}
|
|
311
|
+
function renderToolGroup(tools, context) {
|
|
312
|
+
const allDone = tools.every((tool) => tool.status === "done");
|
|
313
|
+
const hasError = tools.some((tool) => tool.isError);
|
|
314
|
+
const status = allDone ? (hasError ? "error" : "done") : "running";
|
|
315
|
+
return toolHeader(status, segmentsToPlainText(buildToolGroupSummary(tools, allDone)), "", context);
|
|
316
|
+
}
|
|
317
|
+
function renderServerToolStart(name, input, context) {
|
|
318
|
+
const { label, detail } = getServerToolHeaderParts(name, input);
|
|
319
|
+
return block([
|
|
320
|
+
toolHeader("running", label, detail, context, { quoteDetail: true }),
|
|
321
|
+
...messageResponse([dim(context, "· Searching...")], context),
|
|
322
|
+
]);
|
|
323
|
+
}
|
|
324
|
+
function renderServerToolDone(name, input, resultType, durationMs, context) {
|
|
325
|
+
const { label, detail } = getServerToolHeaderParts(name, input);
|
|
326
|
+
const isAborted = resultType === "aborted";
|
|
327
|
+
const summary = isAborted ? "Stopped." : `Did 1 search in ${Math.round(durationMs / 1000)}s`;
|
|
328
|
+
return block([
|
|
329
|
+
toolHeader(isAborted ? "error" : "done", label, detail, context, { quoteDetail: true }),
|
|
330
|
+
...messageResponse([dim(context, summary)], context),
|
|
331
|
+
]);
|
|
332
|
+
}
|
|
333
|
+
function renderSubAgentGroup(agents, aborted, context) {
|
|
334
|
+
if (agents.length === 0)
|
|
335
|
+
return "";
|
|
336
|
+
const runningCount = agents.filter((agent) => agent.status === "running").length;
|
|
337
|
+
const allDone = runningCount === 0;
|
|
338
|
+
const headerText = aborted
|
|
339
|
+
? `${agents.length} agent${agents.length !== 1 ? "s" : ""} interrupted`
|
|
340
|
+
: allDone
|
|
341
|
+
? `${agents.length} agent${agents.length !== 1 ? "s" : ""} completed`
|
|
342
|
+
: `${agents.length} agent${agents.length !== 1 ? "s" : ""} launched`;
|
|
343
|
+
const lines = [
|
|
344
|
+
toolHeader(aborted ? "error" : allDone ? "done" : "running", headerText, "", context).replace(/^ /, ""),
|
|
345
|
+
];
|
|
346
|
+
agents.forEach((agent, index) => {
|
|
347
|
+
lines.push(...renderSubAgentRows(agent, index === agents.length - 1, aborted === true, context));
|
|
348
|
+
});
|
|
349
|
+
return block(lines);
|
|
350
|
+
}
|
|
351
|
+
function renderGoal(title, workerId, context) {
|
|
352
|
+
return `${color(context.theme.success, "▶", true)} ${dim(context, "Goal: ")}${color(context.theme.success, title)}${workerId ? dim(context, ` · worker ${workerId}`) : ""}`;
|
|
353
|
+
}
|
|
354
|
+
function renderGoalProgress(item, context) {
|
|
355
|
+
const isError = item.status === "failed" || item.status === "fail" || item.status === "blocked";
|
|
356
|
+
const status = isError
|
|
357
|
+
? "error"
|
|
358
|
+
: item.phase === "worker_finished" ||
|
|
359
|
+
item.phase === "verifier_finished" ||
|
|
360
|
+
item.phase === "terminal"
|
|
361
|
+
? "done"
|
|
362
|
+
: "running";
|
|
363
|
+
const labelColor = isError
|
|
364
|
+
? context.theme.error
|
|
365
|
+
: item.phase === "worker_finished" || item.phase === "terminal"
|
|
366
|
+
? context.theme.success
|
|
367
|
+
: item.phase === "verifier_finished" || item.phase === "verifier_started"
|
|
368
|
+
? context.theme.accent
|
|
369
|
+
: item.phase === "orchestrator_reviewing" || item.phase === "orchestrator_working"
|
|
370
|
+
? context.theme.secondary
|
|
371
|
+
: item.phase === "continuing"
|
|
372
|
+
? context.theme.warning
|
|
373
|
+
: context.theme.primary;
|
|
374
|
+
const header = `${toolHeader(status, color(labelColor, item.title, true), "", context)}${item.workerId ? dim(context, ` · worker ${item.workerId}`) : ""}`;
|
|
375
|
+
const bodyLines = [];
|
|
376
|
+
if (item.detail) {
|
|
377
|
+
bodyLines.push(dim(context, wrapPlain(item.detail, context.columns - 8)));
|
|
378
|
+
}
|
|
379
|
+
for (const row of item.summaryRows ?? []) {
|
|
380
|
+
bodyLines.push(`${dim(context, row.label.padEnd(12))}${color(context.theme.text, row.value)}${row.detail ? dim(context, ` · ${row.detail}`) : ""}`);
|
|
381
|
+
}
|
|
382
|
+
for (const section of item.summarySections ?? []) {
|
|
383
|
+
bodyLines.push(dim(context, section.title));
|
|
384
|
+
for (const sectionLine of section.lines) {
|
|
385
|
+
bodyLines.push(`${color(context.theme.text, "• ")}${color(context.theme.text, sectionLine)}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return block([header, ...messageResponse(bodyLines, context)]);
|
|
389
|
+
}
|
|
390
|
+
function renderError(headline, message, guidance, context) {
|
|
391
|
+
const lines = [color(context.theme.error, `✗ ${headline}`)];
|
|
392
|
+
if (message && message !== headline) {
|
|
393
|
+
lines.push(dim(context, indent(wrapPlain(message, context.columns - 2), " ")));
|
|
394
|
+
}
|
|
395
|
+
lines.push(dim(context, indent(wrapPlain(`→ ${guidance}`, context.columns - 2), " ")));
|
|
396
|
+
return block(lines);
|
|
397
|
+
}
|
|
398
|
+
function renderStylePack(added, showSetupHint, context) {
|
|
399
|
+
const names = added.map((id) => LANGUAGE_DISPLAY_NAMES[id] ?? id).join(", ");
|
|
400
|
+
const headerLabel = added.length > 1 ? "STYLE PACKS ACTIVE" : "STYLE PACK ACTIVE";
|
|
401
|
+
const lines = [
|
|
402
|
+
`${color(context.theme.language, "◆", true)} ${color(context.theme.language, headerLabel, true)}`,
|
|
403
|
+
color(context.theme.text, names, true),
|
|
404
|
+
];
|
|
405
|
+
if (showSetupHint) {
|
|
406
|
+
lines.push(`${dim(context, "Tip: run ")}${color(context.theme.language, "/setup", true)}${dim(context, " to audit this project against the active pack(s)")}`);
|
|
407
|
+
}
|
|
408
|
+
return block(lines);
|
|
409
|
+
}
|
|
410
|
+
function renderSetupHint(context) {
|
|
411
|
+
return block([
|
|
412
|
+
`${color(context.theme.language, "◆", true)} ${color(context.theme.language, "NO STYLE PACKS DETECTED", true)}`,
|
|
413
|
+
dim(context, "This directory has no recognized language manifest at its root."),
|
|
414
|
+
`${dim(context, "Tip: run ")}${color(context.theme.language, "/setup", true)}${dim(context, " to audit project hygiene or bootstrap a new project from scratch")}`,
|
|
415
|
+
]);
|
|
416
|
+
}
|
|
417
|
+
function renderCompacting(context) {
|
|
418
|
+
return `${color(context.theme.warning, "·")} ${dim(context, "Compacting conversation")}${dim(context, "...")}`;
|
|
419
|
+
}
|
|
420
|
+
function renderCompacted(originalCount, newCount, tokensBefore, tokensAfter, context) {
|
|
421
|
+
const reduction = tokensBefore > 0 ? Math.round((1 - tokensAfter / tokensBefore) * 100) : 0;
|
|
422
|
+
return block([
|
|
423
|
+
`${color(context.theme.warning, "⟳")} ${dim(context, "Conversation compacted")}`,
|
|
424
|
+
dim(context, ` ${originalCount} → ${newCount} messages · ${formatTokenCount(tokensBefore)} → ${formatTokenCount(tokensAfter)} tokens · ${reduction}% reduction`),
|
|
425
|
+
]);
|
|
426
|
+
}
|
|
427
|
+
function renderPlanEvent(event, detail, context) {
|
|
428
|
+
const labels = {
|
|
429
|
+
approved: "Plan approved",
|
|
430
|
+
rejected: "Plan rejected",
|
|
431
|
+
dismissed: "Plan dismissed",
|
|
432
|
+
};
|
|
433
|
+
const lines = [color(context.theme.commandColor, ` ○ ${labels[event]}`, true)];
|
|
434
|
+
if (detail)
|
|
435
|
+
lines[0] += dim(context, ` — "${detail}"`);
|
|
436
|
+
return block(lines);
|
|
437
|
+
}
|
|
438
|
+
function renderStepDone(stepNum, description, context) {
|
|
439
|
+
return `${color(context.theme.success, "✓", true)} ${color(context.theme.success, `Step ${stepNum} done`, true)}${description ? dim(context, ` — ${description}`) : ""}`;
|
|
440
|
+
}
|
|
441
|
+
function renderServerStyleToolDone(name, args, result, isError, context) {
|
|
442
|
+
const { label, detail } = getToolHeaderParts(name, args);
|
|
443
|
+
const searchCount = (result.match(/^\d+\./gm) ?? []).length;
|
|
444
|
+
const summaryText = isError
|
|
445
|
+
? (result.split("\n")[0] ?? "")
|
|
446
|
+
: `${searchCount} result${searchCount !== 1 ? "s" : ""}`;
|
|
447
|
+
return block([
|
|
448
|
+
toolHeader(isError ? "error" : "done", label, detail, context, { quoteDetail: true }),
|
|
449
|
+
...messageResponse([dim(context, summaryText)], context),
|
|
450
|
+
]);
|
|
451
|
+
}
|
|
452
|
+
function renderSubAgentRows(agent, isLast, aborted, context) {
|
|
453
|
+
const branch = isLast ? "└─" : "├─";
|
|
454
|
+
const continuation = isLast ? " " : "│ ";
|
|
455
|
+
const isRunning = agent.status === "running" && !aborted;
|
|
456
|
+
const firstLine = agent.task.split("\n")[0]?.replace(/\*\*/g, "") ?? "";
|
|
457
|
+
const taskDisplay = firstLine.length > 60 ? `${firstLine.slice(0, 57)}…` : firstLine;
|
|
458
|
+
const taskPrefix = agent.status === "done"
|
|
459
|
+
? color(context.theme.success, "✓ ", true)
|
|
460
|
+
: agent.status === "error"
|
|
461
|
+
? color(context.theme.error, "✗ ", true)
|
|
462
|
+
: "";
|
|
463
|
+
const taskLine = `${dim(context, ` ${branch.padEnd(3)}`)}${taskPrefix}${color(agent.status === "done" ? context.theme.success : context.theme.text, taskDisplay, isRunning)}`;
|
|
464
|
+
const totalTokens = agent.tokenUsage ? agent.tokenUsage.input + agent.tokenUsage.output : 0;
|
|
465
|
+
let detail;
|
|
466
|
+
if (isRunning) {
|
|
467
|
+
detail = `${color(context.theme.primary, "· ")}${dim(context, agent.currentActivity ?? "Starting…")}`;
|
|
468
|
+
}
|
|
469
|
+
else if (agent.status === "done") {
|
|
470
|
+
detail = dim(context, `${formatCompactTokens(totalTokens)} tokens${agent.durationMs != null ? ` · ${formatDuration(agent.durationMs)}` : ""}`);
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
detail = color(context.theme.error, `${agent.status === "aborted" || aborted ? "Interrupted" : "Failed"}${agent.durationMs != null ? ` · ${formatDuration(agent.durationMs)}` : ""}`);
|
|
474
|
+
}
|
|
475
|
+
return [taskLine, `${dim(context, ` ${continuation}${RETURN_SYMBOL} `)}${detail}`];
|
|
476
|
+
}
|
|
477
|
+
function toolResultPreview(name, result, isError, context) {
|
|
478
|
+
if (isError)
|
|
479
|
+
return outputPreview(result, context, context.theme.error);
|
|
480
|
+
if (["read", "write", "skill", "web_fetch", "source_path", "task_stop"].includes(name))
|
|
481
|
+
return [];
|
|
482
|
+
if (name === "edit" && extractDiff(result))
|
|
483
|
+
return [];
|
|
484
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
485
|
+
if (name === "bash" && /^Exit code:/.test(lines[0] ?? ""))
|
|
486
|
+
lines.shift();
|
|
487
|
+
if (lines.length === 0 || result === "No matches found.")
|
|
488
|
+
return [];
|
|
489
|
+
return outputPreview(lines.join("\n"), context, name === "bash" && getBashExitCode(result) !== "0"
|
|
490
|
+
? context.theme.warning
|
|
491
|
+
: context.theme.textMuted);
|
|
492
|
+
}
|
|
493
|
+
function outputPreview(text, context, colorHex, options = {}) {
|
|
494
|
+
const lines = text.split("\n").filter((lineText) => lineText.length > 0);
|
|
495
|
+
const selected = options.tail ? lines.slice(-3) : lines.slice(0, MAX_OUTPUT_LINES);
|
|
496
|
+
const display = selected.map((lineText) => {
|
|
497
|
+
const wrapped = wrapPlain(truncatePlain(lineText, context.columns - 8), context.columns - 8);
|
|
498
|
+
return color(colorHex, wrapped);
|
|
499
|
+
});
|
|
500
|
+
if (lines.length > MAX_OUTPUT_LINES) {
|
|
501
|
+
display.push(dim(context, `… +${lines.length - MAX_OUTPUT_LINES} line${lines.length - MAX_OUTPUT_LINES === 1 ? "" : "s"}`));
|
|
502
|
+
}
|
|
503
|
+
return display;
|
|
504
|
+
}
|
|
505
|
+
function toolHeader(status, label, detail, context, options = {}) {
|
|
506
|
+
const dotColor = status === "error"
|
|
507
|
+
? context.theme.error
|
|
508
|
+
: status === "done"
|
|
509
|
+
? context.theme.success
|
|
510
|
+
: context.theme.primary;
|
|
511
|
+
const labelColor = status === "error" ? context.theme.toolError : context.theme.toolName;
|
|
512
|
+
const detailText = detail
|
|
513
|
+
? color(context.theme.text, options.quoteDetail ? `(${dim(context, '"')}${detail}${dim(context, '"')})` : `(${detail})`)
|
|
514
|
+
: "";
|
|
515
|
+
const suffixText = options.suffix ? dim(context, ` ${options.suffix}`) : "";
|
|
516
|
+
return `${RESPONSE_LEFT_PADDING}${color(dotColor, BLACK_CIRCLE)} ${color(labelColor, label, true)}${detailText}${suffixText}`;
|
|
517
|
+
}
|
|
518
|
+
function stateToolHeader(status, label, detail, inline, context) {
|
|
519
|
+
const suffix = [detail, inline ? `· ${inline}` : ""]
|
|
520
|
+
.filter((value) => value.length > 0)
|
|
521
|
+
.join(" ");
|
|
522
|
+
return `${toolHeader(status, label, "", context)}${suffix ? dim(context, ` ${suffix}`) : ""}`;
|
|
523
|
+
}
|
|
524
|
+
function messageResponse(lines, context) {
|
|
525
|
+
if (lines.length === 0)
|
|
526
|
+
return [];
|
|
527
|
+
const [first, ...rest] = lines;
|
|
528
|
+
return [
|
|
529
|
+
`${RESPONSE_LEFT_PADDING}${dim(context, ` ${RETURN_SYMBOL} `)}${first}`,
|
|
530
|
+
...rest.map((lineText) => `${RESPONSE_LEFT_PADDING}${dim(context, " ")}${lineText}`),
|
|
531
|
+
];
|
|
532
|
+
}
|
|
533
|
+
function prefixFirstLine(text, firstPrefix, nextPrefix) {
|
|
534
|
+
return text
|
|
535
|
+
.split("\n")
|
|
536
|
+
.map((lineText, index) => {
|
|
537
|
+
if (lineText.length === 0)
|
|
538
|
+
return "";
|
|
539
|
+
return `${index === 0 ? firstPrefix : nextPrefix}${lineText}`;
|
|
540
|
+
})
|
|
541
|
+
.join("\n");
|
|
542
|
+
}
|
|
543
|
+
function formatDuration(ms) {
|
|
544
|
+
const totalSec = Math.round(ms / 1000);
|
|
545
|
+
if (totalSec < 60)
|
|
546
|
+
return `${totalSec}s`;
|
|
547
|
+
const min = Math.floor(totalSec / 60);
|
|
548
|
+
const sec = totalSec % 60;
|
|
549
|
+
return sec > 0 ? `${min}m ${sec}s` : `${min}m`;
|
|
550
|
+
}
|
|
551
|
+
function getToolHeaderParts(name, args) {
|
|
552
|
+
const displayName = toolDisplayName(name);
|
|
553
|
+
switch (name) {
|
|
554
|
+
case "bash": {
|
|
555
|
+
const command = String(args.command ?? "");
|
|
556
|
+
const firstLine = command.split("\n")[0] ?? "";
|
|
557
|
+
const detail = firstLine.length > 60 ? `${firstLine.slice(0, 57)}…` : firstLine;
|
|
558
|
+
return { label: displayName, detail: command.includes("\n") ? `${detail} …` : detail };
|
|
559
|
+
}
|
|
560
|
+
case "edit":
|
|
561
|
+
case "write":
|
|
562
|
+
return { label: displayName, detail: shortenPath(String(args.file_path ?? "")) };
|
|
563
|
+
case "read":
|
|
564
|
+
return { label: "Read", detail: shortenPath(String(args.file_path ?? "")) };
|
|
565
|
+
case "grep":
|
|
566
|
+
case "find": {
|
|
567
|
+
const pattern = String(args.pattern ?? "");
|
|
568
|
+
return {
|
|
569
|
+
label: displayName,
|
|
570
|
+
detail: pattern.length > 40 ? `${pattern.slice(0, 37)}…` : pattern,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
case "ls":
|
|
574
|
+
return { label: displayName, detail: shortenPath(String(args.path ?? ".")) };
|
|
575
|
+
case "subagent": {
|
|
576
|
+
const task = String(args.task ?? "");
|
|
577
|
+
return { label: displayName, detail: task.length > 50 ? `${task.slice(0, 47)}…` : task };
|
|
578
|
+
}
|
|
579
|
+
case "skill":
|
|
580
|
+
return { label: displayName, detail: String(args.skill ?? "") };
|
|
581
|
+
case "task_output":
|
|
582
|
+
case "task_stop":
|
|
583
|
+
return { label: displayName, detail: String(args.id ?? "") };
|
|
584
|
+
case "web_search": {
|
|
585
|
+
const query = String(args.query ?? "");
|
|
586
|
+
return { label: "Web Search", detail: query.length > 60 ? `${query.slice(0, 57)}…` : query };
|
|
587
|
+
}
|
|
588
|
+
case "source_path": {
|
|
589
|
+
const packageName = String(args.package ?? "");
|
|
590
|
+
return {
|
|
591
|
+
label: displayName,
|
|
592
|
+
detail: packageName.length > 60 ? `${packageName.slice(0, 57)}…` : packageName,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
case "web_fetch": {
|
|
596
|
+
const url = String(args.url ?? "");
|
|
597
|
+
return { label: displayName, detail: url.length > 60 ? `${url.slice(0, 57)}…` : url };
|
|
598
|
+
}
|
|
599
|
+
case "tasks":
|
|
600
|
+
case "goals":
|
|
601
|
+
return { label: displayName, detail: String(args.action ?? "") };
|
|
602
|
+
default:
|
|
603
|
+
return { label: displayName, detail: name.startsWith("mcp__") ? getMCPDetailArg(args) : "" };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
function toolDisplayName(name) {
|
|
607
|
+
if (name.startsWith("mcp__")) {
|
|
608
|
+
const parts = name.split("__");
|
|
609
|
+
return snakeToTitle(parts[2] ?? parts[1] ?? "mcp");
|
|
610
|
+
}
|
|
611
|
+
switch (name) {
|
|
612
|
+
case "bash":
|
|
613
|
+
return "Bash";
|
|
614
|
+
case "read":
|
|
615
|
+
return "Read";
|
|
616
|
+
case "write":
|
|
617
|
+
return "Write";
|
|
618
|
+
case "edit":
|
|
619
|
+
return "Update";
|
|
620
|
+
case "grep":
|
|
621
|
+
return "Search";
|
|
622
|
+
case "find":
|
|
623
|
+
return "Find";
|
|
624
|
+
case "ls":
|
|
625
|
+
return "List";
|
|
626
|
+
case "subagent":
|
|
627
|
+
return "Agent";
|
|
628
|
+
case "skill":
|
|
629
|
+
return "Skill";
|
|
630
|
+
case "web_fetch":
|
|
631
|
+
return "Fetch";
|
|
632
|
+
case "web_search":
|
|
633
|
+
return "Web Search";
|
|
634
|
+
case "task_output":
|
|
635
|
+
return "Task Output";
|
|
636
|
+
case "task_stop":
|
|
637
|
+
return "Task Stop";
|
|
638
|
+
case "source_path":
|
|
639
|
+
return "Source";
|
|
640
|
+
case "tasks":
|
|
641
|
+
return "Task";
|
|
642
|
+
case "goals":
|
|
643
|
+
return "Goal";
|
|
644
|
+
default:
|
|
645
|
+
return snakeToTitle(name);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function snakeToTitle(value) {
|
|
649
|
+
return value
|
|
650
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
651
|
+
.split("_")
|
|
652
|
+
.filter((word) => word.length > 0)
|
|
653
|
+
.map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1).toLowerCase()}`)
|
|
654
|
+
.join(" ");
|
|
655
|
+
}
|
|
656
|
+
function getMCPDetailArg(args) {
|
|
657
|
+
const entries = Object.entries(args).filter(([, value]) => value !== undefined && value !== null && value !== "");
|
|
658
|
+
if (entries.length === 0)
|
|
659
|
+
return "";
|
|
660
|
+
const preferred = ["query", "prompt", "url", "path", "pattern", "name", "command", "repo"];
|
|
661
|
+
const preferredEntry = preferred
|
|
662
|
+
.map((key) => entries.find(([entryKey]) => entryKey.toLowerCase() === key))
|
|
663
|
+
.find((entry) => entry !== undefined);
|
|
664
|
+
const best = preferredEntry ??
|
|
665
|
+
entries
|
|
666
|
+
.filter(([, value]) => typeof value === "string")
|
|
667
|
+
.sort((a, b) => String(a[1]).length - String(b[1]).length)[0] ??
|
|
668
|
+
entries[0];
|
|
669
|
+
const value = String(best?.[1] ?? "");
|
|
670
|
+
return value.length > 50 ? `${value.slice(0, 47)}…` : value;
|
|
671
|
+
}
|
|
672
|
+
function getCompactRunningLabel(name, args) {
|
|
673
|
+
switch (name) {
|
|
674
|
+
case "grep":
|
|
675
|
+
return "Searching…";
|
|
676
|
+
case "read":
|
|
677
|
+
return "Reading…";
|
|
678
|
+
case "find":
|
|
679
|
+
return "Finding files…";
|
|
680
|
+
case "ls":
|
|
681
|
+
return "Listing…";
|
|
682
|
+
case "source_path": {
|
|
683
|
+
const packageName = String(args.package ?? "");
|
|
684
|
+
return `Resolving source${packageName ? ` for ${packageName}` : ""}…`;
|
|
685
|
+
}
|
|
686
|
+
default:
|
|
687
|
+
return `${name}…`;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function getCompactDoneLabel(name, args, result) {
|
|
691
|
+
switch (name) {
|
|
692
|
+
case "grep": {
|
|
693
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
694
|
+
const matchCount = lines.filter((lineText) => !/^\d+ match|^\[Truncated/.test(lineText)).length;
|
|
695
|
+
return `Searched for 1 pattern${matchCount > 0 ? ` (${matchCount} match${matchCount !== 1 ? "es" : ""})` : ""}`;
|
|
696
|
+
}
|
|
697
|
+
case "read":
|
|
698
|
+
return `Read ${shortenPath(String(args.file_path ?? ""))}`;
|
|
699
|
+
case "find": {
|
|
700
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
701
|
+
return `Found ${lines.length} file${lines.length !== 1 ? "s" : ""}`;
|
|
702
|
+
}
|
|
703
|
+
case "ls": {
|
|
704
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
705
|
+
return `Listed ${lines.length} item${lines.length !== 1 ? "s" : ""}`;
|
|
706
|
+
}
|
|
707
|
+
case "source_path": {
|
|
708
|
+
const packageName = String(args.package ?? "source");
|
|
709
|
+
const sourcePath = extractSourcePath(result);
|
|
710
|
+
return `Resolved ${packageName} → ${sourcePath ? shortenPath(sourcePath) : "source path"}`;
|
|
711
|
+
}
|
|
712
|
+
default:
|
|
713
|
+
return name;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
function getInlineSummary(name, result, isError) {
|
|
717
|
+
if (isError) {
|
|
718
|
+
const firstLine = result.split("\n")[0] ?? "";
|
|
719
|
+
return firstLine.length > 60 ? `${firstLine.slice(0, 57)}…` : firstLine;
|
|
720
|
+
}
|
|
721
|
+
switch (name) {
|
|
722
|
+
case "read": {
|
|
723
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
724
|
+
return `${lines.length} line${lines.length !== 1 ? "s" : ""}`;
|
|
725
|
+
}
|
|
726
|
+
case "write":
|
|
727
|
+
return result.match(/^Wrote \d+ lines?/)?.[0] ?? result.split("\n")[0] ?? "";
|
|
728
|
+
case "bash": {
|
|
729
|
+
const exitCode = result.match(/^Exit code: (.+)/)?.[1];
|
|
730
|
+
return exitCode ? `exit ${exitCode}` : "done";
|
|
731
|
+
}
|
|
732
|
+
case "subagent":
|
|
733
|
+
return "completed";
|
|
734
|
+
case "skill":
|
|
735
|
+
return result.startsWith("Error") ? (result.split("\n")[0] ?? "") : "loaded";
|
|
736
|
+
case "web_fetch": {
|
|
737
|
+
if (result.startsWith("Error"))
|
|
738
|
+
return result.split("\n")[0] ?? "";
|
|
739
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
740
|
+
return `${lines.length} line${lines.length !== 1 ? "s" : ""}`;
|
|
741
|
+
}
|
|
742
|
+
case "source_path":
|
|
743
|
+
return extractSourcePath(result) ? shortenPath(extractSourcePath(result) ?? "") : "resolved";
|
|
744
|
+
case "task_stop":
|
|
745
|
+
return result.split("\n")[0] ?? "stopped";
|
|
746
|
+
case "tasks":
|
|
747
|
+
case "goals": {
|
|
748
|
+
const quoted = result.match(/"([^"]+)"/)?.[1];
|
|
749
|
+
if (quoted)
|
|
750
|
+
return quoted.length > 50 ? `${quoted.slice(0, 47)}…` : quoted;
|
|
751
|
+
const firstLine = result.split("\n")[0] ?? "";
|
|
752
|
+
return firstLine.length > 60 ? `${firstLine.slice(0, 57)}…` : firstLine;
|
|
753
|
+
}
|
|
754
|
+
default: {
|
|
755
|
+
if (!name.startsWith("mcp__"))
|
|
756
|
+
return "";
|
|
757
|
+
const lines = result.split("\n").filter((lineText) => lineText.length > 0);
|
|
758
|
+
if (lines.length === 0)
|
|
759
|
+
return "no results";
|
|
760
|
+
const first = lines[0] ?? "";
|
|
761
|
+
return lines.length === 1
|
|
762
|
+
? first.length > 50
|
|
763
|
+
? `${first.slice(0, 47)}…`
|
|
764
|
+
: first
|
|
765
|
+
: `${lines.length} lines`;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
function shortenPath(filePath) {
|
|
770
|
+
const parts = filePath.split("/");
|
|
771
|
+
if (parts.length <= 3)
|
|
772
|
+
return filePath;
|
|
773
|
+
return `…/${parts.slice(-2).join("/")}`;
|
|
774
|
+
}
|
|
775
|
+
function extractSourcePath(result) {
|
|
776
|
+
return result.match(/^Source path:\s*(.+)$/m)?.[1]?.trim();
|
|
777
|
+
}
|
|
778
|
+
function getServerToolHeaderParts(name, input) {
|
|
779
|
+
const values = input && typeof input === "object" ? input : {};
|
|
780
|
+
if (name === "web_search") {
|
|
781
|
+
const query = String(values.query ?? "");
|
|
782
|
+
return { label: "Web Search", detail: query.length > 60 ? `${query.slice(0, 57)}…` : query };
|
|
783
|
+
}
|
|
784
|
+
return { label: name, detail: "" };
|
|
785
|
+
}
|
|
786
|
+
function getBashExitCode(result) {
|
|
787
|
+
return result.match(/^Exit code: (.+)/)?.[1]?.trim() ?? "0";
|
|
788
|
+
}
|
|
789
|
+
function extractDiff(result) {
|
|
790
|
+
return result.includes("---") && result.includes("+++") ? result : undefined;
|
|
791
|
+
}
|
|
792
|
+
function renderDiffPreview(diff, args, context) {
|
|
793
|
+
const added = (diff.match(/^\+[^+]/gm) ?? []).length;
|
|
794
|
+
const removed = (diff.match(/^-[^-]/gm) ?? []).length;
|
|
795
|
+
const lines = [
|
|
796
|
+
dim(context, `Added ${added} line${added !== 1 ? "s" : ""}, removed ${removed} line${removed !== 1 ? "s" : ""}`),
|
|
797
|
+
];
|
|
798
|
+
const diffLines = buildDiffLines(diff, String(args.file_path ?? ""), context);
|
|
799
|
+
if (diffLines.length > 0) {
|
|
800
|
+
lines.push(dim(context, "────────────────────────────────────────────────────────────────"));
|
|
801
|
+
lines.push(...diffLines);
|
|
802
|
+
lines.push(dim(context, "────────────────────────────────────────────────────────────────"));
|
|
803
|
+
}
|
|
804
|
+
const hiddenCount = Math.max(0, countDisplayDiffLines(diff) + 1 - (diffLines.length + 1));
|
|
805
|
+
if (hiddenCount > 0)
|
|
806
|
+
lines.push(dim(context, `… +${hiddenCount} lines`));
|
|
807
|
+
return lines;
|
|
808
|
+
}
|
|
809
|
+
function countDisplayDiffLines(diff) {
|
|
810
|
+
return diff
|
|
811
|
+
.split("\n")
|
|
812
|
+
.filter((lineText) => !lineText.startsWith("---") && !lineText.startsWith("+++") && !lineText.startsWith("@@")).length;
|
|
813
|
+
}
|
|
814
|
+
function buildDiffLines(diff, filePath, context) {
|
|
815
|
+
const lang = langFromFilePath(filePath);
|
|
816
|
+
const displayLines = diff
|
|
817
|
+
.split("\n")
|
|
818
|
+
.filter((lineText) => !lineText.startsWith("---") && !lineText.startsWith("+++") && !lineText.startsWith("@@"))
|
|
819
|
+
.slice(0, MAX_OUTPUT_LINES);
|
|
820
|
+
return displayLines.map((lineText, index) => {
|
|
821
|
+
const marker = lineText[0] === "+" || lineText[0] === "-" ? lineText[0] : " ";
|
|
822
|
+
const content = truncatePlain(lineText.slice(marker === " " ? 0 : 1), Math.max(10, context.columns - 12));
|
|
823
|
+
const lineNo = String(index + 1).padStart(2, " ");
|
|
824
|
+
if (marker === "+")
|
|
825
|
+
return chalk.bgHex("#16a34a").hex("#ffffff")(`${lineNo} + ${content}`);
|
|
826
|
+
if (marker === "-")
|
|
827
|
+
return chalk.bgHex("#dc2626").hex("#ffffff")(`${lineNo} - ${content}`);
|
|
828
|
+
return `${color(context.theme.textDim, `${lineNo} `)}${colorCode(content, lang, context)}`;
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
function langFromFilePath(filePath) {
|
|
832
|
+
if (/\.tsx?$/.test(filePath))
|
|
833
|
+
return "ts";
|
|
834
|
+
if (/\.jsx?$/.test(filePath))
|
|
835
|
+
return "js";
|
|
836
|
+
if (/\.json$/.test(filePath))
|
|
837
|
+
return "json";
|
|
838
|
+
return "text";
|
|
839
|
+
}
|
|
840
|
+
function colorCode(text, lang, context) {
|
|
841
|
+
if (lang === "text")
|
|
842
|
+
return color(context.theme.text, text);
|
|
843
|
+
return color(context.theme.text, text);
|
|
844
|
+
}
|
|
845
|
+
function formatCompactTokens(n) {
|
|
846
|
+
if (n >= 1_000_000)
|
|
847
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
848
|
+
if (n >= 1_000)
|
|
849
|
+
return `${(n / 1_000).toFixed(1)}k`;
|
|
850
|
+
return String(n);
|
|
851
|
+
}
|
|
852
|
+
function formatTokenCount(n) {
|
|
853
|
+
if (n >= 1000) {
|
|
854
|
+
const k = n / 1000;
|
|
855
|
+
return k >= 10 ? `${Math.round(k)}k` : `${k.toFixed(1)}k`;
|
|
856
|
+
}
|
|
857
|
+
return String(n);
|
|
858
|
+
}
|
|
859
|
+
function block(lines) {
|
|
860
|
+
return lines.filter((lineText) => lineText.length > 0).join("\n");
|
|
861
|
+
}
|
|
862
|
+
function line(context, colorHex, text, bold = false) {
|
|
863
|
+
return color(colorHex, wrapPlain(text, context.columns), bold);
|
|
864
|
+
}
|
|
865
|
+
function wrapPlain(text, width) {
|
|
866
|
+
return wrapAnsi(text, Math.max(10, width), { hard: true, wordWrap: true });
|
|
867
|
+
}
|
|
868
|
+
function indent(text, prefix) {
|
|
869
|
+
return text
|
|
870
|
+
.split("\n")
|
|
871
|
+
.map((lineText) => `${prefix}${lineText}`)
|
|
872
|
+
.join("\n");
|
|
873
|
+
}
|
|
874
|
+
function truncatePlain(text, width) {
|
|
875
|
+
const max = Math.max(1, width);
|
|
876
|
+
if (stringWidth(text) <= max)
|
|
877
|
+
return text;
|
|
878
|
+
let result = "";
|
|
879
|
+
for (const char of text) {
|
|
880
|
+
if (stringWidth(`${result}${char}…`) > max)
|
|
881
|
+
break;
|
|
882
|
+
result += char;
|
|
883
|
+
}
|
|
884
|
+
return `${result}…`;
|
|
885
|
+
}
|
|
886
|
+
function color(hex, text, bold = false) {
|
|
887
|
+
const styled = chalk.hex(hex)(text);
|
|
888
|
+
return bold ? chalk.bold(styled) : styled;
|
|
889
|
+
}
|
|
890
|
+
function userChipSegment(text, foregroundHex, bold = false) {
|
|
891
|
+
const styled = chalk.bgHex(USER_MESSAGE_BACKGROUND).hex(foregroundHex)(text);
|
|
892
|
+
return bold ? chalk.bold(styled) : styled;
|
|
893
|
+
}
|
|
894
|
+
function dim(context, text) {
|
|
895
|
+
return color(context.theme.textDim, text);
|
|
896
|
+
}
|
|
897
|
+
function gradientLine(text) {
|
|
898
|
+
let colorIndex = 0;
|
|
899
|
+
let result = "";
|
|
900
|
+
for (const char of text) {
|
|
901
|
+
if (char === " ") {
|
|
902
|
+
result += char;
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
result += chalk.hex(GRADIENT[colorIndex % GRADIENT.length] ?? GRADIENT[0])(char);
|
|
906
|
+
colorIndex++;
|
|
907
|
+
}
|
|
908
|
+
return result;
|
|
909
|
+
}
|
|
910
|
+
//# sourceMappingURL=terminal-history.js.map
|