centaurus-cli 3.1.3 → 3.1.4
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/cli-adapter.js +685 -153
- package/dist/cli-adapter.js.map +1 -1
- package/dist/config/defaultConfig.js +1 -4
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/models.js +4 -0
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +66 -2
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +4 -4
- package/dist/config/types.js.map +1 -1
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-context-injector.js +109 -0
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/background-task-manager.js +59 -0
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/local-chat-storage.js +2 -0
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/skill-storage.js +141 -0
- package/dist/services/skill-storage.js.map +1 -0
- package/dist/services/sub-agent-manager.js +49 -8
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +17 -5
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/tools/background-command.js +5 -2
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +367 -109
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/file-ops.js +23 -6
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/plan-mode.js +184 -336
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/sub-agent.js +24 -5
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/todo-list.js +157 -0
- package/dist/tools/todo-list.js.map +1 -0
- package/dist/types/skill.js +30 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/ui/components/App.js +956 -162
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +3 -1
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +3 -1
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +3 -1
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/CompactShellPreview.js +44 -0
- package/dist/ui/components/CompactShellPreview.js.map +1 -0
- package/dist/ui/components/ConfigViewer.js +3 -1
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +3 -1
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +3 -1
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +6 -3
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +4 -2
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/InputBox.js +243 -40
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +5 -3
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +4 -1
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +3 -1
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +63 -13
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +3 -1
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +9 -7
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/ModelPicker.js +170 -0
- package/dist/ui/components/ModelPicker.js.map +1 -0
- package/dist/ui/components/MonitorModeAIPanel.js +3 -1
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +12 -6
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanQuestionMessage.js +37 -0
- package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
- package/dist/ui/components/PlanQuestionScreen.js +138 -0
- package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
- package/dist/ui/components/PlanReviewScreen.js +7 -9
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +65 -28
- package/dist/ui/components/RulesEditorScreen.js.map +1 -1
- package/dist/ui/components/SelectPrompt.js +3 -1
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/SkillCreatorScreen.js +217 -0
- package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +4 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +5 -3
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/SubAgentListScreen.js +65 -0
- package/dist/ui/components/SubAgentListScreen.js.map +1 -0
- package/dist/ui/components/SubAgentViewScreen.js +123 -0
- package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
- package/dist/ui/components/TaskCompletedMessage.js +40 -8
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +6 -4
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/TextEditor.js +297 -0
- package/dist/ui/components/TextEditor.js.map +1 -0
- package/dist/ui/components/TodoListMessage.js +59 -0
- package/dist/ui/components/TodoListMessage.js.map +1 -0
- package/dist/ui/components/ToolExecutionMessage.js +134 -84
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +3 -1
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +33 -33
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/ui/theme.js +97 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/utils/chat-history-limit.js +247 -0
- package/dist/ui/utils/chat-history-limit.js.map +1 -0
- package/dist/utils/chat-formatter.js +22 -9
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/input-classifier.js +11 -1
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/output-truncation.js +175 -0
- package/dist/utils/output-truncation.js.map +1 -0
- package/dist/utils/rule-reference-resolver.js +3 -3
- package/dist/utils/rule-reference-resolver.js.map +1 -1
- package/dist/utils/tunnel-commands-manager.js +134 -0
- package/dist/utils/tunnel-commands-manager.js.map +1 -0
- package/package.json +91 -90
- package/postinstall.js +4 -11
- package/dist/ui/components/MultiLineInput.js +0 -255
- package/dist/ui/components/MultiLineInput.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/ui/theme.ts"],"sourcesContent":["/**\r\n * Centralized theme system for Centaurus CLI.\r\n *\r\n * Every UI component imports `getThemeColors()` (or the React hook `useTheme()`)\r\n * instead of hard-coding hex values. When the user changes the accent color via\r\n * `/settings theme`, the singleton is updated and React state propagation ensures\r\n * all mounted components re-render with the new palette.\r\n */\r\n\r\nimport React from 'react';\r\n\r\n// ── Default accent (the existing blue) ──────────────────────────────\r\nexport const DEFAULT_ACCENT_COLOR = '#00ccff';\r\n\r\n// ── Color palette choices ───────────────────────────────────────────\r\nexport interface ThemeOption {\r\n name: string;\r\n value: string; // hex accent\r\n label: string; // display name with swatch\r\n}\r\n\r\nexport const THEME_PALETTE: ThemeOption[] = [\r\n { name: 'blue', value: '#00ccff', label: '████ Ocean Blue' },\r\n { name: 'cyan', value: '#00ddbb', label: '████ Cyan Teal' },\r\n { name: 'green', value: '#00cc88', label: '████ Emerald Green' },\r\n { name: 'lime', value: '#88cc00', label: '████ Lime' },\r\n { name: 'yellow', value: '#ffcc00', label: '████ Golden Yellow' },\r\n { name: 'orange', value: '#ff8844', label: '████ Sunset Orange' },\r\n { name: 'red', value: '#ff4466', label: '████ Ruby Red' },\r\n { name: 'pink', value: '#ff66aa', label: '████ Pink' },\r\n { name: 'violet', value: '#aa66ff', label: '████ Violet Purple' },\r\n { name: 'sky', value: '#4499ff', label: '████ Sky Blue' },\r\n];\r\n\r\n// ── HSL helpers ─────────────────────────────────────────────────────\r\n\r\nfunction hexToHsl(hex: string): [number, number, number] {\r\n const r = parseInt(hex.slice(1, 3), 16) / 255;\r\n const g = parseInt(hex.slice(3, 5), 16) / 255;\r\n const b = parseInt(hex.slice(5, 7), 16) / 255;\r\n\r\n const max = Math.max(r, g, b);\r\n const min = Math.min(r, g, b);\r\n const l = (max + min) / 2;\r\n let h = 0;\r\n let s = 0;\r\n\r\n if (max !== min) {\r\n const d = max - min;\r\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\r\n if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;\r\n else if (max === g) h = ((b - r) / d + 2) / 6;\r\n else h = ((r - g) / d + 4) / 6;\r\n }\r\n\r\n return [h * 360, s * 100, l * 100];\r\n}\r\n\r\nfunction hslToHex(h: number, s: number, l: number): string {\r\n h /= 360; s /= 100; l /= 100;\r\n const hue2rgb = (p: number, q: number, t: number) => {\r\n if (t < 0) t += 1; if (t > 1) t -= 1;\r\n if (t < 1 / 6) return p + (q - p) * 6 * t;\r\n if (t < 1 / 2) return q;\r\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\r\n return p;\r\n };\r\n\r\n let r: number, g: number, b: number;\r\n if (s === 0) {\r\n r = g = b = l;\r\n } else {\r\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\r\n const p = 2 * l - q;\r\n r = hue2rgb(p, q, h + 1 / 3);\r\n g = hue2rgb(p, q, h);\r\n b = hue2rgb(p, q, h - 1 / 3);\r\n }\r\n\r\n const toHex = (n: number) => Math.round(n * 255).toString(16).padStart(2, '0');\r\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`;\r\n}\r\n\r\n// ── Derived color palette ───────────────────────────────────────────\r\n\r\nexport interface ThemeColors {\r\n /** Primary accent — the bright user-chosen color (replaces #00ccff) */\r\n accent: string;\r\n /** Slightly muted accent (replaces #00aacc) */\r\n accentMuted: string;\r\n /** Input box / component border (replaces #257aa5) */\r\n border: string;\r\n /** Section divider / subtle border (replaces #1a5a7a) */\r\n borderDim: string;\r\n /** Faint divider (replaces #1a4a6a) */\r\n divider: string;\r\n /** Very dark background accent (replaces #003b59) */\r\n bgAccent: string;\r\n}\r\n\r\nexport function deriveThemeColors(accent: string): ThemeColors {\r\n const [h, s, l] = hexToHsl(accent.slice(0, 7)); // strip alpha if present\r\n\r\n return {\r\n accent,\r\n accentMuted: hslToHex(h, Math.max(s * 0.85, 30), l * 0.82),\r\n border: hslToHex(h, Math.max(s * 0.65, 25), Math.min(l * 0.52, 42)),\r\n borderDim: hslToHex(h, Math.max(s * 0.60, 20), Math.min(l * 0.40, 32)),\r\n divider: hslToHex(h, Math.max(s * 0.55, 18), Math.min(l * 0.35, 28)),\r\n bgAccent: hslToHex(h, Math.max(s * 0.70, 25), Math.min(l * 0.25, 20)),\r\n };\r\n}\r\n\r\n// ── Singleton (for non-React code like WelcomeBanner static render) ─\r\n\r\nlet _accentColor = DEFAULT_ACCENT_COLOR;\r\nlet _themeColors = deriveThemeColors(DEFAULT_ACCENT_COLOR);\r\n\r\nexport function setGlobalAccentColor(color: string): void {\r\n _accentColor = color;\r\n _themeColors = deriveThemeColors(color);\r\n}\r\n\r\nexport function getAccentColor(): string {\r\n return _accentColor;\r\n}\r\n\r\nexport function getThemeColors(): ThemeColors {\r\n return _themeColors;\r\n}\r\n\r\n// ── React Context ───────────────────────────────────────────────────\r\n\r\nexport const ThemeContext = React.createContext<ThemeColors>(\r\n deriveThemeColors(DEFAULT_ACCENT_COLOR)\r\n);\r\n\r\nexport function useTheme(): ThemeColors {\r\n return React.useContext(ThemeContext);\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import v8 from "v8";
|
|
3
|
+
import wrapAnsi from "wrap-ansi";
|
|
4
|
+
const KB = 1024;
|
|
5
|
+
const MB = 1024 * KB;
|
|
6
|
+
const FILE_MARKER_REGEX = /\[(IMAGE|FILE):\s*[^\]]+?\s*\((gs:\/\/[^\)]+|upload failed[^\)]*|uploading[^\)]*)\)\]/g;
|
|
7
|
+
const CHAT_HISTORY_LIMIT_DEFAULTS = {
|
|
8
|
+
maxHeadroomShare: 5e-3,
|
|
9
|
+
maxProcessRssShare: 0.5,
|
|
10
|
+
minRenderBudgetBytes: 768 * KB,
|
|
11
|
+
maxRenderBudgetBytes: 8 * MB,
|
|
12
|
+
minLineLimit: 250,
|
|
13
|
+
maxLineLimit: 4e3,
|
|
14
|
+
minTerminalWidth: 20,
|
|
15
|
+
minEstimatedBytesPerLine: 1024,
|
|
16
|
+
estimatedBytesPerColumn: 16
|
|
17
|
+
};
|
|
18
|
+
function clamp(value, min, max) {
|
|
19
|
+
return Math.min(max, Math.max(min, value));
|
|
20
|
+
}
|
|
21
|
+
function normalizePositive(value) {
|
|
22
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
23
|
+
}
|
|
24
|
+
function stripFileMarkers(content) {
|
|
25
|
+
return content.replace(FILE_MARKER_REGEX, "").trim();
|
|
26
|
+
}
|
|
27
|
+
function countFileMarkers(content) {
|
|
28
|
+
return content.match(FILE_MARKER_REGEX)?.length ?? 0;
|
|
29
|
+
}
|
|
30
|
+
function getChatHistoryMemorySnapshot() {
|
|
31
|
+
const usage = process.memoryUsage();
|
|
32
|
+
const heapStats = v8.getHeapStatistics();
|
|
33
|
+
return {
|
|
34
|
+
processAvailableMemory: typeof process.availableMemory === "function" ? process.availableMemory() : os.freemem(),
|
|
35
|
+
systemFreeMemory: os.freemem(),
|
|
36
|
+
systemTotalMemory: os.totalmem(),
|
|
37
|
+
processRss: usage.rss,
|
|
38
|
+
processHeapUsed: usage.heapUsed,
|
|
39
|
+
v8AvailableHeap: heapStats.total_available_size,
|
|
40
|
+
v8HeapLimit: heapStats.heap_size_limit
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function countWrappedVisualLines(text, width) {
|
|
44
|
+
if (!text) {
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
const safeWidth = Math.max(1, Math.floor(width));
|
|
48
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
49
|
+
return normalized.split("\n").reduce((total, line) => {
|
|
50
|
+
const wrapped = wrapAnsi(line.length > 0 ? line : " ", safeWidth, {
|
|
51
|
+
hard: true,
|
|
52
|
+
trim: false
|
|
53
|
+
});
|
|
54
|
+
return total + wrapped.split("\n").length;
|
|
55
|
+
}, 0);
|
|
56
|
+
}
|
|
57
|
+
function estimateUserAttachmentBadgeRows(content, width) {
|
|
58
|
+
const fileCount = countFileMarkers(content);
|
|
59
|
+
if (fileCount === 0) {
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
const safeWidth = Math.max(20, width);
|
|
63
|
+
const badgesPerRow = Math.max(1, Math.floor((safeWidth - 2) / 18));
|
|
64
|
+
return Math.ceil(fileCount / badgesPerRow);
|
|
65
|
+
}
|
|
66
|
+
function estimateToolMessageLines(message, width) {
|
|
67
|
+
if (!message.toolExecution) {
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
const renderWidth = Math.max(20, width - 8);
|
|
71
|
+
const details = [
|
|
72
|
+
`Tool: ${message.toolExecution.toolName}`,
|
|
73
|
+
`Status: ${message.toolExecution.status}`,
|
|
74
|
+
message.toolExecution.arguments ? `Args: ${JSON.stringify(message.toolExecution.arguments)}` : "",
|
|
75
|
+
message.toolExecution.error || message.toolExecution.result || ""
|
|
76
|
+
].filter(Boolean).join("\n");
|
|
77
|
+
return 2 + countWrappedVisualLines(details, renderWidth) + 1;
|
|
78
|
+
}
|
|
79
|
+
function estimateConnectionStatusLines(message, width) {
|
|
80
|
+
if (!message.connectionStatus) {
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
const renderWidth = Math.max(20, width - 6);
|
|
84
|
+
const details = [
|
|
85
|
+
`${message.connectionStatus.type.toUpperCase()} ${message.connectionStatus.status}`,
|
|
86
|
+
message.connectionStatus.connectionString || "",
|
|
87
|
+
message.connectionStatus.error || ""
|
|
88
|
+
].filter(Boolean).join("\n");
|
|
89
|
+
return 2 + countWrappedVisualLines(details, renderWidth) + 1;
|
|
90
|
+
}
|
|
91
|
+
function estimateTaskCompletionLines(message, width) {
|
|
92
|
+
if (!message.taskCompletion) {
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
const stepLines = message.taskCompletion.allSteps?.length ?? 1;
|
|
96
|
+
const noteLines = message.taskCompletion.completionNote ? countWrappedVisualLines(message.taskCompletion.completionNote, Math.max(20, width - 6)) : 0;
|
|
97
|
+
return 2 + stepLines + noteLines + 1;
|
|
98
|
+
}
|
|
99
|
+
function estimateTodoListLines(message) {
|
|
100
|
+
if (!message.todoList) {
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
return 2 + message.todoList.todos.length + 1;
|
|
104
|
+
}
|
|
105
|
+
function estimatePlanAcceptedLines(message) {
|
|
106
|
+
if (!message.planAccepted) {
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
return 2 + (message.planAccepted.steps?.length ?? 0) + 1;
|
|
110
|
+
}
|
|
111
|
+
function estimatePlanQuestionLines(message, width) {
|
|
112
|
+
if (!message.planQuestion) {
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
const renderWidth = Math.max(20, width - 6);
|
|
116
|
+
const answerLines = message.planQuestion.userAnswer ? countWrappedVisualLines(message.planQuestion.userAnswer, renderWidth) : 0;
|
|
117
|
+
return 2 + countWrappedVisualLines(message.planQuestion.question, renderWidth) + message.planQuestion.options.length + answerLines + 1;
|
|
118
|
+
}
|
|
119
|
+
function estimateMessageVisualLines(message, width) {
|
|
120
|
+
if (message.approval) {
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
if (message.toolExecution) {
|
|
124
|
+
return estimateToolMessageLines(message, width);
|
|
125
|
+
}
|
|
126
|
+
if (message.connectionStatus) {
|
|
127
|
+
return estimateConnectionStatusLines(message, width);
|
|
128
|
+
}
|
|
129
|
+
if (message.taskCompletion) {
|
|
130
|
+
return estimateTaskCompletionLines(message, width);
|
|
131
|
+
}
|
|
132
|
+
if (message.todoList) {
|
|
133
|
+
return estimateTodoListLines(message);
|
|
134
|
+
}
|
|
135
|
+
if (message.planAccepted) {
|
|
136
|
+
return estimatePlanAcceptedLines(message);
|
|
137
|
+
}
|
|
138
|
+
if (message.planQuestion) {
|
|
139
|
+
return estimatePlanQuestionLines(message, width);
|
|
140
|
+
}
|
|
141
|
+
if (message.role === "assistant" && !message.content.trim() && message.thinkingDuration === void 0) {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
const safeWidth = Math.max(CHAT_HISTORY_LIMIT_DEFAULTS.minTerminalWidth, Math.floor(width));
|
|
145
|
+
const contentWidth = message.role === "assistant" ? Math.max(20, safeWidth - 6) : Math.max(20, safeWidth - 4);
|
|
146
|
+
const visibleContent = message.role === "user" && !message.isCommandMode ? stripFileMarkers(message.content) : message.content;
|
|
147
|
+
let total = 0;
|
|
148
|
+
if (!message.isSpacer) {
|
|
149
|
+
total += 1;
|
|
150
|
+
}
|
|
151
|
+
if (message.thinkingDuration !== void 0 && message.thinkingDuration >= 0) {
|
|
152
|
+
total += 1;
|
|
153
|
+
}
|
|
154
|
+
if (visibleContent.trim()) {
|
|
155
|
+
total += countWrappedVisualLines(visibleContent, contentWidth);
|
|
156
|
+
}
|
|
157
|
+
if (message.role === "user" && !message.isCommandMode) {
|
|
158
|
+
total += estimateUserAttachmentBadgeRows(message.content, safeWidth);
|
|
159
|
+
}
|
|
160
|
+
return total + 1;
|
|
161
|
+
}
|
|
162
|
+
function calculateChatHistoryLineLimit({
|
|
163
|
+
width,
|
|
164
|
+
memory = getChatHistoryMemorySnapshot(),
|
|
165
|
+
lineLimitOverride
|
|
166
|
+
}) {
|
|
167
|
+
if (typeof lineLimitOverride === "number" && Number.isFinite(lineLimitOverride)) {
|
|
168
|
+
return Math.max(1, Math.floor(lineLimitOverride));
|
|
169
|
+
}
|
|
170
|
+
const safeWidth = Math.max(
|
|
171
|
+
CHAT_HISTORY_LIMIT_DEFAULTS.minTerminalWidth,
|
|
172
|
+
Math.floor(width || 80)
|
|
173
|
+
);
|
|
174
|
+
const headroomCandidates = [
|
|
175
|
+
normalizePositive(memory.processAvailableMemory),
|
|
176
|
+
normalizePositive(memory.systemFreeMemory),
|
|
177
|
+
normalizePositive(memory.v8AvailableHeap)
|
|
178
|
+
].filter((value) => value !== null);
|
|
179
|
+
const headroomBytes = headroomCandidates.length > 0 ? Math.min(...headroomCandidates) : CHAT_HISTORY_LIMIT_DEFAULTS.minRenderBudgetBytes;
|
|
180
|
+
const processRss = normalizePositive(memory.processRss) ?? 32 * MB;
|
|
181
|
+
const renderBudgetBytes = clamp(
|
|
182
|
+
Math.min(
|
|
183
|
+
headroomBytes * CHAT_HISTORY_LIMIT_DEFAULTS.maxHeadroomShare,
|
|
184
|
+
processRss * CHAT_HISTORY_LIMIT_DEFAULTS.maxProcessRssShare
|
|
185
|
+
),
|
|
186
|
+
CHAT_HISTORY_LIMIT_DEFAULTS.minRenderBudgetBytes,
|
|
187
|
+
CHAT_HISTORY_LIMIT_DEFAULTS.maxRenderBudgetBytes
|
|
188
|
+
);
|
|
189
|
+
const estimatedBytesPerLine = Math.max(
|
|
190
|
+
CHAT_HISTORY_LIMIT_DEFAULTS.minEstimatedBytesPerLine,
|
|
191
|
+
safeWidth * CHAT_HISTORY_LIMIT_DEFAULTS.estimatedBytesPerColumn
|
|
192
|
+
);
|
|
193
|
+
return clamp(
|
|
194
|
+
Math.floor(renderBudgetBytes / estimatedBytesPerLine),
|
|
195
|
+
CHAT_HISTORY_LIMIT_DEFAULTS.minLineLimit,
|
|
196
|
+
CHAT_HISTORY_LIMIT_DEFAULTS.maxLineLimit
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
function limitChatHistoryForDisplay(history, options = {}) {
|
|
200
|
+
const {
|
|
201
|
+
enabled = true,
|
|
202
|
+
width = process.stdout.columns || 120,
|
|
203
|
+
memory,
|
|
204
|
+
lineLimitOverride
|
|
205
|
+
} = options;
|
|
206
|
+
const lineLimit = calculateChatHistoryLineLimit({
|
|
207
|
+
width,
|
|
208
|
+
memory,
|
|
209
|
+
lineLimitOverride
|
|
210
|
+
});
|
|
211
|
+
if (!enabled || history.length === 0) {
|
|
212
|
+
return {
|
|
213
|
+
visibleMessages: history,
|
|
214
|
+
hiddenMessageCount: 0,
|
|
215
|
+
visibleLineCount: history.reduce(
|
|
216
|
+
(total, message) => total + estimateMessageVisualLines(message, width),
|
|
217
|
+
0
|
|
218
|
+
),
|
|
219
|
+
lineLimit
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
let totalLines = 0;
|
|
223
|
+
let startIndex = history.length;
|
|
224
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
225
|
+
const messageLines = estimateMessageVisualLines(history[i], width);
|
|
226
|
+
if (startIndex < history.length && totalLines + messageLines > lineLimit) {
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
totalLines += messageLines;
|
|
230
|
+
startIndex = i;
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
visibleMessages: history.slice(startIndex),
|
|
234
|
+
hiddenMessageCount: startIndex,
|
|
235
|
+
visibleLineCount: totalLines,
|
|
236
|
+
lineLimit
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
export {
|
|
240
|
+
CHAT_HISTORY_LIMIT_DEFAULTS,
|
|
241
|
+
calculateChatHistoryLineLimit,
|
|
242
|
+
countWrappedVisualLines,
|
|
243
|
+
estimateMessageVisualLines,
|
|
244
|
+
getChatHistoryMemorySnapshot,
|
|
245
|
+
limitChatHistoryForDisplay
|
|
246
|
+
};
|
|
247
|
+
//# sourceMappingURL=chat-history-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/utils/chat-history-limit.ts"],"sourcesContent":["import os from 'os';\r\nimport v8 from 'v8';\r\nimport wrapAnsi from 'wrap-ansi';\r\nimport { Message } from '../../types/index.js';\r\n\r\nconst KB = 1024;\r\nconst MB = 1024 * KB;\r\nconst FILE_MARKER_REGEX = /\\[(IMAGE|FILE):\\s*[^\\]]+?\\s*\\((gs:\\/\\/[^\\)]+|upload failed[^\\)]*|uploading[^\\)]*)\\)\\]/g;\r\n\r\nexport interface ChatHistoryMemorySnapshot {\r\n processAvailableMemory: number;\r\n systemFreeMemory: number;\r\n systemTotalMemory: number;\r\n processRss: number;\r\n processHeapUsed: number;\r\n v8AvailableHeap: number;\r\n v8HeapLimit: number;\r\n}\r\n\r\nexport interface ChatHistoryLimitOptions {\r\n enabled?: boolean;\r\n width?: number;\r\n memory?: ChatHistoryMemorySnapshot;\r\n lineLimitOverride?: number;\r\n}\r\n\r\nexport interface ChatHistoryLimitResult {\r\n visibleMessages: Message[];\r\n hiddenMessageCount: number;\r\n visibleLineCount: number;\r\n lineLimit: number;\r\n}\r\n\r\nexport const CHAT_HISTORY_LIMIT_DEFAULTS = {\r\n maxHeadroomShare: 0.005,\r\n maxProcessRssShare: 0.5,\r\n minRenderBudgetBytes: 768 * KB,\r\n maxRenderBudgetBytes: 8 * MB,\r\n minLineLimit: 250,\r\n maxLineLimit: 4000,\r\n minTerminalWidth: 20,\r\n minEstimatedBytesPerLine: 1024,\r\n estimatedBytesPerColumn: 16,\r\n} as const;\r\n\r\nfunction clamp(value: number, min: number, max: number): number {\r\n return Math.min(max, Math.max(min, value));\r\n}\r\n\r\nfunction normalizePositive(value: number | undefined): number | null {\r\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : null;\r\n}\r\n\r\nfunction stripFileMarkers(content: string): string {\r\n return content.replace(FILE_MARKER_REGEX, '').trim();\r\n}\r\n\r\nfunction countFileMarkers(content: string): number {\r\n return content.match(FILE_MARKER_REGEX)?.length ?? 0;\r\n}\r\n\r\nexport function getChatHistoryMemorySnapshot(): ChatHistoryMemorySnapshot {\r\n const usage = process.memoryUsage();\r\n const heapStats = v8.getHeapStatistics();\r\n\r\n return {\r\n processAvailableMemory: typeof process.availableMemory === 'function'\r\n ? process.availableMemory()\r\n : os.freemem(),\r\n systemFreeMemory: os.freemem(),\r\n systemTotalMemory: os.totalmem(),\r\n processRss: usage.rss,\r\n processHeapUsed: usage.heapUsed,\r\n v8AvailableHeap: heapStats.total_available_size,\r\n v8HeapLimit: heapStats.heap_size_limit,\r\n };\r\n}\r\n\r\nexport function countWrappedVisualLines(text: string, width: number): number {\r\n if (!text) {\r\n return 0;\r\n }\r\n\r\n const safeWidth = Math.max(1, Math.floor(width));\r\n const normalized = text.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\r\n\r\n return normalized.split('\\n').reduce((total, line) => {\r\n const wrapped = wrapAnsi(line.length > 0 ? line : ' ', safeWidth, {\r\n hard: true,\r\n trim: false,\r\n });\r\n\r\n return total + wrapped.split('\\n').length;\r\n }, 0);\r\n}\r\n\r\nfunction estimateUserAttachmentBadgeRows(content: string, width: number): number {\r\n const fileCount = countFileMarkers(content);\r\n if (fileCount === 0) {\r\n return 0;\r\n }\r\n\r\n const safeWidth = Math.max(20, width);\r\n const badgesPerRow = Math.max(1, Math.floor((safeWidth - 2) / 18));\r\n return Math.ceil(fileCount / badgesPerRow);\r\n}\r\n\r\nfunction estimateToolMessageLines(message: Message, width: number): number {\r\n if (!message.toolExecution) {\r\n return 0;\r\n }\r\n\r\n const renderWidth = Math.max(20, width - 8);\r\n const details = [\r\n `Tool: ${message.toolExecution.toolName}`,\r\n `Status: ${message.toolExecution.status}`,\r\n message.toolExecution.arguments ? `Args: ${JSON.stringify(message.toolExecution.arguments)}` : '',\r\n message.toolExecution.error || message.toolExecution.result || '',\r\n ].filter(Boolean).join('\\n');\r\n\r\n return 2 + countWrappedVisualLines(details, renderWidth) + 1;\r\n}\r\n\r\nfunction estimateConnectionStatusLines(message: Message, width: number): number {\r\n if (!message.connectionStatus) {\r\n return 0;\r\n }\r\n\r\n const renderWidth = Math.max(20, width - 6);\r\n const details = [\r\n `${message.connectionStatus.type.toUpperCase()} ${message.connectionStatus.status}`,\r\n message.connectionStatus.connectionString || '',\r\n message.connectionStatus.error || '',\r\n ].filter(Boolean).join('\\n');\r\n\r\n return 2 + countWrappedVisualLines(details, renderWidth) + 1;\r\n}\r\n\r\nfunction estimateTaskCompletionLines(message: Message, width: number): number {\r\n if (!message.taskCompletion) {\r\n return 0;\r\n }\r\n\r\n const stepLines = message.taskCompletion.allSteps?.length ?? 1;\r\n const noteLines = message.taskCompletion.completionNote\r\n ? countWrappedVisualLines(message.taskCompletion.completionNote, Math.max(20, width - 6))\r\n : 0;\r\n\r\n return 2 + stepLines + noteLines + 1;\r\n}\r\n\r\nfunction estimateTodoListLines(message: Message): number {\r\n if (!message.todoList) {\r\n return 0;\r\n }\r\n\r\n return 2 + message.todoList.todos.length + 1;\r\n}\r\n\r\nfunction estimatePlanAcceptedLines(message: Message): number {\r\n if (!message.planAccepted) {\r\n return 0;\r\n }\r\n\r\n return 2 + (message.planAccepted.steps?.length ?? 0) + 1;\r\n}\r\n\r\nfunction estimatePlanQuestionLines(message: Message, width: number): number {\r\n if (!message.planQuestion) {\r\n return 0;\r\n }\r\n\r\n const renderWidth = Math.max(20, width - 6);\r\n const answerLines = message.planQuestion.userAnswer\r\n ? countWrappedVisualLines(message.planQuestion.userAnswer, renderWidth)\r\n : 0;\r\n\r\n return 2 +\r\n countWrappedVisualLines(message.planQuestion.question, renderWidth) +\r\n message.planQuestion.options.length +\r\n answerLines +\r\n 1;\r\n}\r\n\r\nexport function estimateMessageVisualLines(message: Message, width: number): number {\r\n if (message.approval) {\r\n return 0;\r\n }\r\n\r\n if (message.toolExecution) {\r\n return estimateToolMessageLines(message, width);\r\n }\r\n\r\n if (message.connectionStatus) {\r\n return estimateConnectionStatusLines(message, width);\r\n }\r\n\r\n if (message.taskCompletion) {\r\n return estimateTaskCompletionLines(message, width);\r\n }\r\n\r\n if (message.todoList) {\r\n return estimateTodoListLines(message);\r\n }\r\n\r\n if (message.planAccepted) {\r\n return estimatePlanAcceptedLines(message);\r\n }\r\n\r\n if (message.planQuestion) {\r\n return estimatePlanQuestionLines(message, width);\r\n }\r\n\r\n if (message.role === 'assistant' &&\r\n !message.content.trim() &&\r\n message.thinkingDuration === undefined) {\r\n return 0;\r\n }\r\n\r\n const safeWidth = Math.max(CHAT_HISTORY_LIMIT_DEFAULTS.minTerminalWidth, Math.floor(width));\r\n const contentWidth = message.role === 'assistant'\r\n ? Math.max(20, safeWidth - 6)\r\n : Math.max(20, safeWidth - 4);\r\n const visibleContent = message.role === 'user' && !message.isCommandMode\r\n ? stripFileMarkers(message.content)\r\n : message.content;\r\n\r\n let total = 0;\r\n\r\n if (!message.isSpacer) {\r\n total += 1;\r\n }\r\n\r\n if (message.thinkingDuration !== undefined && message.thinkingDuration >= 0) {\r\n total += 1;\r\n }\r\n\r\n if (visibleContent.trim()) {\r\n total += countWrappedVisualLines(visibleContent, contentWidth);\r\n }\r\n\r\n if (message.role === 'user' && !message.isCommandMode) {\r\n total += estimateUserAttachmentBadgeRows(message.content, safeWidth);\r\n }\r\n\r\n return total + 1;\r\n}\r\n\r\nexport function calculateChatHistoryLineLimit({\r\n width,\r\n memory = getChatHistoryMemorySnapshot(),\r\n lineLimitOverride,\r\n}: Pick<ChatHistoryLimitOptions, 'width' | 'memory' | 'lineLimitOverride'>): number {\r\n if (typeof lineLimitOverride === 'number' && Number.isFinite(lineLimitOverride)) {\r\n return Math.max(1, Math.floor(lineLimitOverride));\r\n }\r\n\r\n const safeWidth = Math.max(\r\n CHAT_HISTORY_LIMIT_DEFAULTS.minTerminalWidth,\r\n Math.floor(width || 80)\r\n );\r\n\r\n const headroomCandidates = [\r\n normalizePositive(memory.processAvailableMemory),\r\n normalizePositive(memory.systemFreeMemory),\r\n normalizePositive(memory.v8AvailableHeap),\r\n ].filter((value): value is number => value !== null);\r\n\r\n const headroomBytes = headroomCandidates.length > 0\r\n ? Math.min(...headroomCandidates)\r\n : CHAT_HISTORY_LIMIT_DEFAULTS.minRenderBudgetBytes;\r\n const processRss = normalizePositive(memory.processRss) ?? (32 * MB);\r\n\r\n const renderBudgetBytes = clamp(\r\n Math.min(\r\n headroomBytes * CHAT_HISTORY_LIMIT_DEFAULTS.maxHeadroomShare,\r\n processRss * CHAT_HISTORY_LIMIT_DEFAULTS.maxProcessRssShare\r\n ),\r\n CHAT_HISTORY_LIMIT_DEFAULTS.minRenderBudgetBytes,\r\n CHAT_HISTORY_LIMIT_DEFAULTS.maxRenderBudgetBytes\r\n );\r\n\r\n const estimatedBytesPerLine = Math.max(\r\n CHAT_HISTORY_LIMIT_DEFAULTS.minEstimatedBytesPerLine,\r\n safeWidth * CHAT_HISTORY_LIMIT_DEFAULTS.estimatedBytesPerColumn\r\n );\r\n\r\n return clamp(\r\n Math.floor(renderBudgetBytes / estimatedBytesPerLine),\r\n CHAT_HISTORY_LIMIT_DEFAULTS.minLineLimit,\r\n CHAT_HISTORY_LIMIT_DEFAULTS.maxLineLimit\r\n );\r\n}\r\n\r\nexport function limitChatHistoryForDisplay(\r\n history: Message[],\r\n options: ChatHistoryLimitOptions = {}\r\n): ChatHistoryLimitResult {\r\n const {\r\n enabled = true,\r\n width = process.stdout.columns || 120,\r\n memory,\r\n lineLimitOverride,\r\n } = options;\r\n\r\n const lineLimit = calculateChatHistoryLineLimit({\r\n width,\r\n memory,\r\n lineLimitOverride,\r\n });\r\n\r\n if (!enabled || history.length === 0) {\r\n return {\r\n visibleMessages: history,\r\n hiddenMessageCount: 0,\r\n visibleLineCount: history.reduce(\r\n (total, message) => total + estimateMessageVisualLines(message, width),\r\n 0\r\n ),\r\n lineLimit,\r\n };\r\n }\r\n\r\n let totalLines = 0;\r\n let startIndex = history.length;\r\n\r\n for (let i = history.length - 1; i >= 0; i--) {\r\n const messageLines = estimateMessageVisualLines(history[i], width);\r\n\r\n if (startIndex < history.length && totalLines + messageLines > lineLimit) {\r\n break;\r\n }\r\n\r\n totalLines += messageLines;\r\n startIndex = i;\r\n }\r\n\r\n return {\r\n visibleMessages: history.slice(startIndex),\r\n hiddenMessageCount: startIndex,\r\n visibleLineCount: totalLines,\r\n lineLimit,\r\n };\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -277,28 +277,41 @@ ${truncate(cleanResult, 1e3)}
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
function formatMessage(message) {
|
|
280
|
-
const { role, content, toolExecution, isCommandMode, taskCompletion, planAccepted, connectionStatus } = message;
|
|
281
|
-
if (role === "system") {
|
|
280
|
+
const { role, content, toolExecution, isCommandMode, taskCompletion, planAccepted, planQuestion, connectionStatus } = message;
|
|
281
|
+
if (role === "system" && !taskCompletion && !planAccepted && !planQuestion && !connectionStatus && content) {
|
|
282
282
|
return "";
|
|
283
283
|
}
|
|
284
284
|
if (connectionStatus) {
|
|
285
285
|
const { type, status, connectionString, error: connError } = connectionStatus;
|
|
286
286
|
if (status === "connected") {
|
|
287
|
-
return
|
|
287
|
+
return `Connected to ${type.toUpperCase()}: ${connectionString || "session"}`;
|
|
288
288
|
} else if (status === "disconnected") {
|
|
289
|
-
return
|
|
289
|
+
return `Disconnected from ${type.toUpperCase()} session`;
|
|
290
290
|
} else if (status === "error") {
|
|
291
|
-
return
|
|
291
|
+
return `${type.toUpperCase()} connection error: ${connError || "unknown error"}`;
|
|
292
292
|
}
|
|
293
293
|
return "";
|
|
294
294
|
}
|
|
295
|
+
if (planQuestion) {
|
|
296
|
+
const { question, options, userAnswer, wasSkipped } = planQuestion;
|
|
297
|
+
let output = `Q: ${question}
|
|
298
|
+
Options: ${options.map((o, i) => `${i + 1}. ${o}`).join(", ")}`;
|
|
299
|
+
if (wasSkipped) {
|
|
300
|
+
output += `
|
|
301
|
+
Answer: (skipped)`;
|
|
302
|
+
} else {
|
|
303
|
+
output += `
|
|
304
|
+
Answer: ${userAnswer}`;
|
|
305
|
+
}
|
|
306
|
+
return output;
|
|
307
|
+
}
|
|
295
308
|
if (planAccepted) {
|
|
296
|
-
const { planTitle,
|
|
297
|
-
return
|
|
309
|
+
const { planTitle, totalSteps } = planAccepted;
|
|
310
|
+
return `Plan accepted: "${planTitle || "Implementation Plan"}" with ${totalSteps || 0} steps`;
|
|
298
311
|
}
|
|
299
312
|
if (taskCompletion) {
|
|
300
|
-
const {
|
|
301
|
-
let output =
|
|
313
|
+
const { completedStepNumber, totalCount, completedStepDescription, completionNote } = taskCompletion;
|
|
314
|
+
let output = `Step ${completedStepNumber}/${totalCount} completed: ${completedStepDescription}`;
|
|
302
315
|
if (completionNote) {
|
|
303
316
|
output += `
|
|
304
317
|
Note: ${completionNote}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/chat-formatter.ts"],"sourcesContent":["/**\r\n * Chat Formatter Utility\r\n * \r\n * Formats chat messages into human-readable text for clipboard sharing.\r\n * Converts internal tool call JSON and execution data into readable descriptions.\r\n */\r\n\r\nimport { Message, ToolExecution } from '../types/index.js';\r\nimport stripAnsi from 'strip-ansi';\r\n\r\n/**\r\n * Clean Unicode characters that might get corrupted in clipboard.\r\n * Removes emojis, box-drawing characters, and other problematic Unicode.\r\n */\r\nfunction cleanUnicode(text: string): string {\r\n return text\r\n // Remove box-drawing characters (used in UI borders)\r\n .replace(/[\\u2500-\\u257F]/g, '')\r\n // Remove block elements\r\n .replace(/[\\u2580-\\u259F]/g, '')\r\n // Remove emojis and pictographs (replace with text equivalents)\r\n .replace(/✓/g, '[OK]')\r\n .replace(/✗/g, '[FAIL]')\r\n .replace(/📖/g, '[READ]')\r\n .replace(/📁/g, '[DIR]')\r\n .replace(/📂/g, '[DIR]')\r\n .replace(/📄/g, '[FILE]')\r\n .replace(/✅/g, '[DONE]')\r\n .replace(/❌/g, '[ERROR]')\r\n .replace(/📭/g, '[EMPTY]')\r\n .replace(/📋/g, '[CLIPBOARD]')\r\n .replace(/🔗/g, '[LINK]')\r\n .replace(/🔌/g, '[DISCONNECT]')\r\n .replace(/⚠️/g, '[WARNING]')\r\n .replace(/🆕/g, '[NEW]')\r\n // Remove remaining emojis (broad Unicode ranges)\r\n .replace(/[\\u{1F300}-\\u{1F9FF}]/gu, '')\r\n .replace(/[\\u{2600}-\\u{26FF}]/gu, '')\r\n .replace(/[\\u{2700}-\\u{27BF}]/gu, '')\r\n // Remove common corrupted sequences (Γ, ≡, etc.)\r\n .replace(/Γ[^\\s]*/g, '')\r\n .replace(/≡[^\\s]*/g, '')\r\n // Clean up extra whitespace from removals\r\n .replace(/\\n{3,}/g, '\\n\\n')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Format a tool execution into human-readable text.\r\n */\r\nfunction formatToolExecution(toolExecution: ToolExecution): string {\r\n const { toolName, status, result, error, arguments: args } = toolExecution;\r\n\r\n // Only format completed or error executions\r\n if (status !== 'completed' && status !== 'error') {\r\n return '';\r\n }\r\n\r\n const statusLabel = status === 'completed' ? '✓' : '✗';\r\n\r\n // Clean result output (remove ANSI codes)\r\n const cleanResult = result ? stripAnsi(result).trim() : '';\r\n\r\n // Helper to truncate long content\r\n const truncate = (text: string, maxLen: number = 3000): string => {\r\n if (text.length <= maxLen) return text;\r\n return text.substring(0, maxLen) + '\\n... (content truncated)';\r\n };\r\n\r\n // Handle different tool types\r\n switch (toolName) {\r\n case 'execute_command': {\r\n const command = args?.command || args?.CommandLine || args?.commandLine || 'unknown command';\r\n const cwd = args?.cwd || '';\r\n let output = `${statusLabel} The assistant ran a shell command: \\`${command}\\``;\r\n if (cwd) {\r\n output += ` (in directory: ${cwd})`;\r\n }\r\n if (cleanResult) {\r\n output += `\\n\\nOutput:\\n\\`\\`\\`\\n${truncate(cleanResult, 2000)}\\n\\`\\`\\``;\r\n }\r\n if (status === 'error' && error) {\r\n output += `\\n\\nError: ${error}`;\r\n }\r\n return output;\r\n }\r\n\r\n case 'view_file': {\r\n const filePath = args?.AbsolutePath || args?.file_path || 'unknown file';\r\n const startLine = args?.StartLine;\r\n const endLine = args?.EndLine;\r\n let output = `${statusLabel} The assistant read file: \\`${filePath}\\``;\r\n if (startLine && endLine) {\r\n output += ` (lines ${startLine}-${endLine})`;\r\n }\r\n // Include the file contents from the result\r\n if (cleanResult) {\r\n output += `\\n\\nFile contents:\\n\\`\\`\\`\\n${truncate(cleanResult)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'write_to_file': {\r\n const filePath = args?.TargetFile || args?.file_path || 'unknown file';\r\n const content = args?.CodeContent || '';\r\n const lines = content ? content.split('\\n').length : 0;\r\n let output = `${statusLabel} The assistant wrote to file: \\`${filePath}\\` (${lines} lines)`;\r\n // Include the content that was written\r\n if (content) {\r\n output += `\\n\\nNew file contents:\\n\\`\\`\\`\\n${truncate(content)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'edit_file':\r\n case 'replace_file_content': {\r\n const filePath = args?.file_path || args?.TargetFile || 'unknown file';\r\n const targetContent = args?.TargetContent || args?.target_content || '';\r\n const replacementContent = args?.ReplacementContent || args?.replacement_content || '';\r\n let output = `${statusLabel} The assistant edited file: \\`${filePath}\\``;\r\n\r\n // Include the edit details\r\n if (targetContent || replacementContent) {\r\n output += `\\n\\nEdit made:`;\r\n if (targetContent) {\r\n output += `\\n\\nOriginal:\\n\\`\\`\\`\\n${truncate(targetContent, 500)}\\n\\`\\`\\``;\r\n }\r\n if (replacementContent) {\r\n output += `\\n\\nReplaced with:\\n\\`\\`\\`\\n${truncate(replacementContent, 500)}\\n\\`\\`\\``;\r\n }\r\n }\r\n return output;\r\n }\r\n\r\n case 'multi_edit_file':\r\n case 'multi_replace_file_content': {\r\n const filePath = args?.file_path || args?.TargetFile || 'unknown file';\r\n const chunks = args?.ReplacementChunks || args?.edits || [];\r\n let output = `${statusLabel} The assistant made ${chunks.length || 'multiple'} edits to file: \\`${filePath}\\``;\r\n\r\n // Include each edit\r\n if (Array.isArray(chunks) && chunks.length > 0) {\r\n output += `\\n\\nEdits made:`;\r\n chunks.slice(0, 5).forEach((chunk: any, i: number) => {\r\n const target = chunk.TargetContent || chunk.target_content || '';\r\n const replacement = chunk.ReplacementContent || chunk.replacement_content || '';\r\n output += `\\n\\n**Edit ${i + 1}:**`;\r\n if (target) {\r\n output += `\\nOriginal:\\n\\`\\`\\`\\n${truncate(target, 300)}\\n\\`\\`\\``;\r\n }\r\n if (replacement) {\r\n output += `\\nReplaced with:\\n\\`\\`\\`\\n${truncate(replacement, 300)}\\n\\`\\`\\``;\r\n }\r\n });\r\n if (chunks.length > 5) {\r\n output += `\\n\\n... and ${chunks.length - 5} more edits`;\r\n }\r\n }\r\n return output;\r\n }\r\n\r\n case 'list_dir': {\r\n const dirPath = args?.DirectoryPath || args?.directory || 'unknown directory';\r\n let output = `${statusLabel} The assistant listed directory: \\`${dirPath}\\``;\r\n if (cleanResult) {\r\n output += `\\n\\nContents:\\n\\`\\`\\`\\n${truncate(cleanResult, 1000)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'grep_search': {\r\n const query = args?.Query || args?.query || 'unknown query';\r\n let output = `${statusLabel} The assistant searched for: \"${query}\"`;\r\n if (cleanResult) {\r\n output += `\\n\\nSearch results:\\n\\`\\`\\`\\n${truncate(cleanResult, 1500)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'find_files':\r\n case 'find_by_name': {\r\n const pattern = args?.pattern || args?.Pattern || '*';\r\n let output = `${statusLabel} The assistant searched for files matching: \"${pattern}\"`;\r\n if (cleanResult) {\r\n output += `\\n\\nFiles found:\\n\\`\\`\\`\\n${truncate(cleanResult, 1000)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'web_search':\r\n case 'search_web': {\r\n const query = args?.query || 'unknown query';\r\n let output = `${statusLabel} The assistant searched the web for: \"${query}\"`;\r\n if (cleanResult) {\r\n output += `\\n\\nSearch results:\\n${truncate(cleanResult, 2000)}`;\r\n }\r\n return output;\r\n }\r\n\r\n case 'fetch_url':\r\n case 'read_url_content': {\r\n const url = args?.url || args?.Url || 'unknown URL';\r\n let output = `${statusLabel} The assistant fetched URL: ${url}`;\r\n if (cleanResult) {\r\n output += `\\n\\nContent:\\n${truncate(cleanResult, 2000)}`;\r\n }\r\n return output;\r\n }\r\n\r\n case 'view_code_item':\r\n case 'inspect_symbol': {\r\n const filePath = args?.filePath || args?.File || 'unknown file';\r\n const nodePaths = args?.NodePaths || args?.symbols || [];\r\n let output = `${statusLabel} The assistant inspected code in: \\`${filePath}\\``;\r\n if (Array.isArray(nodePaths) && nodePaths.length > 0) {\r\n output += ` (symbols: ${nodePaths.join(', ')})`;\r\n }\r\n if (cleanResult) {\r\n output += `\\n\\nCode:\\n\\`\\`\\`\\n${truncate(cleanResult)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'view_file_outline': {\r\n const filePath = args?.AbsolutePath || 'unknown file';\r\n let output = `${statusLabel} The assistant viewed outline of: \\`${filePath}\\``;\r\n if (cleanResult) {\r\n output += `\\n\\nOutline:\\n\\`\\`\\`\\n${truncate(cleanResult, 1500)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'read_binary_file': {\r\n const filePath = args?.file_path || 'unknown file';\r\n return `${statusLabel} The assistant uploaded binary file: \\`${filePath}\\``;\r\n }\r\n\r\n case 'create_image':\r\n case 'generate_image': {\r\n const outputPath = args?.output_path || args?.ImageName || 'unknown path';\r\n const prompt = args?.Prompt || args?.image_prompt || '';\r\n let output = `${statusLabel} The assistant generated an image: \\`${outputPath}\\``;\r\n if (prompt) {\r\n output += `\\n\\nPrompt used: \"${truncate(prompt, 500)}\"`;\r\n }\r\n return output;\r\n }\r\n\r\n default: {\r\n // Check for MCP tools (mcp_servername_toolname)\r\n if (toolName.startsWith('mcp_')) {\r\n const parts = toolName.slice(4).split('_');\r\n const serverName = parts[0] || 'unknown';\r\n const mcpToolName = parts.slice(1).join('_') || 'unknown';\r\n let output = `${statusLabel} The assistant used MCP tool: ${serverName}.${mcpToolName}`;\r\n\r\n // Include the full MCP result\r\n if (cleanResult) {\r\n output += `\\n\\nResult:\\n\\`\\`\\`\\n${truncate(cleanResult)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n // Generic tool formatting\r\n let output = `${statusLabel} The assistant used tool: ${toolName}`;\r\n if (cleanResult) {\r\n output += `\\n\\nResult:\\n\\`\\`\\`\\n${truncate(cleanResult, 1000)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Format a single message into human-readable text.\r\n */\r\nfunction formatMessage(message: Message): string {\r\n const { role, content, toolExecution, isCommandMode, taskCompletion, planAccepted, connectionStatus } = message;\r\n\r\n // Skip system messages\r\n if (role === 'system') {\r\n return '';\r\n }\r\n\r\n // Handle connection status messages\r\n if (connectionStatus) {\r\n const { type, status, connectionString, error: connError } = connectionStatus;\r\n if (status === 'connected') {\r\n return `🔗 Connected to ${type.toUpperCase()}: ${connectionString || 'session'}`;\r\n } else if (status === 'disconnected') {\r\n return `🔌 Disconnected from ${type.toUpperCase()} session`;\r\n } else if (status === 'error') {\r\n return `❌ ${type.toUpperCase()} connection error: ${connError || 'unknown error'}`;\r\n }\r\n return '';\r\n }\r\n\r\n // Handle plan accepted messages\r\n if (planAccepted) {\r\n const { planTitle, totalTasks } = planAccepted;\r\n return `📋 Plan accepted: \"${planTitle || 'Implementation Plan'}\" with ${totalTasks || 0} tasks`;\r\n }\r\n\r\n // Handle task completion messages\r\n if (taskCompletion) {\r\n const { taskNumber, totalTasks, taskDescription, completionNote } = taskCompletion;\r\n let output = `✅ Task ${taskNumber}/${totalTasks} completed: ${taskDescription}`;\r\n if (completionNote) {\r\n output += `\\nNote: ${completionNote}`;\r\n }\r\n return output;\r\n }\r\n\r\n // Handle tool execution messages\r\n if (toolExecution) {\r\n return formatToolExecution(toolExecution);\r\n }\r\n\r\n // Handle user messages\r\n if (role === 'user') {\r\n if (isCommandMode) {\r\n return `## User (Terminal Command)\\n\\`\\`\\`\\n${content}\\n\\`\\`\\``;\r\n }\r\n return `## User\\n${content}`;\r\n }\r\n\r\n // Handle assistant messages\r\n if (role === 'assistant') {\r\n if (content && content.trim()) {\r\n return `## Assistant\\n${content}`;\r\n }\r\n return '';\r\n }\r\n\r\n // Handle tool result messages (usually internal, skip)\r\n if (role === 'tool') {\r\n return '';\r\n }\r\n\r\n return '';\r\n}\r\n\r\n/**\r\n * Format entire chat history into human-readable text for clipboard sharing.\r\n */\r\nexport function formatChatForClipboard(messages: Message[]): string {\r\n const header = `# Chat Session Export\r\nGenerated: ${new Date().toLocaleString()}\r\n---\r\n\r\n`;\r\n\r\n const formattedMessages = messages\r\n .map(formatMessage)\r\n .filter(text => text.trim() !== '')\r\n .join('\\n\\n---\\n\\n');\r\n\r\n if (!formattedMessages) {\r\n return cleanUnicode(header + 'No messages in this chat session.');\r\n }\r\n\r\n return cleanUnicode(header + formattedMessages);\r\n}\r\n"],"mappings":"AAQA,OAAO,eAAe;AAMtB,SAAS,aAAa,MAAsB;AACxC,SAAO,KAEF,QAAQ,oBAAoB,EAAE,EAE9B,QAAQ,oBAAoB,EAAE,EAE9B,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,OAAO,QAAQ,EACvB,QAAQ,OAAO,OAAO,EACtB,QAAQ,OAAO,OAAO,EACtB,QAAQ,OAAO,QAAQ,EACvB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,SAAS,EACvB,QAAQ,OAAO,SAAS,EACxB,QAAQ,OAAO,aAAa,EAC5B,QAAQ,OAAO,QAAQ,EACvB,QAAQ,OAAO,cAAc,EAC7B,QAAQ,OAAO,WAAW,EAC1B,QAAQ,OAAO,OAAO,EAEtB,QAAQ,2BAA2B,EAAE,EACrC,QAAQ,yBAAyB,EAAE,EACnC,QAAQ,yBAAyB,EAAE,EAEnC,QAAQ,YAAY,EAAE,EACtB,QAAQ,YAAY,EAAE,EAEtB,QAAQ,WAAW,MAAM,EACzB,KAAK;AACd;AAKA,SAAS,oBAAoB,eAAsC;AAC/D,QAAM,EAAE,UAAU,QAAQ,QAAQ,OAAO,WAAW,KAAK,IAAI;AAG7D,MAAI,WAAW,eAAe,WAAW,SAAS;AAC9C,WAAO;AAAA,EACX;AAEA,QAAM,cAAc,WAAW,cAAc,WAAM;AAGnD,QAAM,cAAc,SAAS,UAAU,MAAM,EAAE,KAAK,IAAI;AAGxD,QAAM,WAAW,CAAC,MAAc,SAAiB,QAAiB;AAC9D,QAAI,KAAK,UAAU,OAAQ,QAAO;AAClC,WAAO,KAAK,UAAU,GAAG,MAAM,IAAI;AAAA,EACvC;AAGA,UAAQ,UAAU;AAAA,IACd,KAAK,mBAAmB;AACpB,YAAM,UAAU,MAAM,WAAW,MAAM,eAAe,MAAM,eAAe;AAC3E,YAAM,MAAM,MAAM,OAAO;AACzB,UAAI,SAAS,GAAG,WAAW,yCAAyC,OAAO;AAC3E,UAAI,KAAK;AACL,kBAAU,mBAAmB,GAAG;AAAA,MACpC;AACA,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAAwB,SAAS,aAAa,GAAI,CAAC;AAAA;AAAA,MACjE;AACA,UAAI,WAAW,WAAW,OAAO;AAC7B,kBAAU;AAAA;AAAA,SAAc,KAAK;AAAA,MACjC;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK,aAAa;AACd,YAAM,WAAW,MAAM,gBAAgB,MAAM,aAAa;AAC1D,YAAM,YAAY,MAAM;AACxB,YAAM,UAAU,MAAM;AACtB,UAAI,SAAS,GAAG,WAAW,+BAA+B,QAAQ;AAClE,UAAI,aAAa,SAAS;AACtB,kBAAU,WAAW,SAAS,IAAI,OAAO;AAAA,MAC7C;AAEA,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAA+B,SAAS,WAAW,CAAC;AAAA;AAAA,MAClE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK,iBAAiB;AAClB,YAAM,WAAW,MAAM,cAAc,MAAM,aAAa;AACxD,YAAM,UAAU,MAAM,eAAe;AACrC,YAAM,QAAQ,UAAU,QAAQ,MAAM,IAAI,EAAE,SAAS;AACrD,UAAI,SAAS,GAAG,WAAW,mCAAmC,QAAQ,OAAO,KAAK;AAElF,UAAI,SAAS;AACT,kBAAU;AAAA;AAAA;AAAA;AAAA,EAAmC,SAAS,OAAO,CAAC;AAAA;AAAA,MAClE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,wBAAwB;AACzB,YAAM,WAAW,MAAM,aAAa,MAAM,cAAc;AACxD,YAAM,gBAAgB,MAAM,iBAAiB,MAAM,kBAAkB;AACrE,YAAM,qBAAqB,MAAM,sBAAsB,MAAM,uBAAuB;AACpF,UAAI,SAAS,GAAG,WAAW,iCAAiC,QAAQ;AAGpE,UAAI,iBAAiB,oBAAoB;AACrC,kBAAU;AAAA;AAAA;AACV,YAAI,eAAe;AACf,oBAAU;AAAA;AAAA;AAAA;AAAA,EAA0B,SAAS,eAAe,GAAG,CAAC;AAAA;AAAA,QACpE;AACA,YAAI,oBAAoB;AACpB,oBAAU;AAAA;AAAA;AAAA;AAAA,EAA+B,SAAS,oBAAoB,GAAG,CAAC;AAAA;AAAA,QAC9E;AAAA,MACJ;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,8BAA8B;AAC/B,YAAM,WAAW,MAAM,aAAa,MAAM,cAAc;AACxD,YAAM,SAAS,MAAM,qBAAqB,MAAM,SAAS,CAAC;AAC1D,UAAI,SAAS,GAAG,WAAW,uBAAuB,OAAO,UAAU,UAAU,qBAAqB,QAAQ;AAG1G,UAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,GAAG;AAC5C,kBAAU;AAAA;AAAA;AACV,eAAO,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAY,MAAc;AAClD,gBAAM,SAAS,MAAM,iBAAiB,MAAM,kBAAkB;AAC9D,gBAAM,cAAc,MAAM,sBAAsB,MAAM,uBAAuB;AAC7E,oBAAU;AAAA;AAAA,SAAc,IAAI,CAAC;AAC7B,cAAI,QAAQ;AACR,sBAAU;AAAA;AAAA;AAAA,EAAwB,SAAS,QAAQ,GAAG,CAAC;AAAA;AAAA,UAC3D;AACA,cAAI,aAAa;AACb,sBAAU;AAAA;AAAA;AAAA,EAA6B,SAAS,aAAa,GAAG,CAAC;AAAA;AAAA,UACrE;AAAA,QACJ,CAAC;AACD,YAAI,OAAO,SAAS,GAAG;AACnB,oBAAU;AAAA;AAAA,UAAe,OAAO,SAAS,CAAC;AAAA,QAC9C;AAAA,MACJ;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK,YAAY;AACb,YAAM,UAAU,MAAM,iBAAiB,MAAM,aAAa;AAC1D,UAAI,SAAS,GAAG,WAAW,sCAAsC,OAAO;AACxE,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAA0B,SAAS,aAAa,GAAI,CAAC;AAAA;AAAA,MACnE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK,eAAe;AAChB,YAAM,QAAQ,MAAM,SAAS,MAAM,SAAS;AAC5C,UAAI,SAAS,GAAG,WAAW,iCAAiC,KAAK;AACjE,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAAgC,SAAS,aAAa,IAAI,CAAC;AAAA;AAAA,MACzE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,gBAAgB;AACjB,YAAM,UAAU,MAAM,WAAW,MAAM,WAAW;AAClD,UAAI,SAAS,GAAG,WAAW,gDAAgD,OAAO;AAClF,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAA6B,SAAS,aAAa,GAAI,CAAC;AAAA;AAAA,MACtE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,cAAc;AACf,YAAM,QAAQ,MAAM,SAAS;AAC7B,UAAI,SAAS,GAAG,WAAW,yCAAyC,KAAK;AACzE,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA,EAAwB,SAAS,aAAa,GAAI,CAAC;AAAA,MACjE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,oBAAoB;AACrB,YAAM,MAAM,MAAM,OAAO,MAAM,OAAO;AACtC,UAAI,SAAS,GAAG,WAAW,+BAA+B,GAAG;AAC7D,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA,EAAiB,SAAS,aAAa,GAAI,CAAC;AAAA,MAC1D;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,kBAAkB;AACnB,YAAM,WAAW,MAAM,YAAY,MAAM,QAAQ;AACjD,YAAM,YAAY,MAAM,aAAa,MAAM,WAAW,CAAC;AACvD,UAAI,SAAS,GAAG,WAAW,uCAAuC,QAAQ;AAC1E,UAAI,MAAM,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG;AAClD,kBAAU,cAAc,UAAU,KAAK,IAAI,CAAC;AAAA,MAChD;AACA,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAAsB,SAAS,WAAW,CAAC;AAAA;AAAA,MACzD;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK,qBAAqB;AACtB,YAAM,WAAW,MAAM,gBAAgB;AACvC,UAAI,SAAS,GAAG,WAAW,uCAAuC,QAAQ;AAC1E,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAAyB,SAAS,aAAa,IAAI,CAAC;AAAA;AAAA,MAClE;AACA,aAAO;AAAA,IACX;AAAA,IAEA,KAAK,oBAAoB;AACrB,YAAM,WAAW,MAAM,aAAa;AACpC,aAAO,GAAG,WAAW,0CAA0C,QAAQ;AAAA,IAC3E;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,kBAAkB;AACnB,YAAM,aAAa,MAAM,eAAe,MAAM,aAAa;AAC3D,YAAM,SAAS,MAAM,UAAU,MAAM,gBAAgB;AACrD,UAAI,SAAS,GAAG,WAAW,wCAAwC,UAAU;AAC7E,UAAI,QAAQ;AACR,kBAAU;AAAA;AAAA,gBAAqB,SAAS,QAAQ,GAAG,CAAC;AAAA,MACxD;AACA,aAAO;AAAA,IACX;AAAA,IAEA,SAAS;AAEL,UAAI,SAAS,WAAW,MAAM,GAAG;AAC7B,cAAM,QAAQ,SAAS,MAAM,CAAC,EAAE,MAAM,GAAG;AACzC,cAAM,aAAa,MAAM,CAAC,KAAK;AAC/B,cAAM,cAAc,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK;AAChD,YAAIA,UAAS,GAAG,WAAW,iCAAiC,UAAU,IAAI,WAAW;AAGrF,YAAI,aAAa;AACb,UAAAA,WAAU;AAAA;AAAA;AAAA;AAAA,EAAwB,SAAS,WAAW,CAAC;AAAA;AAAA,QAC3D;AACA,eAAOA;AAAA,MACX;AAGA,UAAI,SAAS,GAAG,WAAW,6BAA6B,QAAQ;AAChE,UAAI,aAAa;AACb,kBAAU;AAAA;AAAA;AAAA;AAAA,EAAwB,SAAS,aAAa,GAAI,CAAC;AAAA;AAAA,MACjE;AACA,aAAO;AAAA,IACX;AAAA,EACJ;AACJ;AAKA,SAAS,cAAc,SAA0B;AAC7C,QAAM,EAAE,MAAM,SAAS,eAAe,eAAe,gBAAgB,cAAc,iBAAiB,IAAI;AAGxG,MAAI,SAAS,UAAU;AACnB,WAAO;AAAA,EACX;AAGA,MAAI,kBAAkB;AAClB,UAAM,EAAE,MAAM,QAAQ,kBAAkB,OAAO,UAAU,IAAI;AAC7D,QAAI,WAAW,aAAa;AACxB,aAAO,0BAAmB,KAAK,YAAY,CAAC,KAAK,oBAAoB,SAAS;AAAA,IAClF,WAAW,WAAW,gBAAgB;AAClC,aAAO,+BAAwB,KAAK,YAAY,CAAC;AAAA,IACrD,WAAW,WAAW,SAAS;AAC3B,aAAO,UAAK,KAAK,YAAY,CAAC,sBAAsB,aAAa,eAAe;AAAA,IACpF;AACA,WAAO;AAAA,EACX;AAGA,MAAI,cAAc;AACd,UAAM,EAAE,WAAW,WAAW,IAAI;AAClC,WAAO,6BAAsB,aAAa,qBAAqB,UAAU,cAAc,CAAC;AAAA,EAC5F;AAGA,MAAI,gBAAgB;AAChB,UAAM,EAAE,YAAY,YAAY,iBAAiB,eAAe,IAAI;AACpE,QAAI,SAAS,eAAU,UAAU,IAAI,UAAU,eAAe,eAAe;AAC7E,QAAI,gBAAgB;AAChB,gBAAU;AAAA,QAAW,cAAc;AAAA,IACvC;AACA,WAAO;AAAA,EACX;AAGA,MAAI,eAAe;AACf,WAAO,oBAAoB,aAAa;AAAA,EAC5C;AAGA,MAAI,SAAS,QAAQ;AACjB,QAAI,eAAe;AACf,aAAO;AAAA;AAAA,EAAuC,OAAO;AAAA;AAAA,IACzD;AACA,WAAO;AAAA,EAAY,OAAO;AAAA,EAC9B;AAGA,MAAI,SAAS,aAAa;AACtB,QAAI,WAAW,QAAQ,KAAK,GAAG;AAC3B,aAAO;AAAA,EAAiB,OAAO;AAAA,IACnC;AACA,WAAO;AAAA,EACX;AAGA,MAAI,SAAS,QAAQ;AACjB,WAAO;AAAA,EACX;AAEA,SAAO;AACX;AAKO,SAAS,uBAAuB,UAA6B;AAChE,QAAM,SAAS;AAAA,cACN,oBAAI,KAAK,GAAE,eAAe,CAAC;AAAA;AAAA;AAAA;AAKpC,QAAM,oBAAoB,SACrB,IAAI,aAAa,EACjB,OAAO,UAAQ,KAAK,KAAK,MAAM,EAAE,EACjC,KAAK,aAAa;AAEvB,MAAI,CAAC,mBAAmB;AACpB,WAAO,aAAa,SAAS,mCAAmC;AAAA,EACpE;AAEA,SAAO,aAAa,SAAS,iBAAiB;AAClD;","names":["output"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/chat-formatter.ts"],"sourcesContent":["/**\r\n * Chat Formatter Utility\r\n * \r\n * Formats chat messages into human-readable text for clipboard sharing.\r\n * Converts internal tool call JSON and execution data into readable descriptions.\r\n */\r\n\r\nimport { Message, ToolExecution } from '../types/index.js';\r\nimport stripAnsi from 'strip-ansi';\r\n\r\n/**\r\n * Clean Unicode characters that might get corrupted in clipboard.\r\n * Removes emojis, box-drawing characters, and other problematic Unicode.\r\n */\r\nfunction cleanUnicode(text: string): string {\r\n return text\r\n // Remove box-drawing characters (used in UI borders)\r\n .replace(/[\\u2500-\\u257F]/g, '')\r\n // Remove block elements\r\n .replace(/[\\u2580-\\u259F]/g, '')\r\n // Remove emojis and pictographs (replace with text equivalents)\r\n .replace(/✓/g, '[OK]')\r\n .replace(/✗/g, '[FAIL]')\r\n .replace(/📖/g, '[READ]')\r\n .replace(/📁/g, '[DIR]')\r\n .replace(/📂/g, '[DIR]')\r\n .replace(/📄/g, '[FILE]')\r\n .replace(/✅/g, '[DONE]')\r\n .replace(/❌/g, '[ERROR]')\r\n .replace(/📭/g, '[EMPTY]')\r\n .replace(/📋/g, '[CLIPBOARD]')\r\n .replace(/🔗/g, '[LINK]')\r\n .replace(/🔌/g, '[DISCONNECT]')\r\n .replace(/⚠️/g, '[WARNING]')\r\n .replace(/🆕/g, '[NEW]')\r\n // Remove remaining emojis (broad Unicode ranges)\r\n .replace(/[\\u{1F300}-\\u{1F9FF}]/gu, '')\r\n .replace(/[\\u{2600}-\\u{26FF}]/gu, '')\r\n .replace(/[\\u{2700}-\\u{27BF}]/gu, '')\r\n // Remove common corrupted sequences (Γ, ≡, etc.)\r\n .replace(/Γ[^\\s]*/g, '')\r\n .replace(/≡[^\\s]*/g, '')\r\n // Clean up extra whitespace from removals\r\n .replace(/\\n{3,}/g, '\\n\\n')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Format a tool execution into human-readable text.\r\n */\r\nfunction formatToolExecution(toolExecution: ToolExecution): string {\r\n const { toolName, status, result, error, arguments: args } = toolExecution;\r\n\r\n // Only format completed or error executions\r\n if (status !== 'completed' && status !== 'error') {\r\n return '';\r\n }\r\n\r\n const statusLabel = status === 'completed' ? '✓' : '✗';\r\n\r\n // Clean result output (remove ANSI codes)\r\n const cleanResult = result ? stripAnsi(result).trim() : '';\r\n\r\n // Helper to truncate long content\r\n const truncate = (text: string, maxLen: number = 3000): string => {\r\n if (text.length <= maxLen) return text;\r\n return text.substring(0, maxLen) + '\\n... (content truncated)';\r\n };\r\n\r\n // Handle different tool types\r\n switch (toolName) {\r\n case 'execute_command': {\r\n const command = args?.command || args?.CommandLine || args?.commandLine || 'unknown command';\r\n const cwd = args?.cwd || '';\r\n let output = `${statusLabel} The assistant ran a shell command: \\`${command}\\``;\r\n if (cwd) {\r\n output += ` (in directory: ${cwd})`;\r\n }\r\n if (cleanResult) {\r\n output += `\\n\\nOutput:\\n\\`\\`\\`\\n${truncate(cleanResult, 2000)}\\n\\`\\`\\``;\r\n }\r\n if (status === 'error' && error) {\r\n output += `\\n\\nError: ${error}`;\r\n }\r\n return output;\r\n }\r\n\r\n case 'view_file': {\r\n const filePath = args?.AbsolutePath || args?.file_path || 'unknown file';\r\n const startLine = args?.StartLine;\r\n const endLine = args?.EndLine;\r\n let output = `${statusLabel} The assistant read file: \\`${filePath}\\``;\r\n if (startLine && endLine) {\r\n output += ` (lines ${startLine}-${endLine})`;\r\n }\r\n // Include the file contents from the result\r\n if (cleanResult) {\r\n output += `\\n\\nFile contents:\\n\\`\\`\\`\\n${truncate(cleanResult)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'write_to_file': {\r\n const filePath = args?.TargetFile || args?.file_path || 'unknown file';\r\n const content = args?.CodeContent || '';\r\n const lines = content ? content.split('\\n').length : 0;\r\n let output = `${statusLabel} The assistant wrote to file: \\`${filePath}\\` (${lines} lines)`;\r\n // Include the content that was written\r\n if (content) {\r\n output += `\\n\\nNew file contents:\\n\\`\\`\\`\\n${truncate(content)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'edit_file':\r\n case 'replace_file_content': {\r\n const filePath = args?.file_path || args?.TargetFile || 'unknown file';\r\n const targetContent = args?.TargetContent || args?.target_content || '';\r\n const replacementContent = args?.ReplacementContent || args?.replacement_content || '';\r\n let output = `${statusLabel} The assistant edited file: \\`${filePath}\\``;\r\n\r\n // Include the edit details\r\n if (targetContent || replacementContent) {\r\n output += `\\n\\nEdit made:`;\r\n if (targetContent) {\r\n output += `\\n\\nOriginal:\\n\\`\\`\\`\\n${truncate(targetContent, 500)}\\n\\`\\`\\``;\r\n }\r\n if (replacementContent) {\r\n output += `\\n\\nReplaced with:\\n\\`\\`\\`\\n${truncate(replacementContent, 500)}\\n\\`\\`\\``;\r\n }\r\n }\r\n return output;\r\n }\r\n\r\n case 'multi_edit_file':\r\n case 'multi_replace_file_content': {\r\n const filePath = args?.file_path || args?.TargetFile || 'unknown file';\r\n const chunks = args?.ReplacementChunks || args?.edits || [];\r\n let output = `${statusLabel} The assistant made ${chunks.length || 'multiple'} edits to file: \\`${filePath}\\``;\r\n\r\n // Include each edit\r\n if (Array.isArray(chunks) && chunks.length > 0) {\r\n output += `\\n\\nEdits made:`;\r\n chunks.slice(0, 5).forEach((chunk: any, i: number) => {\r\n const target = chunk.TargetContent || chunk.target_content || '';\r\n const replacement = chunk.ReplacementContent || chunk.replacement_content || '';\r\n output += `\\n\\n**Edit ${i + 1}:**`;\r\n if (target) {\r\n output += `\\nOriginal:\\n\\`\\`\\`\\n${truncate(target, 300)}\\n\\`\\`\\``;\r\n }\r\n if (replacement) {\r\n output += `\\nReplaced with:\\n\\`\\`\\`\\n${truncate(replacement, 300)}\\n\\`\\`\\``;\r\n }\r\n });\r\n if (chunks.length > 5) {\r\n output += `\\n\\n... and ${chunks.length - 5} more edits`;\r\n }\r\n }\r\n return output;\r\n }\r\n\r\n case 'list_dir': {\r\n const dirPath = args?.DirectoryPath || args?.directory || 'unknown directory';\r\n let output = `${statusLabel} The assistant listed directory: \\`${dirPath}\\``;\r\n if (cleanResult) {\r\n output += `\\n\\nContents:\\n\\`\\`\\`\\n${truncate(cleanResult, 1000)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'grep_search': {\r\n const query = args?.Query || args?.query || 'unknown query';\r\n let output = `${statusLabel} The assistant searched for: \"${query}\"`;\r\n if (cleanResult) {\r\n output += `\\n\\nSearch results:\\n\\`\\`\\`\\n${truncate(cleanResult, 1500)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'find_files':\r\n case 'find_by_name': {\r\n const pattern = args?.pattern || args?.Pattern || '*';\r\n let output = `${statusLabel} The assistant searched for files matching: \"${pattern}\"`;\r\n if (cleanResult) {\r\n output += `\\n\\nFiles found:\\n\\`\\`\\`\\n${truncate(cleanResult, 1000)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'web_search':\r\n case 'search_web': {\r\n const query = args?.query || 'unknown query';\r\n let output = `${statusLabel} The assistant searched the web for: \"${query}\"`;\r\n if (cleanResult) {\r\n output += `\\n\\nSearch results:\\n${truncate(cleanResult, 2000)}`;\r\n }\r\n return output;\r\n }\r\n\r\n case 'fetch_url':\r\n case 'read_url_content': {\r\n const url = args?.url || args?.Url || 'unknown URL';\r\n let output = `${statusLabel} The assistant fetched URL: ${url}`;\r\n if (cleanResult) {\r\n output += `\\n\\nContent:\\n${truncate(cleanResult, 2000)}`;\r\n }\r\n return output;\r\n }\r\n\r\n case 'view_code_item':\r\n case 'inspect_symbol': {\r\n const filePath = args?.filePath || args?.File || 'unknown file';\r\n const nodePaths = args?.NodePaths || args?.symbols || [];\r\n let output = `${statusLabel} The assistant inspected code in: \\`${filePath}\\``;\r\n if (Array.isArray(nodePaths) && nodePaths.length > 0) {\r\n output += ` (symbols: ${nodePaths.join(', ')})`;\r\n }\r\n if (cleanResult) {\r\n output += `\\n\\nCode:\\n\\`\\`\\`\\n${truncate(cleanResult)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'view_file_outline': {\r\n const filePath = args?.AbsolutePath || 'unknown file';\r\n let output = `${statusLabel} The assistant viewed outline of: \\`${filePath}\\``;\r\n if (cleanResult) {\r\n output += `\\n\\nOutline:\\n\\`\\`\\`\\n${truncate(cleanResult, 1500)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n case 'read_binary_file': {\r\n const filePath = args?.file_path || 'unknown file';\r\n return `${statusLabel} The assistant uploaded binary file: \\`${filePath}\\``;\r\n }\r\n\r\n case 'create_image':\r\n case 'generate_image': {\r\n const outputPath = args?.output_path || args?.ImageName || 'unknown path';\r\n const prompt = args?.Prompt || args?.image_prompt || '';\r\n let output = `${statusLabel} The assistant generated an image: \\`${outputPath}\\``;\r\n if (prompt) {\r\n output += `\\n\\nPrompt used: \"${truncate(prompt, 500)}\"`;\r\n }\r\n return output;\r\n }\r\n\r\n default: {\r\n // Check for MCP tools (mcp_servername_toolname)\r\n if (toolName.startsWith('mcp_')) {\r\n const parts = toolName.slice(4).split('_');\r\n const serverName = parts[0] || 'unknown';\r\n const mcpToolName = parts.slice(1).join('_') || 'unknown';\r\n let output = `${statusLabel} The assistant used MCP tool: ${serverName}.${mcpToolName}`;\r\n\r\n // Include the full MCP result\r\n if (cleanResult) {\r\n output += `\\n\\nResult:\\n\\`\\`\\`\\n${truncate(cleanResult)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n\r\n // Generic tool formatting\r\n let output = `${statusLabel} The assistant used tool: ${toolName}`;\r\n if (cleanResult) {\r\n output += `\\n\\nResult:\\n\\`\\`\\`\\n${truncate(cleanResult, 1000)}\\n\\`\\`\\``;\r\n }\r\n return output;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Format a single message into human-readable text.\r\n */\r\nfunction formatMessage(message: Message): string {\r\n const { role, content, toolExecution, isCommandMode, taskCompletion, planAccepted, planQuestion, connectionStatus } = message;\r\n\r\n // Skip system messages (but not special plan/task messages)\r\n if (role === 'system' && !taskCompletion && !planAccepted && !planQuestion && !connectionStatus && content) {\r\n return '';\r\n }\r\n\r\n // Handle connection status messages\r\n if (connectionStatus) {\r\n const { type, status, connectionString, error: connError } = connectionStatus;\r\n if (status === 'connected') {\r\n return `Connected to ${type.toUpperCase()}: ${connectionString || 'session'}`;\r\n } else if (status === 'disconnected') {\r\n return `Disconnected from ${type.toUpperCase()} session`;\r\n } else if (status === 'error') {\r\n return `${type.toUpperCase()} connection error: ${connError || 'unknown error'}`;\r\n }\r\n return '';\r\n }\r\n\r\n // Handle plan question messages\r\n if (planQuestion) {\r\n const { question, options, userAnswer, wasSkipped } = planQuestion;\r\n let output = `Q: ${question}\\nOptions: ${options.map((o, i) => `${i + 1}. ${o}`).join(', ')}`;\r\n if (wasSkipped) {\r\n output += `\\nAnswer: (skipped)`;\r\n } else {\r\n output += `\\nAnswer: ${userAnswer}`;\r\n }\r\n return output;\r\n }\r\n\r\n // Handle plan accepted messages\r\n if (planAccepted) {\r\n const { planTitle, totalSteps } = planAccepted;\r\n return `Plan accepted: \"${planTitle || 'Implementation Plan'}\" with ${totalSteps || 0} steps`;\r\n }\r\n\r\n // Handle task completion messages\r\n if (taskCompletion) {\r\n const { completedStepNumber, totalCount, completedStepDescription, completionNote } = taskCompletion;\r\n let output = `Step ${completedStepNumber}/${totalCount} completed: ${completedStepDescription}`;\r\n if (completionNote) {\r\n output += `\\nNote: ${completionNote}`;\r\n }\r\n return output;\r\n }\r\n\r\n // Handle tool execution messages\r\n if (toolExecution) {\r\n return formatToolExecution(toolExecution);\r\n }\r\n\r\n // Handle user messages\r\n if (role === 'user') {\r\n if (isCommandMode) {\r\n return `## User (Terminal Command)\\n\\`\\`\\`\\n${content}\\n\\`\\`\\``;\r\n }\r\n return `## User\\n${content}`;\r\n }\r\n\r\n // Handle assistant messages\r\n if (role === 'assistant') {\r\n if (content && content.trim()) {\r\n return `## Assistant\\n${content}`;\r\n }\r\n return '';\r\n }\r\n\r\n // Handle tool result messages (usually internal, skip)\r\n if (role === 'tool') {\r\n return '';\r\n }\r\n\r\n return '';\r\n}\r\n\r\n/**\r\n * Format entire chat history into human-readable text for clipboard sharing.\r\n */\r\nexport function formatChatForClipboard(messages: Message[]): string {\r\n const header = `# Chat Session Export\r\nGenerated: ${new Date().toLocaleString()}\r\n---\r\n\r\n`;\r\n\r\n const formattedMessages = messages\r\n .map(formatMessage)\r\n .filter(text => text.trim() !== '')\r\n .join('\\n\\n---\\n\\n');\r\n\r\n if (!formattedMessages) {\r\n return cleanUnicode(header + 'No messages in this chat session.');\r\n }\r\n\r\n return cleanUnicode(header + formattedMessages);\r\n}\r\n"],"mappings":"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","names":["output"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CustomCommandsManager } from "./custom-commands-manager.js";
|
|
2
|
+
import { TunnelCommandsManager } from "./tunnel-commands-manager.js";
|
|
2
3
|
const SLASH_COMMANDS = /* @__PURE__ */ new Set([
|
|
3
4
|
"help",
|
|
4
5
|
"h",
|
|
@@ -43,7 +44,11 @@ const SLASH_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
43
44
|
"workflow",
|
|
44
45
|
"wf",
|
|
45
46
|
"rules",
|
|
46
|
-
"revert"
|
|
47
|
+
"revert",
|
|
48
|
+
"sub-agent",
|
|
49
|
+
"subagent",
|
|
50
|
+
"compact",
|
|
51
|
+
"skill"
|
|
47
52
|
]);
|
|
48
53
|
const DEFINITE_COMMANDS = /* @__PURE__ */ new Set([
|
|
49
54
|
// Package Managers
|
|
@@ -968,6 +973,11 @@ function detectIntent(input) {
|
|
|
968
973
|
if (customCommandsManager.hasCommand(firstWord)) {
|
|
969
974
|
return "command";
|
|
970
975
|
}
|
|
976
|
+
const tunnelCommandsManager = TunnelCommandsManager.getInstance();
|
|
977
|
+
tunnelCommandsManager.loadSync();
|
|
978
|
+
if (tunnelCommandsManager.matchCommand(trimmed)) {
|
|
979
|
+
return "command";
|
|
980
|
+
}
|
|
971
981
|
if (AMBIGUOUS_COMMANDS.has(firstWord)) {
|
|
972
982
|
return disambiguateCommand(trimmed, words);
|
|
973
983
|
}
|