snow-ai 0.3.5 → 0.3.7

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.
Files changed (101) hide show
  1. package/dist/agents/reviewAgent.d.ts +50 -0
  2. package/dist/agents/reviewAgent.js +264 -0
  3. package/dist/api/anthropic.js +104 -71
  4. package/dist/api/chat.d.ts +1 -1
  5. package/dist/api/chat.js +60 -41
  6. package/dist/api/gemini.js +97 -57
  7. package/dist/api/responses.d.ts +9 -1
  8. package/dist/api/responses.js +110 -70
  9. package/dist/api/systemPrompt.d.ts +1 -1
  10. package/dist/api/systemPrompt.js +36 -7
  11. package/dist/api/types.d.ts +8 -0
  12. package/dist/hooks/useCommandHandler.d.ts +1 -0
  13. package/dist/hooks/useCommandHandler.js +44 -1
  14. package/dist/hooks/useCommandPanel.js +13 -0
  15. package/dist/hooks/useConversation.d.ts +4 -1
  16. package/dist/hooks/useConversation.js +65 -9
  17. package/dist/hooks/useKeyboardInput.js +19 -0
  18. package/dist/hooks/useTerminalFocus.js +13 -3
  19. package/dist/mcp/aceCodeSearch.d.ts +2 -76
  20. package/dist/mcp/aceCodeSearch.js +31 -467
  21. package/dist/mcp/bash.d.ts +1 -8
  22. package/dist/mcp/bash.js +20 -40
  23. package/dist/mcp/filesystem.d.ts +3 -68
  24. package/dist/mcp/filesystem.js +32 -348
  25. package/dist/mcp/ideDiagnostics.js +2 -4
  26. package/dist/mcp/todo.d.ts +1 -17
  27. package/dist/mcp/todo.js +11 -15
  28. package/dist/mcp/types/aceCodeSearch.types.d.ts +92 -0
  29. package/dist/mcp/types/aceCodeSearch.types.js +4 -0
  30. package/dist/mcp/types/bash.types.d.ts +13 -0
  31. package/dist/mcp/types/bash.types.js +4 -0
  32. package/dist/mcp/types/filesystem.types.d.ts +44 -0
  33. package/dist/mcp/types/filesystem.types.js +4 -0
  34. package/dist/mcp/types/todo.types.d.ts +27 -0
  35. package/dist/mcp/types/todo.types.js +4 -0
  36. package/dist/mcp/types/websearch.types.d.ts +30 -0
  37. package/dist/mcp/types/websearch.types.js +4 -0
  38. package/dist/mcp/utils/aceCodeSearch/filesystem.utils.d.ts +34 -0
  39. package/dist/mcp/utils/aceCodeSearch/filesystem.utils.js +146 -0
  40. package/dist/mcp/utils/aceCodeSearch/language.utils.d.ts +14 -0
  41. package/dist/mcp/utils/aceCodeSearch/language.utils.js +99 -0
  42. package/dist/mcp/utils/aceCodeSearch/search.utils.d.ts +31 -0
  43. package/dist/mcp/utils/aceCodeSearch/search.utils.js +136 -0
  44. package/dist/mcp/utils/aceCodeSearch/symbol.utils.d.ts +20 -0
  45. package/dist/mcp/utils/aceCodeSearch/symbol.utils.js +141 -0
  46. package/dist/mcp/utils/bash/security.utils.d.ts +20 -0
  47. package/dist/mcp/utils/bash/security.utils.js +34 -0
  48. package/dist/mcp/utils/filesystem/code-analysis.utils.d.ts +18 -0
  49. package/dist/mcp/utils/filesystem/code-analysis.utils.js +165 -0
  50. package/dist/mcp/utils/filesystem/match-finder.utils.d.ts +16 -0
  51. package/dist/mcp/utils/filesystem/match-finder.utils.js +85 -0
  52. package/dist/mcp/utils/filesystem/similarity.utils.d.ts +22 -0
  53. package/dist/mcp/utils/filesystem/similarity.utils.js +75 -0
  54. package/dist/mcp/utils/todo/date.utils.d.ts +9 -0
  55. package/dist/mcp/utils/todo/date.utils.js +14 -0
  56. package/dist/mcp/utils/websearch/browser.utils.d.ts +8 -0
  57. package/dist/mcp/utils/websearch/browser.utils.js +58 -0
  58. package/dist/mcp/utils/websearch/text.utils.d.ts +16 -0
  59. package/dist/mcp/utils/websearch/text.utils.js +39 -0
  60. package/dist/mcp/websearch.d.ts +1 -31
  61. package/dist/mcp/websearch.js +21 -97
  62. package/dist/ui/components/ChatInput.d.ts +2 -1
  63. package/dist/ui/components/ChatInput.js +10 -3
  64. package/dist/ui/components/MarkdownRenderer.d.ts +1 -2
  65. package/dist/ui/components/MarkdownRenderer.js +16 -153
  66. package/dist/ui/components/MessageList.js +4 -4
  67. package/dist/ui/components/SessionListScreen.js +37 -17
  68. package/dist/ui/components/ToolResultPreview.js +27 -7
  69. package/dist/ui/components/UsagePanel.d.ts +2 -0
  70. package/dist/ui/components/UsagePanel.js +360 -0
  71. package/dist/ui/pages/ChatScreen.d.ts +4 -0
  72. package/dist/ui/pages/ChatScreen.js +70 -30
  73. package/dist/ui/pages/ConfigScreen.js +23 -19
  74. package/dist/ui/pages/HeadlessModeScreen.js +2 -4
  75. package/dist/ui/pages/SubAgentConfigScreen.js +17 -17
  76. package/dist/ui/pages/SystemPromptConfigScreen.js +7 -6
  77. package/dist/utils/commandExecutor.d.ts +3 -3
  78. package/dist/utils/commandExecutor.js +4 -4
  79. package/dist/utils/commands/home.d.ts +2 -0
  80. package/dist/utils/commands/home.js +12 -0
  81. package/dist/utils/commands/review.d.ts +2 -0
  82. package/dist/utils/commands/review.js +81 -0
  83. package/dist/utils/commands/role.d.ts +2 -0
  84. package/dist/utils/commands/role.js +37 -0
  85. package/dist/utils/commands/usage.d.ts +2 -0
  86. package/dist/utils/commands/usage.js +12 -0
  87. package/dist/utils/contextCompressor.js +99 -367
  88. package/dist/utils/fileUtils.js +3 -3
  89. package/dist/utils/mcpToolsManager.js +12 -12
  90. package/dist/utils/proxyUtils.d.ts +15 -0
  91. package/dist/utils/proxyUtils.js +50 -0
  92. package/dist/utils/retryUtils.d.ts +27 -0
  93. package/dist/utils/retryUtils.js +114 -2
  94. package/dist/utils/sessionManager.d.ts +2 -5
  95. package/dist/utils/sessionManager.js +16 -83
  96. package/dist/utils/terminal.js +4 -3
  97. package/dist/utils/usageLogger.d.ts +11 -0
  98. package/dist/utils/usageLogger.js +99 -0
  99. package/package.json +3 -7
  100. package/dist/agents/summaryAgent.d.ts +0 -31
  101. package/dist/agents/summaryAgent.js +0 -256
