snow-ai 0.3.7 → 0.3.8
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/agents/compactAgent.js +7 -3
- package/dist/agents/summaryAgent.d.ts +57 -0
- package/dist/agents/summaryAgent.js +259 -0
- package/dist/api/anthropic.d.ts +1 -0
- package/dist/api/anthropic.js +20 -13
- package/dist/api/chat.d.ts +1 -0
- package/dist/api/chat.js +23 -12
- package/dist/api/gemini.d.ts +1 -0
- package/dist/api/gemini.js +14 -8
- package/dist/api/responses.d.ts +1 -0
- package/dist/api/responses.js +23 -15
- package/dist/app.js +15 -2
- package/dist/hooks/useCommandHandler.js +58 -0
- package/dist/hooks/useCommandPanel.d.ts +2 -1
- package/dist/hooks/useCommandPanel.js +6 -1
- package/dist/hooks/useConversation.js +44 -24
- package/dist/hooks/useSnapshotState.d.ts +2 -0
- package/dist/mcp/filesystem.d.ts +131 -46
- package/dist/mcp/filesystem.js +188 -35
- package/dist/mcp/types/filesystem.types.d.ts +91 -0
- package/dist/mcp/utils/filesystem/batch-operations.utils.d.ts +39 -0
- package/dist/mcp/utils/filesystem/batch-operations.utils.js +182 -0
- package/dist/ui/components/ChatInput.d.ts +2 -1
- package/dist/ui/components/ChatInput.js +3 -3
- package/dist/ui/components/CommandPanel.d.ts +2 -1
- package/dist/ui/components/CommandPanel.js +18 -3
- package/dist/ui/components/MarkdownRenderer.js +10 -1
- package/dist/ui/components/MessageList.js +1 -1
- package/dist/ui/components/PendingMessages.js +1 -1
- package/dist/ui/components/PendingToolCalls.d.ts +11 -0
- package/dist/ui/components/PendingToolCalls.js +35 -0
- package/dist/ui/components/ToolResultPreview.d.ts +1 -1
- package/dist/ui/components/ToolResultPreview.js +116 -152
- package/dist/ui/pages/ChatScreen.d.ts +1 -0
- package/dist/ui/pages/ChatScreen.js +99 -60
- package/dist/utils/chatExporter.d.ts +9 -0
- package/dist/utils/chatExporter.js +126 -0
- package/dist/utils/commandExecutor.d.ts +1 -1
- package/dist/utils/commands/export.d.ts +2 -0
- package/dist/utils/commands/export.js +12 -0
- package/dist/utils/commands/init.js +3 -3
- package/dist/utils/fileDialog.d.ts +9 -0
- package/dist/utils/fileDialog.js +74 -0
- package/dist/utils/fileUtils.js +3 -3
- package/dist/utils/incrementalSnapshot.d.ts +7 -0
- package/dist/utils/incrementalSnapshot.js +35 -0
- package/dist/utils/messageFormatter.js +89 -6
- package/dist/utils/sessionConverter.js +11 -0
- package/dist/utils/sessionManager.d.ts +5 -0
- package/dist/utils/sessionManager.js +45 -0
- package/dist/utils/toolDisplayConfig.d.ts +16 -0
- package/dist/utils/toolDisplayConfig.js +42 -0
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -16,6 +16,9 @@ export default function App({ version, skipWelcome, headlessPrompt }) {
|
|
|
16
16
|
return (React.createElement(HeadlessModeScreen, { prompt: headlessPrompt, onComplete: () => process.exit(0) }));
|
|
17
17
|
}
|
|
18
18
|
const [currentView, setCurrentView] = useState(skipWelcome ? 'chat' : 'welcome');
|
|
19
|
+
// Add a key to force remount ChatScreen when returning from welcome screen
|
|
20
|
+
// This ensures configuration changes are picked up
|
|
21
|
+
const [chatScreenKey, setChatScreenKey] = useState(0);
|
|
19
22
|
const [exitNotification, setExitNotification] = useState({
|
|
20
23
|
show: false,
|
|
21
24
|
message: '',
|
|
@@ -27,16 +30,26 @@ export default function App({ version, skipWelcome, headlessPrompt }) {
|
|
|
27
30
|
// Global navigation handler
|
|
28
31
|
useEffect(() => {
|
|
29
32
|
const unsubscribe = onNavigate(event => {
|
|
33
|
+
// When navigating to welcome from chat (e.g., /home command),
|
|
34
|
+
// increment key so next time chat is entered, it remounts with fresh config
|
|
35
|
+
if (event.destination === 'welcome' && currentView === 'chat') {
|
|
36
|
+
setChatScreenKey(prev => prev + 1);
|
|
37
|
+
}
|
|
30
38
|
setCurrentView(event.destination);
|
|
31
39
|
});
|
|
32
40
|
return unsubscribe;
|
|
33
|
-
}, []);
|
|
41
|
+
}, [currentView]);
|
|
34
42
|
const handleMenuSelect = (value) => {
|
|
35
43
|
if (value === 'chat' ||
|
|
36
44
|
value === 'settings' ||
|
|
37
45
|
value === 'mcp' ||
|
|
38
46
|
value === 'systemprompt' ||
|
|
39
47
|
value === 'customheaders') {
|
|
48
|
+
// When entering chat from welcome screen, increment key to force remount
|
|
49
|
+
// This ensures any configuration changes are picked up
|
|
50
|
+
if (value === 'chat' && currentView === 'welcome') {
|
|
51
|
+
setChatScreenKey(prev => prev + 1);
|
|
52
|
+
}
|
|
40
53
|
setCurrentView(value);
|
|
41
54
|
}
|
|
42
55
|
else if (value === 'exit') {
|
|
@@ -48,7 +61,7 @@ export default function App({ version, skipWelcome, headlessPrompt }) {
|
|
|
48
61
|
case 'welcome':
|
|
49
62
|
return (React.createElement(WelcomeScreen, { version: version, onMenuSelect: handleMenuSelect }));
|
|
50
63
|
case 'chat':
|
|
51
|
-
return React.createElement(ChatScreen, { skipWelcome: skipWelcome });
|
|
64
|
+
return React.createElement(ChatScreen, { key: chatScreenKey, skipWelcome: skipWelcome });
|
|
52
65
|
case 'settings':
|
|
53
66
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
54
67
|
React.createElement(Text, { color: "blue" }, "Settings"),
|
|
@@ -4,6 +4,8 @@ import { sessionManager } from '../utils/sessionManager.js';
|
|
|
4
4
|
import { compressContext } from '../utils/contextCompressor.js';
|
|
5
5
|
import { navigateTo } from './useGlobalNavigation.js';
|
|
6
6
|
import { resetTerminal } from '../utils/terminal.js';
|
|
7
|
+
import { showSaveDialog, isFileDialogSupported } from '../utils/fileDialog.js';
|
|
8
|
+
import { exportMessagesToFile } from '../utils/chatExporter.js';
|
|
7
9
|
export function useCommandHandler(options) {
|
|
8
10
|
const { stdout } = useStdout();
|
|
9
11
|
const handleCommandExecution = useCallback(async (commandName, result) => {
|
|
@@ -193,6 +195,62 @@ export function useCommandHandler(options) {
|
|
|
193
195
|
// Auto-send the review prompt using advanced model (not basic model), hide the prompt from UI
|
|
194
196
|
options.processMessage(result.prompt, undefined, false, true);
|
|
195
197
|
}
|
|
198
|
+
else if (result.success && result.action === 'exportChat') {
|
|
199
|
+
// Handle export chat command
|
|
200
|
+
// Show loading message first
|
|
201
|
+
const loadingMessage = {
|
|
202
|
+
role: 'command',
|
|
203
|
+
content: 'Opening file save dialog...',
|
|
204
|
+
commandName: commandName,
|
|
205
|
+
};
|
|
206
|
+
options.setMessages(prev => [...prev, loadingMessage]);
|
|
207
|
+
try {
|
|
208
|
+
// Check if file dialog is supported
|
|
209
|
+
if (!isFileDialogSupported()) {
|
|
210
|
+
const errorMessage = {
|
|
211
|
+
role: 'command',
|
|
212
|
+
content: 'File dialog not supported on this platform. Export cancelled.',
|
|
213
|
+
commandName: commandName,
|
|
214
|
+
};
|
|
215
|
+
options.setMessages(prev => [...prev, errorMessage]);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
// Generate default filename with timestamp
|
|
219
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('.')[0];
|
|
220
|
+
const defaultFilename = `snow-chat-${timestamp}.txt`;
|
|
221
|
+
// Show native save dialog
|
|
222
|
+
const filePath = await showSaveDialog(defaultFilename, 'Export Chat Conversation');
|
|
223
|
+
if (!filePath) {
|
|
224
|
+
// User cancelled
|
|
225
|
+
const cancelMessage = {
|
|
226
|
+
role: 'command',
|
|
227
|
+
content: 'Export cancelled by user.',
|
|
228
|
+
commandName: commandName,
|
|
229
|
+
};
|
|
230
|
+
options.setMessages(prev => [...prev, cancelMessage]);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// Export messages to file
|
|
234
|
+
await exportMessagesToFile(options.messages, filePath);
|
|
235
|
+
// Show success message
|
|
236
|
+
const successMessage = {
|
|
237
|
+
role: 'command',
|
|
238
|
+
content: `✓ Chat exported successfully to:\n${filePath}`,
|
|
239
|
+
commandName: commandName,
|
|
240
|
+
};
|
|
241
|
+
options.setMessages(prev => [...prev, successMessage]);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
// Show error message
|
|
245
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
246
|
+
const errorMessage = {
|
|
247
|
+
role: 'command',
|
|
248
|
+
content: `✗ Export failed: ${errorMsg}`,
|
|
249
|
+
commandName: commandName,
|
|
250
|
+
};
|
|
251
|
+
options.setMessages(prev => [...prev, errorMessage]);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
196
254
|
else if (result.message) {
|
|
197
255
|
// For commands that just return a message (like /role, /init without SNOW.md, etc.)
|
|
198
256
|
// Display the message as a command message
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TextBuffer } from '../utils/textBuffer.js';
|
|
2
|
-
export declare function useCommandPanel(buffer: TextBuffer): {
|
|
2
|
+
export declare function useCommandPanel(buffer: TextBuffer, isProcessing?: boolean): {
|
|
3
3
|
showCommands: boolean;
|
|
4
4
|
setShowCommands: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
5
5
|
commandSelectedIndex: number;
|
|
@@ -13,4 +13,5 @@ export declare function useCommandPanel(buffer: TextBuffer): {
|
|
|
13
13
|
name: string;
|
|
14
14
|
description: string;
|
|
15
15
|
}[];
|
|
16
|
+
isProcessing: boolean;
|
|
16
17
|
};
|
|
@@ -30,8 +30,12 @@ const commands = [
|
|
|
30
30
|
name: 'usage',
|
|
31
31
|
description: 'View token usage statistics with interactive charts',
|
|
32
32
|
},
|
|
33
|
+
{
|
|
34
|
+
name: 'export',
|
|
35
|
+
description: 'Export chat conversation to text file with save dialog',
|
|
36
|
+
},
|
|
33
37
|
];
|
|
34
|
-
export function useCommandPanel(buffer) {
|
|
38
|
+
export function useCommandPanel(buffer, isProcessing = false) {
|
|
35
39
|
const [showCommands, setShowCommands] = useState(false);
|
|
36
40
|
const [commandSelectedIndex, setCommandSelectedIndex] = useState(0);
|
|
37
41
|
// Get filtered commands based on current input
|
|
@@ -62,5 +66,6 @@ export function useCommandPanel(buffer) {
|
|
|
62
66
|
getFilteredCommands,
|
|
63
67
|
updateCommandPanelState,
|
|
64
68
|
commands,
|
|
69
|
+
isProcessing, // Export isProcessing for CommandPanel to use
|
|
65
70
|
};
|
|
66
71
|
}
|
|
@@ -11,6 +11,7 @@ import { sessionManager } from '../utils/sessionManager.js';
|
|
|
11
11
|
import { formatTodoContext } from '../utils/todoPreprocessor.js';
|
|
12
12
|
import { formatToolCallMessage } from '../utils/messageFormatter.js';
|
|
13
13
|
import { resourceMonitor } from '../utils/resourceMonitor.js';
|
|
14
|
+
import { isToolNeedTwoStepDisplay } from '../utils/toolDisplayConfig.js';
|
|
14
15
|
/**
|
|
15
16
|
* Handle conversation with streaming and tool calls
|
|
16
17
|
* Returns the usage data collected during the conversation
|
|
@@ -85,7 +86,7 @@ export async function handleConversationWithTools(options) {
|
|
|
85
86
|
}
|
|
86
87
|
};
|
|
87
88
|
try {
|
|
88
|
-
encoder = encoding_for_model('gpt-
|
|
89
|
+
encoder = encoding_for_model('gpt-5');
|
|
89
90
|
resourceMonitor.trackEncoderCreated();
|
|
90
91
|
}
|
|
91
92
|
catch (e) {
|
|
@@ -95,8 +96,8 @@ export async function handleConversationWithTools(options) {
|
|
|
95
96
|
setStreamTokenCount(0);
|
|
96
97
|
const config = getOpenAiConfig();
|
|
97
98
|
const model = options.useBasicModel
|
|
98
|
-
? config.basicModel || config.advancedModel || 'gpt-
|
|
99
|
-
: config.advancedModel || 'gpt-
|
|
99
|
+
? config.basicModel || config.advancedModel || 'gpt-5'
|
|
100
|
+
: config.advancedModel || 'gpt-5';
|
|
100
101
|
// Tool calling loop (no limit on rounds)
|
|
101
102
|
let finalAssistantMessage = null;
|
|
102
103
|
// Accumulate usage data across all rounds
|
|
@@ -238,7 +239,8 @@ export async function handleConversationWithTools(options) {
|
|
|
238
239
|
else {
|
|
239
240
|
// Add to existing usage for UI display
|
|
240
241
|
accumulatedUsage.prompt_tokens += chunk.usage.prompt_tokens || 0;
|
|
241
|
-
accumulatedUsage.completion_tokens +=
|
|
242
|
+
accumulatedUsage.completion_tokens +=
|
|
243
|
+
chunk.usage.completion_tokens || 0;
|
|
242
244
|
accumulatedUsage.total_tokens += chunk.usage.total_tokens || 0;
|
|
243
245
|
if (chunk.usage.cache_creation_input_tokens !== undefined) {
|
|
244
246
|
accumulatedUsage.cache_creation_input_tokens =
|
|
@@ -293,7 +295,7 @@ export async function handleConversationWithTools(options) {
|
|
|
293
295
|
},
|
|
294
296
|
]);
|
|
295
297
|
}
|
|
296
|
-
// Display tool calls in UI
|
|
298
|
+
// Display tool calls in UI - 只有耗时工具才显示进行中状态
|
|
297
299
|
for (const toolCall of receivedToolCalls) {
|
|
298
300
|
const toolDisplay = formatToolCallMessage(toolCall);
|
|
299
301
|
let toolArgs;
|
|
@@ -303,21 +305,24 @@ export async function handleConversationWithTools(options) {
|
|
|
303
305
|
catch (e) {
|
|
304
306
|
toolArgs = {};
|
|
305
307
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
308
|
+
// 只有耗时工具才在动态区显示进行中状态
|
|
309
|
+
if (isToolNeedTwoStepDisplay(toolCall.function.name)) {
|
|
310
|
+
setMessages(prev => [
|
|
311
|
+
...prev,
|
|
312
|
+
{
|
|
313
|
+
role: 'assistant',
|
|
314
|
+
content: `⚡ ${toolDisplay.toolName}`,
|
|
315
|
+
streaming: false,
|
|
316
|
+
toolCall: {
|
|
317
|
+
name: toolCall.function.name,
|
|
318
|
+
arguments: toolArgs,
|
|
319
|
+
},
|
|
320
|
+
toolDisplay,
|
|
321
|
+
toolCallId: toolCall.id, // Store tool call ID for later update
|
|
322
|
+
toolPending: true, // Mark as pending execution
|
|
315
323
|
},
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
toolPending: true, // Mark as pending execution
|
|
319
|
-
},
|
|
320
|
-
]);
|
|
324
|
+
]);
|
|
325
|
+
}
|
|
321
326
|
}
|
|
322
327
|
// Filter tools that need confirmation (not in always-approved list OR session-approved list)
|
|
323
328
|
const toolsNeedingConfirmation = [];
|
|
@@ -377,7 +382,7 @@ export async function handleConversationWithTools(options) {
|
|
|
377
382
|
// Add all tools to approved list
|
|
378
383
|
approvedTools.push(...toolsNeedingConfirmation);
|
|
379
384
|
}
|
|
380
|
-
// Execute approved tools with sub-agent message callback
|
|
385
|
+
// Execute approved tools with sub-agent message callback and terminal output callback
|
|
381
386
|
const toolResults = await executeToolCalls(approvedTools, controller.signal, setStreamTokenCount, async (subAgentMessage) => {
|
|
382
387
|
// Handle sub-agent messages - display and save to session
|
|
383
388
|
setMessages(prev => {
|
|
@@ -603,6 +608,7 @@ export async function handleConversationWithTools(options) {
|
|
|
603
608
|
!isError) {
|
|
604
609
|
try {
|
|
605
610
|
const resultData = JSON.parse(result.content);
|
|
611
|
+
// Handle single file edit
|
|
606
612
|
if (resultData.oldContent && resultData.newContent) {
|
|
607
613
|
editDiffData = {
|
|
608
614
|
oldContent: resultData.oldContent,
|
|
@@ -613,14 +619,24 @@ export async function handleConversationWithTools(options) {
|
|
|
613
619
|
contextStartLine: resultData.contextStartLine,
|
|
614
620
|
};
|
|
615
621
|
}
|
|
622
|
+
// Handle batch edit
|
|
623
|
+
else if (resultData.results &&
|
|
624
|
+
Array.isArray(resultData.results)) {
|
|
625
|
+
editDiffData = {
|
|
626
|
+
batchResults: resultData.results,
|
|
627
|
+
isBatch: true,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
616
630
|
}
|
|
617
631
|
catch (e) {
|
|
618
632
|
// If parsing fails, just show regular result
|
|
619
633
|
}
|
|
620
634
|
}
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
635
|
+
// 处理工具执行结果的显示
|
|
636
|
+
// - 耗时工具(两步显示):完成消息追加到静态区,之前的进行中消息已包含参数
|
|
637
|
+
// - 普通工具(单步显示):完成消息需要包含参数和结果,使用 toolDisplay
|
|
638
|
+
// 获取工具参数的格式化信息
|
|
639
|
+
const toolDisplay = formatToolCallMessage(toolCall);
|
|
624
640
|
setMessages(prev => [
|
|
625
641
|
...prev,
|
|
626
642
|
// Add new completed message
|
|
@@ -633,7 +649,11 @@ export async function handleConversationWithTools(options) {
|
|
|
633
649
|
name: toolCall.function.name,
|
|
634
650
|
arguments: editDiffData,
|
|
635
651
|
}
|
|
636
|
-
: undefined,
|
|
652
|
+
: undefined,
|
|
653
|
+
// 为普通工具添加参数显示(耗时工具在进行中状态已经显示过参数)
|
|
654
|
+
toolDisplay: !isToolNeedTwoStepDisplay(toolCall.function.name)
|
|
655
|
+
? toolDisplay
|
|
656
|
+
: undefined,
|
|
637
657
|
// Store tool result for preview rendering
|
|
638
658
|
toolResult: !isError ? result.content : undefined,
|
|
639
659
|
},
|
|
@@ -5,10 +5,12 @@ export declare function useSnapshotState(messagesLength: number): {
|
|
|
5
5
|
messageIndex: number;
|
|
6
6
|
fileCount: number;
|
|
7
7
|
filePaths?: string[];
|
|
8
|
+
message?: string;
|
|
8
9
|
} | null;
|
|
9
10
|
setPendingRollback: import("react").Dispatch<import("react").SetStateAction<{
|
|
10
11
|
messageIndex: number;
|
|
11
12
|
fileCount: number;
|
|
12
13
|
filePaths?: string[];
|
|
14
|
+
message?: string;
|
|
13
15
|
} | null>>;
|
|
14
16
|
};
|
package/dist/mcp/filesystem.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { StructureAnalysis } from './types/filesystem.types.js';
|
|
1
|
+
import type { EditBySearchConfig, EditByLineConfig, EditBySearchResult, EditByLineResult } from './types/filesystem.types.js';
|
|
3
2
|
/**
|
|
4
3
|
* Filesystem MCP Service
|
|
5
4
|
* Provides basic file operations: read, create, and delete files
|
|
@@ -13,13 +12,17 @@ export declare class FilesystemMCPService {
|
|
|
13
12
|
constructor(basePath?: string);
|
|
14
13
|
/**
|
|
15
14
|
* Get the content of a file with optional line range
|
|
16
|
-
* @param filePath - Path to the file (relative to base path or absolute) or array of file paths
|
|
17
|
-
* @param startLine - Starting line number (1-indexed, inclusive, optional - defaults to 1)
|
|
18
|
-
* @param endLine - Ending line number (1-indexed, inclusive, optional - defaults to
|
|
15
|
+
* @param filePath - Path to the file (relative to base path or absolute) or array of file paths or array of file config objects
|
|
16
|
+
* @param startLine - Starting line number (1-indexed, inclusive, optional - defaults to 1). Used for single file or as default for array of strings
|
|
17
|
+
* @param endLine - Ending line number (1-indexed, inclusive, optional - defaults to file end). Used for single file or as default for array of strings
|
|
19
18
|
* @returns Object containing the requested content with line numbers and metadata
|
|
20
19
|
* @throws Error if file doesn't exist or cannot be read
|
|
21
20
|
*/
|
|
22
|
-
getFileContent(filePath: string | string[]
|
|
21
|
+
getFileContent(filePath: string | string[] | Array<{
|
|
22
|
+
path: string;
|
|
23
|
+
startLine?: number;
|
|
24
|
+
endLine?: number;
|
|
25
|
+
}>, startLine?: number, endLine?: number): Promise<{
|
|
23
26
|
content: string;
|
|
24
27
|
startLine: number;
|
|
25
28
|
endLine: number;
|
|
@@ -77,57 +80,42 @@ export declare class FilesystemMCPService {
|
|
|
77
80
|
created: Date;
|
|
78
81
|
}>;
|
|
79
82
|
/**
|
|
80
|
-
* Edit
|
|
83
|
+
* Edit file(s) by searching for exact content and replacing it
|
|
81
84
|
* This method uses SMART MATCHING to handle whitespace differences automatically.
|
|
82
85
|
*
|
|
83
|
-
* @param filePath - Path to the file to edit
|
|
84
|
-
* @param searchContent - Content to search for (
|
|
85
|
-
* @param replaceContent - New content to replace
|
|
86
|
+
* @param filePath - Path to the file to edit, or array of file paths, or array of edit config objects
|
|
87
|
+
* @param searchContent - Content to search for (for single file or unified mode)
|
|
88
|
+
* @param replaceContent - New content to replace (for single file or unified mode)
|
|
86
89
|
* @param occurrence - Which occurrence to replace (1-indexed, default: 1, use -1 for all)
|
|
87
90
|
* @param contextLines - Number of context lines to return before and after the edit (default: 8)
|
|
88
91
|
* @returns Object containing success message, before/after comparison, and diagnostics from IDE (VSCode or JetBrains)
|
|
89
92
|
* @throws Error if search content is not found or multiple matches exist
|
|
90
93
|
*/
|
|
91
|
-
editFileBySearch(filePath: string, searchContent
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
startLine: number;
|
|
98
|
-
endLine: number;
|
|
99
|
-
};
|
|
100
|
-
contextStartLine: number;
|
|
101
|
-
contextEndLine: number;
|
|
102
|
-
totalLines: number;
|
|
103
|
-
structureAnalysis?: StructureAnalysis;
|
|
104
|
-
diagnostics?: Diagnostic[];
|
|
105
|
-
}>;
|
|
94
|
+
editFileBySearch(filePath: string | string[] | EditBySearchConfig[], searchContent?: string, replaceContent?: string, occurrence?: number, contextLines?: number): Promise<EditBySearchResult>;
|
|
95
|
+
/**
|
|
96
|
+
* Internal method: Edit a single file by search-replace
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
private editFileBySearchSingle;
|
|
106
100
|
/**
|
|
107
|
-
* Edit
|
|
101
|
+
* Edit file(s) by replacing lines within a specified range
|
|
108
102
|
* BEST PRACTICE: Keep edits small and focused (≤15 lines recommended) for better accuracy.
|
|
109
103
|
* For larger changes, make multiple parallel edits to non-overlapping sections instead of one large edit.
|
|
110
104
|
*
|
|
111
|
-
* @param filePath - Path to the file to edit
|
|
112
|
-
* @param startLine - Starting line number (
|
|
113
|
-
* @param endLine - Ending line number (
|
|
114
|
-
* @param newContent - New content to replace
|
|
105
|
+
* @param filePath - Path to the file to edit, or array of file paths, or array of edit config objects
|
|
106
|
+
* @param startLine - Starting line number (for single file or unified mode)
|
|
107
|
+
* @param endLine - Ending line number (for single file or unified mode)
|
|
108
|
+
* @param newContent - New content to replace (for single file or unified mode)
|
|
115
109
|
* @param contextLines - Number of context lines to return before and after the edit (default: 8)
|
|
116
110
|
* @returns Object containing success message, precise before/after comparison, and diagnostics from IDE (VSCode or JetBrains)
|
|
117
111
|
* @throws Error if file editing fails
|
|
118
112
|
*/
|
|
119
|
-
editFile(filePath: string, startLine
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
contextEndLine: number;
|
|
126
|
-
totalLines: number;
|
|
127
|
-
linesModified: number;
|
|
128
|
-
structureAnalysis?: StructureAnalysis;
|
|
129
|
-
diagnostics?: Diagnostic[];
|
|
130
|
-
}>;
|
|
113
|
+
editFile(filePath: string | string[] | EditByLineConfig[], startLine?: number, endLine?: number, newContent?: string, contextLines?: number): Promise<EditByLineResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Internal method: Edit a single file by line range
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
private editFileSingle;
|
|
131
119
|
/**
|
|
132
120
|
* Resolve path relative to base path and normalize it
|
|
133
121
|
* @private
|
|
@@ -155,6 +143,29 @@ export declare const mcpTools: ({
|
|
|
155
143
|
type: string;
|
|
156
144
|
items: {
|
|
157
145
|
type: string;
|
|
146
|
+
properties?: undefined;
|
|
147
|
+
required?: undefined;
|
|
148
|
+
};
|
|
149
|
+
description: string;
|
|
150
|
+
} | {
|
|
151
|
+
type: string;
|
|
152
|
+
items: {
|
|
153
|
+
type: string;
|
|
154
|
+
properties: {
|
|
155
|
+
path: {
|
|
156
|
+
type: string;
|
|
157
|
+
description: string;
|
|
158
|
+
};
|
|
159
|
+
startLine: {
|
|
160
|
+
type: string;
|
|
161
|
+
description: string;
|
|
162
|
+
};
|
|
163
|
+
endLine: {
|
|
164
|
+
type: string;
|
|
165
|
+
description: string;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
required: string[];
|
|
158
169
|
};
|
|
159
170
|
description: string;
|
|
160
171
|
})[];
|
|
@@ -283,9 +294,46 @@ export declare const mcpTools: ({
|
|
|
283
294
|
type: string;
|
|
284
295
|
properties: {
|
|
285
296
|
filePath: {
|
|
286
|
-
|
|
297
|
+
oneOf: ({
|
|
298
|
+
type: string;
|
|
299
|
+
description: string;
|
|
300
|
+
items?: undefined;
|
|
301
|
+
} | {
|
|
302
|
+
type: string;
|
|
303
|
+
items: {
|
|
304
|
+
type: string;
|
|
305
|
+
properties?: undefined;
|
|
306
|
+
required?: undefined;
|
|
307
|
+
};
|
|
308
|
+
description: string;
|
|
309
|
+
} | {
|
|
310
|
+
type: string;
|
|
311
|
+
items: {
|
|
312
|
+
type: string;
|
|
313
|
+
properties: {
|
|
314
|
+
path: {
|
|
315
|
+
type: string;
|
|
316
|
+
description: string;
|
|
317
|
+
};
|
|
318
|
+
searchContent: {
|
|
319
|
+
type: string;
|
|
320
|
+
description: string;
|
|
321
|
+
};
|
|
322
|
+
replaceContent: {
|
|
323
|
+
type: string;
|
|
324
|
+
description: string;
|
|
325
|
+
};
|
|
326
|
+
occurrence: {
|
|
327
|
+
type: string;
|
|
328
|
+
description: string;
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
required: string[];
|
|
332
|
+
};
|
|
333
|
+
description: string;
|
|
334
|
+
})[];
|
|
287
335
|
description: string;
|
|
288
|
-
|
|
336
|
+
type?: undefined;
|
|
289
337
|
};
|
|
290
338
|
searchContent: {
|
|
291
339
|
type: string;
|
|
@@ -322,9 +370,46 @@ export declare const mcpTools: ({
|
|
|
322
370
|
type: string;
|
|
323
371
|
properties: {
|
|
324
372
|
filePath: {
|
|
325
|
-
|
|
373
|
+
oneOf: ({
|
|
374
|
+
type: string;
|
|
375
|
+
description: string;
|
|
376
|
+
items?: undefined;
|
|
377
|
+
} | {
|
|
378
|
+
type: string;
|
|
379
|
+
items: {
|
|
380
|
+
type: string;
|
|
381
|
+
properties?: undefined;
|
|
382
|
+
required?: undefined;
|
|
383
|
+
};
|
|
384
|
+
description: string;
|
|
385
|
+
} | {
|
|
386
|
+
type: string;
|
|
387
|
+
items: {
|
|
388
|
+
type: string;
|
|
389
|
+
properties: {
|
|
390
|
+
path: {
|
|
391
|
+
type: string;
|
|
392
|
+
description: string;
|
|
393
|
+
};
|
|
394
|
+
startLine: {
|
|
395
|
+
type: string;
|
|
396
|
+
description: string;
|
|
397
|
+
};
|
|
398
|
+
endLine: {
|
|
399
|
+
type: string;
|
|
400
|
+
description: string;
|
|
401
|
+
};
|
|
402
|
+
newContent: {
|
|
403
|
+
type: string;
|
|
404
|
+
description: string;
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
required: string[];
|
|
408
|
+
};
|
|
409
|
+
description: string;
|
|
410
|
+
})[];
|
|
326
411
|
description: string;
|
|
327
|
-
|
|
412
|
+
type?: undefined;
|
|
328
413
|
};
|
|
329
414
|
startLine: {
|
|
330
415
|
type: string;
|