@@ -1,159 +1,22 @@
1
1
  import React from 'react';
2
- import { Box, Text } from 'ink';
2
+ import { Text } from 'ink';
3
3
  import { highlight } from 'cli-highlight';
4
- export default function MarkdownRenderer({ content, color }) {
5
- const blocks = parseMarkdown(content);
6
- return (React.createElement(Box, { flexDirection: "column" }, blocks.map((block, index) => {
7
- if (block.type === 'code') {
8
- return (React.createElement(Box, { key: index, flexDirection: "column", marginY: 0 },
9
- React.createElement(Box, { borderStyle: "round", borderColor: "blue" },
10
- React.createElement(Box, { flexDirection: "column" },
11
- block.language && (React.createElement(Text, { backgroundColor: "green", color: "white" }, block.language)),
12
- React.createElement(Text, null, highlightCode(block.code, block.language))))));
13
- }
14
- // Render heading
15
- if (block.type === 'heading') {
16
- const headingColors = ['cyan', 'blue', 'magenta', 'yellow'];
17
- const headingColor = headingColors[block.level - 1] || 'white';
18
- return (React.createElement(Box, { key: index, marginY: 0 },
19
- React.createElement(Text, { bold: true, color: headingColor }, renderInlineFormatting(block.content))));
20
- }
21
- // Render list
22
- if (block.type === 'list') {
23
- return (React.createElement(Box, { key: index, flexDirection: "column", marginY: 0 }, block.items.map((item, itemIndex) => (React.createElement(Box, { key: itemIndex },
24
- React.createElement(Text, { color: "yellow" }, "\u2022 "),
25
- React.createElement(Text, { color: color }, renderInlineFormatting(item)))))));
26
- }
27
- // Render text with inline formatting
28
- return (React.createElement(Box, { key: index, flexDirection: "column" }, block.content
29
- .split('\n')
30
- .map((line, lineIndex) => (React.createElement(Text, { key: lineIndex, color: color }, line === '' ? ' ' : renderInlineFormatting(line))))));
31
- })));
32
- }
33
- function parseMarkdown(content) {
34
- const blocks = [];
35
- const lines = content.split('\n');
36
- let i = 0;
37
- while (i < lines.length) {
38
- const line = lines[i] ?? '';
39
- // Check for code block - support ```language or just ```
40
- const codeBlockMatch = line.match(/^```(.*)$/);
41
- if (codeBlockMatch) {
42
- const language = codeBlockMatch[1]?.trim() || '';
43
- const codeLines = [];
44
- i++;
45
- // Collect code block lines
46
- while (i < lines.length) {
47
- const currentLine = lines[i] ?? '';
48
- if (currentLine.trim().startsWith('```')) {
49
- break;
50
- }
51
- codeLines.push(currentLine);
52
- i++;
53
- }
54
- blocks.push({
55
- type: 'code',
56
- language,
57
- code: codeLines.join('\n'),
58
- });
59
- i++; // Skip closing ```
60
- continue;
61
- }
62
- // Check for heading (# ## ### ####)
63
- const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
64
- if (headingMatch) {
65
- blocks.push({
66
- type: 'heading',
67
- level: headingMatch[1].length,
68
- content: headingMatch[2].trim(),
69
- });
70
- i++;
71
- continue;
72
- }
73
- // Check for list item (* or -)
74
- const listMatch = line.match(/^[\s]*[*\-]\s+(.+)$/);
75
- if (listMatch) {
76
- const listItems = [listMatch[1].trim()];
77
- i++;
78
- // Collect consecutive list items
79
- while (i < lines.length) {
80
- const currentLine = lines[i] ?? '';
81
- const nextListMatch = currentLine.match(/^[\s]*[*\-]\s+(.+)$/);
82
- if (!nextListMatch) {
83
- break;
84
- }
85
- listItems.push(nextListMatch[1].trim());
86
- i++;
4
+ // @ts-expect-error - cli-markdown doesn't have TypeScript definitions
5
+ import cliMarkdown from 'cli-markdown';
6
+ export default function MarkdownRenderer({ content }) {
7
+ // Use cli-markdown for elegant markdown rendering with syntax highlighting
8
+ const rendered = cliMarkdown(content, {
9
+ // Enable syntax highlighting for code blocks
10
+ code: (code, language) => {
11
+ if (!language)
12
+ return code;
13
+ try {
14
+ return highlight(code, { language, ignoreIllegals: true });
87
15
  }
88
- blocks.push({
89
- type: 'list',
90
- items: listItems,
91
- });
92
- continue;
93
- }
94
- // Collect text lines until next code block, heading, or list
95
- const textLines = [];
96
- while (i < lines.length) {
97
- const currentLine = lines[i] ?? '';
98
- if (currentLine.trim().startsWith('```') ||
99
- currentLine.match(/^#{1,6}\s+/) ||
100
- currentLine.match(/^[\s]*[*\-]\s+/)) {
101
- break;
16
+ catch {
17
+ return code;
102
18
  }
103
- textLines.push(currentLine);
104
- i++;
105
- }
106
- if (textLines.length > 0) {
107
- blocks.push({
108
- type: 'text',
109
- content: textLines.join('\n'),
110
- });
111
- }
112
- }
113
- return blocks;
114
- }
115
- function highlightCode(code, language) {
116
- try {
117
- // If no language specified, try to auto-detect or just return the code
118
- if (!language) {
119
- return code;
120
- }
121
- // Map common language aliases to cli-highlight supported names
122
- const languageMap = {
123
- js: 'javascript',
124
- ts: 'typescript',
125
- py: 'python',
126
- rb: 'ruby',
127
- sh: 'bash',
128
- shell: 'bash',
129
- cs: 'csharp',
130
- 'c#': 'csharp',
131
- cpp: 'cpp',
132
- 'c++': 'cpp',
133
- yml: 'yaml',
134
- md: 'markdown',
135
- };
136
- const mappedLanguage = languageMap[language.toLowerCase()] || language.toLowerCase();
137
- return highlight(code, { language: mappedLanguage, ignoreIllegals: true });
138
- }
139
- catch {
140
- // If highlighting fails, return the code as-is
141
- return code;
142
- }
143
- }
144
- function renderInlineFormatting(text) {
145
- // Handle inline code `code` - remove backticks
146
- text = text.replace(/`([^`]+)`/g, (_, code) => {
147
- // Use ANSI codes for inline code styling
148
- return `\x1b[36m${code}\x1b[0m`;
149
- });
150
- // Handle bold **text** or __text__ - remove markers
151
- text = text.replace(/(\*\*|__)([^*_]+)\1/g, (_, __, content) => {
152
- return `\x1b[1m${content}\x1b[0m`;
153
- });
154
- // Handle italic *text* or _text_ (but not part of bold) - remove markers
155
- text = text.replace(/(?<!\*)(\*)(?!\*)([^*]+)\1(?!\*)/g, (_, __, content) => {
156
- return `\x1b[3m${content}\x1b[0m`;
19
+ },
157
20
  });
158
- return text;
21
+ return React.createElement(Text, null, rendered);
159
22
  }
@@ -24,7 +24,7 @@ const MessageList = memo(({ messages, animationFrame, maxMessages = 6 }) => {
24
24
  : message.role === 'subagent'
25
25
  ? '◈'
26
26
  : '❆'),
27
- React.createElement(Box, { marginLeft: 1, marginBottom: 1, flexDirection: "column" }, message.role === 'command' ? (React.createElement(Text, { color: "gray" },
27
+ React.createElement(Box, { marginLeft: 1, flexDirection: "column" }, message.role === 'command' ? (React.createElement(Text, { color: "gray" },
28
28
  "\u2514\u2500 ",
29
29
  message.commandName)) : message.role === 'subagent' ? (React.createElement(React.Fragment, null,
30
30
  React.createElement(Text, { color: "magenta", dimColor: true },
@@ -32,12 +32,12 @@ const MessageList = memo(({ messages, animationFrame, maxMessages = 6 }) => {
32
32
  message.subAgent?.agentName,
33
33
  message.subAgent?.isComplete ? ' ✓' : ' ...'),
34
34
  React.createElement(Box, { marginLeft: 2 },
35
- React.createElement(MarkdownRenderer, { content: message.content || ' ', color: "gray" })))) : (React.createElement(React.Fragment, null,
36
- React.createElement(MarkdownRenderer, { content: message.content || ' ', color: message.role === 'user' ? 'gray' : undefined }),
35
+ React.createElement(Text, { color: "gray" }, message.content || ' ')))) : (React.createElement(React.Fragment, null,
36
+ message.role === 'user' ? (React.createElement(Text, { color: "gray" }, message.content || ' ')) : (React.createElement(MarkdownRenderer, { content: message.content || ' ' })),
37
37
  (message.systemInfo ||
38
38
  message.files ||
39
39
  message.files ||
40
- message.images) && (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
40
+ message.images) && (React.createElement(Box, { flexDirection: "column" },
41
41
  message.systemInfo && (React.createElement(React.Fragment, null,
42
42
  React.createElement(Text, { color: "gray", dimColor: true },
43
43
  "\u2514\u2500 Platform: ",
@@ -3,7 +3,7 @@ import { Box, Text, useInput, useStdout } from 'ink';
3
3
  import Gradient from 'ink-gradient';
4
4
  import { Alert } from '@inkjs/ui';
5
5
  import ScrollableSelectInput from './ScrollableSelectInput.js';
6
- import { sessionManager } from '../../utils/sessionManager.js';
6
+ import { sessionManager, } from '../../utils/sessionManager.js';
7
7
  export default function SessionListScreen({ onBack, onSelectSession }) {
8
8
  const [sessions, setSessions] = useState([]);
9
9
  const [loading, setLoading] = useState(true);
@@ -53,22 +53,35 @@ export default function SessionListScreen({ onBack, onSelectSession }) {
53
53
  // Create select items with truncated labels
54
54
  const selectItems = useMemo(() => {
55
55
  const terminalWidth = stdout?.columns || 80;
56
- // Increase margin and ensure minimum width
57
- const maxLabelWidth = Math.max(20, terminalWidth - 20);
56
+ // Reserve space for indicators (✔ + ❯ + spacing) and margins
57
+ const reservedSpace = 30;
58
+ const maxLabelWidth = Math.max(30, terminalWidth - reservedSpace);
58
59
  return sessions.map(session => {
59
60
  const timeString = formatDate(session.updatedAt);
60
61
  const title = session.title || 'Untitled';
61
- const label = `${title} (${session.messageCount}) - ${timeString}`;
62
- // Truncate if too long with safer boundary check
63
- let truncatedLabel = label;
64
- if (label.length > maxLabelWidth) {
65
- const maxLength = Math.max(10, maxLabelWidth - 3);
66
- truncatedLabel = label.substring(0, maxLength) + '...';
62
+ // Format: "Title 5 msgs • 2h ago"
63
+ const messageInfo = `${session.messageCount} msg${session.messageCount !== 1 ? 's' : ''}`;
64
+ const fullLabel = `${title} • ${messageInfo} • ${timeString}`;
65
+ // Truncate if too long - prioritize showing the title
66
+ let truncatedLabel = fullLabel;
67
+ if (fullLabel.length > maxLabelWidth) {
68
+ const ellipsis = '...';
69
+ const suffixLength = messageInfo.length + timeString.length + 6; // " • " x2 + "..."
70
+ const availableForTitle = maxLabelWidth - suffixLength - ellipsis.length;
71
+ if (availableForTitle > 10) {
72
+ const truncatedTitle = title.substring(0, availableForTitle);
73
+ truncatedLabel = `${truncatedTitle}${ellipsis} • ${messageInfo} • ${timeString}`;
74
+ }
75
+ else {
76
+ // If terminal is too narrow, just truncate the whole thing
77
+ truncatedLabel =
78
+ fullLabel.substring(0, maxLabelWidth - ellipsis.length) + ellipsis;
79
+ }
67
80
  }
68
81
  return {
69
82
  label: truncatedLabel,
70
83
  value: session.id,
71
- isMarked: selectedSessions.has(session.id)
84
+ isMarked: selectedSessions.has(session.id),
72
85
  };
73
86
  });
74
87
  }, [sessions, formatDate, stdout?.columns, selectedSessions]);
@@ -96,10 +109,14 @@ export default function SessionListScreen({ onBack, onSelectSession }) {
96
109
  const ids = Array.from(selectedSessions);
97
110
  const deletionResults = await Promise.all(ids.map(async (id) => ({
98
111
  id,
99
- success: await sessionManager.deleteSession(id)
112
+ success: await sessionManager.deleteSession(id),
100
113
  })));
101
- const succeededIds = deletionResults.filter(result => result.success).map(result => result.id);
102
- const failedIds = deletionResults.filter(result => !result.success).map(result => result.id);
114
+ const succeededIds = deletionResults
115
+ .filter(result => result.success)
116
+ .map(result => result.id);
117
+ const failedIds = deletionResults
118
+ .filter(result => !result.success)
119
+ .map(result => result.id);
103
120
  if (succeededIds.length > 0) {
104
121
  setSessions(previous => previous.filter(session => !succeededIds.includes(session.id)));
105
122
  setSelectedSessions(previous => {
@@ -113,13 +130,13 @@ export default function SessionListScreen({ onBack, onSelectSession }) {
113
130
  if (failedIds.length > 0) {
114
131
  setActionMessage({
115
132
  type: 'error',
116
- text: `Failed to delete ${failedIds.length} conversation${failedIds.length > 1 ? 's' : ''}.`
133
+ text: `Failed to delete ${failedIds.length} conversation${failedIds.length > 1 ? 's' : ''}.`,
117
134
  });
118
135
  }
119
136
  else if (succeededIds.length > 0) {
120
137
  setActionMessage({
121
138
  type: 'info',
122
- text: `Deleted ${succeededIds.length} conversation${succeededIds.length > 1 ? 's' : ''}.`
139
+ text: `Deleted ${succeededIds.length} conversation${succeededIds.length > 1 ? 's' : ''}.`,
123
140
  });
124
141
  }
125
142
  else {
@@ -182,7 +199,8 @@ export default function SessionListScreen({ onBack, onSelectSession }) {
182
199
  sessions.length,
183
200
  " conversation",
184
201
  sessions.length !== 1 ? 's' : '',
185
- " available"))),
202
+ ' ',
203
+ "available"))),
186
204
  React.createElement(Box, { marginBottom: 1, flexShrink: 0 },
187
205
  React.createElement(ScrollableSelectInput, { items: selectItems, limit: listLimit, onSelect: handleSelect, onToggleItem: handleToggleItem, onDeleteSelection: handleDeleteSelected, selectedValues: selectedSessions, indicator: ({ isSelected }) => (React.createElement(Text, { color: isSelected ? 'green' : 'gray' }, isSelected ? '❯ ' : ' ')), renderItem: ({ isSelected, isMarked, label }) => (React.createElement(Text, null,
188
206
  React.createElement(Text, { color: isMarked ? 'green' : 'gray' }, isMarked ? '✔ ' : ' '),
@@ -192,5 +210,7 @@ export default function SessionListScreen({ onBack, onSelectSession }) {
192
210
  React.createElement(Alert, { variant: actionMessage.type }, actionMessage.text))) : null,
193
211
  React.createElement(Alert, { variant: "info" },
194
212
  "\u2191\u2193 navigate \u2022 Space mark \u2022 D delete \u2022 Enter select \u2022 Esc return \u2022 R refresh",
195
- selectedSessions.size > 0 ? ` • ${selectedSessions.size} selected` : ''))));
213
+ selectedSessions.size > 0
214
+ ? ` • ${selectedSessions.size} selected`
215
+ : ''))));
196
216
  }
@@ -9,7 +9,10 @@ export default function ToolResultPreview({ toolName, result, maxLines = 5 }) {
9
9
  // Try to parse JSON result
10
10
  const data = JSON.parse(result);
11
11
  // Handle different tool types
12
- if (toolName === 'filesystem-read') {
12
+ if (toolName.startsWith('subagent-')) {
13
+ return renderSubAgentPreview(data, maxLines);
14
+ }
15
+ else if (toolName === 'filesystem-read') {
13
16
  return renderReadPreview(data, maxLines);
14
17
  }
15
18
  else if (toolName === 'filesystem-list') {
@@ -40,6 +43,23 @@ export default function ToolResultPreview({ toolName, result, maxLines = 5 }) {
40
43
  return null;
41
44
  }
42
45
  }
46
+ function renderSubAgentPreview(data, maxLines) {
47
+ // Sub-agent results have format: { success: boolean, result: string }
48
+ if (!data.result)
49
+ return null;
50
+ // Split the result into lines
51
+ const lines = data.result.split('\n').filter((line) => line.trim());
52
+ const previewLines = lines.slice(0, maxLines);
53
+ const hasMore = lines.length > maxLines;
54
+ return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
55
+ previewLines.map((line, idx) => (React.createElement(Text, { key: idx, color: "gray", dimColor: true },
56
+ idx === previewLines.length - 1 && !hasMore ? '└─ ' : '├─ ',
57
+ line.length > 80 ? line.slice(0, 80) + '...' : line))),
58
+ hasMore && (React.createElement(Text, { color: "gray", dimColor: true },
59
+ "\u2514\u2500 ... (",
60
+ lines.length - maxLines,
61
+ " more lines)"))));
62
+ }
43
63
  function renderReadPreview(data, maxLines) {
44
64
  if (!data.content)
45
65
  return null;
@@ -77,7 +97,7 @@ function renderListPreview(data, maxLines) {
77
97
  }
78
98
  function renderACEPreview(toolName, data, maxLines) {
79
99
  // Handle ace-text-search results
80
- if (toolName === 'ace-text-search' || toolName === 'ace_text_search') {
100
+ if (toolName === 'ace-text-search' || toolName === 'ace-text_search') {
81
101
  if (!data || data.length === 0) {
82
102
  return (React.createElement(Box, { marginLeft: 2 },
83
103
  React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 No matches found")));
@@ -100,7 +120,7 @@ function renderACEPreview(toolName, data, maxLines) {
100
120
  " more matches)"))));
101
121
  }
102
122
  // Handle ace-search-symbols results
103
- if (toolName === 'ace-search-symbols' || toolName === 'ace_search_symbols') {
123
+ if (toolName === 'ace-search-symbols' || toolName === 'ace-search_symbols') {
104
124
  const symbols = data.symbols || [];
105
125
  if (symbols.length === 0) {
106
126
  return (React.createElement(Box, { marginLeft: 2 },
@@ -124,7 +144,7 @@ function renderACEPreview(toolName, data, maxLines) {
124
144
  " more symbols)"))));
125
145
  }
126
146
  // Handle ace-find-references results
127
- if (toolName === 'ace-find-references' || toolName === 'ace_find_references') {
147
+ if (toolName === 'ace-find-references' || toolName === 'ace-find_references') {
128
148
  const references = Array.isArray(data) ? data : [];
129
149
  if (references.length === 0) {
130
150
  return (React.createElement(Box, { marginLeft: 2 },
@@ -146,7 +166,7 @@ function renderACEPreview(toolName, data, maxLines) {
146
166
  " more references)"))));
147
167
  }
148
168
  // Handle ace-find-definition result
149
- if (toolName === 'ace-find-definition' || toolName === 'ace_find_definition') {
169
+ if (toolName === 'ace-find-definition' || toolName === 'ace-find_definition') {
150
170
  if (!data) {
151
171
  return (React.createElement(Box, { marginLeft: 2 },
152
172
  React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 Definition not found")));
@@ -163,7 +183,7 @@ function renderACEPreview(toolName, data, maxLines) {
163
183
  data.line)));
164
184
  }
165
185
  // Handle ace-file-outline result
166
- if (toolName === 'ace-file-outline' || toolName === 'ace_file_outline') {
186
+ if (toolName === 'ace-file-outline' || toolName === 'ace-file_outline') {
167
187
  const symbols = Array.isArray(data) ? data : [];
168
188
  if (symbols.length === 0) {
169
189
  return (React.createElement(Box, { marginLeft: 2 },
@@ -186,7 +206,7 @@ function renderACEPreview(toolName, data, maxLines) {
186
206
  " more symbols)"))));
187
207
  }
188
208
  // Handle ace-semantic-search result
189
- if (toolName === 'ace-semantic-search' || toolName === 'ace_semantic_search') {
209
+ if (toolName === 'ace-semantic-search' || toolName === 'ace-semantic_search') {
190
210
  const totalResults = (data.symbols?.length || 0) + (data.references?.length || 0);
191
211
  if (totalResults === 0) {
192
212
  return (React.createElement(Box, { marginLeft: 2 },
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export default function UsagePanel(): React.JSX.Element;