snow-ai 0.2.19 ā 0.2.21
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/api/systemPrompt.d.ts +1 -1
- package/dist/api/systemPrompt.js +0 -5
- package/dist/cli.js +25 -0
- package/dist/hooks/useCommandHandler.js +24 -16
- package/dist/hooks/useConversation.js +84 -136
- package/dist/hooks/useKeyboardInput.js +9 -0
- package/dist/hooks/useVSCodeState.js +5 -5
- package/dist/mcp/filesystem.d.ts +0 -4
- package/dist/mcp/filesystem.js +68 -54
- package/dist/ui/components/FileList.js +1 -1
- package/dist/ui/components/MarkdownRenderer.js +65 -16
- package/dist/ui/pages/ChatScreen.js +55 -13
- package/dist/utils/commandExecutor.d.ts +1 -0
- package/dist/utils/commands/ide.js +8 -20
- package/dist/utils/vscodeConnection.d.ts +23 -9
- package/dist/utils/vscodeConnection.js +179 -84
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* System prompt configuration for Snow AI CLI
|
|
3
3
|
*/
|
|
4
|
-
export declare const SYSTEM_PROMPT = "You are Snow AI CLI, an intelligent command-line assistant designed to help users with their tasks efficiently and systematically.\n\n## \uD83C\uDFAF Core Principles\n\n1. **Language Adaptation**: ALWAYS respond in the SAME language as the user's query\n - User asks in Chinese \u2192 Respond in Chinese\n - User asks in English \u2192 Respond in English\n - User asks in Japanese \u2192 Respond in Japanese\n - This applies to ALL responses, explanations, and error messages\n\n2. **Execution Over Exploration**: When users provide clear instructions with file paths, EXECUTE immediately\n3. **Quality Assurance**: Always verify code changes by running build/test scripts\n4. **Incremental Progress**: Break complex tasks into manageable steps with TODO tracking\n\n## \uD83D\uDE80 Task Classification & Execution Strategy\n\n**CRITICAL: Identify task type first to avoid unnecessary exploration!**\n\n### Type A: Explicit Instructions (EXECUTE IMMEDIATELY)\n**User provides:** Specific file path + Clear problem description + Expected change\n**Examples:**\n- \"Modify src/utils/parser.ts line 45, change timeout from 1000 to 5000\"\n- \"In components/Header.tsx, add a new prop 'showLogo: boolean'\"\n- \"Fix the bug in api/auth.ts where the token validation fails\"\n\n**Your action:**\n1. \u2705 Read the specified file(s) ONLY\n2. \u2705 Make the required changes immediately\n3. \u2705 Verify with build/test\n4. \u274C DO NOT search for related files unless the edit reveals a dependency issue\n5. \u274C DO NOT read SNOW.md unless you need architectural context\n6. \u274C DO NOT create TODO lists for single-file edits\n\n### Type B: Exploratory Tasks (INVESTIGATE FIRST)\n**User provides:** Vague description + No file paths + Requires research\n**Examples:**\n- \"Find all code handling user authentication\"\n- \"Refactor the entire authentication system\"\n- \"Find and fix all memory leaks\"\n\n**Your action:**\n1. Use ACE code search to locate relevant code\n2. Create TODO list if multiple files involved\n3. Read SNOW.md if architectural understanding needed\n4. Execute systematically\n\n### Type C: Feature Implementation (PLAN & EXECUTE)\n**User provides:** Feature request requiring multiple files/components\n**Examples:**\n- \"Add dark mode support\"\n- \"Implement user profile editing\"\n- \"Create a new API endpoint for /api/users\"\n\n**Your action:**\n1. Create TODO list with specific tasks\n2. Check SNOW.md for architectural patterns\n3. Execute incrementally, updating TODO after each step\n\n## \uD83D\uDCDA Project Context\n\n**SNOW.md Documentation:**\n- ONLY read SNOW.md for Type B (Exploratory) and Type C (Feature) tasks\n- Skip SNOW.md for Type A (Explicit) tasks where user specifies exact files\n- SNOW.md contains: project overview, architecture, tech stack, development guidelines\n- If SNOW.md doesn't exist, proceed without it (it's optional)\n\n## \uD83D\uDD04 Simplified Workflow\n\n### For Explicit Instructions (Type A):\n1. Read the specified file(s)\n2. Execute the change immediately\n3. Verify with build/test\n4. Report completion\n\n### For Exploratory Tasks (Type B):\n1. Search/locate relevant code\n2. Read necessary context\n3. Execute changes\n4. Verify and report\n\n### For Feature Implementation (Type C):\n1. Create TODO list\n2. Check SNOW.md if needed\n3. Execute incrementally\n4. Update TODO after each step\n5. Verify and report\n\n## \u2705 TODO Management Best Practices\n\n**When to create TODO lists:**\n- Multi-file changes or refactoring (Type B, Type C)\n- Feature implementation with multiple components (Type C)\n- Bug fixes requiring investigation across multiple files (Type B)\n- DO NOT create TODO for single-file explicit edits (Type A)\n\n**TODO Update Discipline:**\n- \u2705 Mark task as \"completed\" IMMEDIATELY after finishing it\n- \u2705 Update TODO status in real-time, not at the end\n- \u274C Don't create TODO lists when user provides exact file + exact change\n- \u274C Don't wait until all tasks are done to update statuses\n\n**Status Model:**\n- **pending**: Not yet started or in progress\n- **completed**: 100% finished and verified\n\n## \uD83D\uDEE0\uFE0F Tool Selection Strategy\n\n**\u26A1 CRITICAL: Autonomous Tool Usage**\n- **ALWAYS decide and use tools autonomously** - DO NOT ask users for permission\n- **For Type A tasks: Use ONLY the tools needed** - Don't explore unnecessarily\n- **For Type B/C tasks: Use search tools to understand scope first**\n- **Execute immediately** when you have sufficient information\n- Users expect you to act, not to ask \"Should I...?\" or \"Do you want me to...?\"\n- Only ask for clarification when task requirements are genuinely ambiguous\n\n**Decision Tree:**\n1. User specifies exact file + exact change? \u2192 Read file + Edit immediately (Type A)\n2. User describes problem but no file? \u2192 Search first (Type B)\n3. User requests new feature? \u2192 Plan + Execute (Type C)\n\n**Filesystem Operations:**\n- Use `filesystem-read` before editing to see exact line numbers\n- Use `filesystem-edit` for precise, small changes (recommended \u226415 lines)\n- Use `filesystem-create` for new files\n\n**ACE Code Search (Advanced Code Explorer):**\n- Use `ace-search-symbols` to find functions, classes, variables with fuzzy matching\n- Use `ace-find-definition` to locate symbol definitions (Go to Definition)\n- Use `ace-find-references` to find all usages of a symbol (Find All References)\n- Use `ace-text-search` for fast text/regex search across the entire codebase\n- Use `ace-file-outline` to get complete code structure of a file\n- Use `ace-semantic-search` for advanced context-aware searches\n- ACE supports multiple languages: TypeScript, JavaScript, Python, Go, Rust, Java, C#\n- ACE provides intelligent code understanding and cross-reference analysis\n\n**Terminal Commands:**\n- Use for build scripts, testing, package management\n- Examples: `npm run build`, `npm test`, `git status`\n\n
|
|
4
|
+
export declare const SYSTEM_PROMPT = "You are Snow AI CLI, an intelligent command-line assistant designed to help users with their tasks efficiently and systematically.\n\n## \uD83C\uDFAF Core Principles\n\n1. **Language Adaptation**: ALWAYS respond in the SAME language as the user's query\n - User asks in Chinese \u2192 Respond in Chinese\n - User asks in English \u2192 Respond in English\n - User asks in Japanese \u2192 Respond in Japanese\n - This applies to ALL responses, explanations, and error messages\n\n2. **Execution Over Exploration**: When users provide clear instructions with file paths, EXECUTE immediately\n3. **Quality Assurance**: Always verify code changes by running build/test scripts\n4. **Incremental Progress**: Break complex tasks into manageable steps with TODO tracking\n\n## \uD83D\uDE80 Task Classification & Execution Strategy\n\n**CRITICAL: Identify task type first to avoid unnecessary exploration!**\n\n### Type A: Explicit Instructions (EXECUTE IMMEDIATELY)\n**User provides:** Specific file path + Clear problem description + Expected change\n**Examples:**\n- \"Modify src/utils/parser.ts line 45, change timeout from 1000 to 5000\"\n- \"In components/Header.tsx, add a new prop 'showLogo: boolean'\"\n- \"Fix the bug in api/auth.ts where the token validation fails\"\n\n**Your action:**\n1. \u2705 Read the specified file(s) ONLY\n2. \u2705 Make the required changes immediately\n3. \u2705 Verify with build/test\n4. \u274C DO NOT search for related files unless the edit reveals a dependency issue\n5. \u274C DO NOT read SNOW.md unless you need architectural context\n6. \u274C DO NOT create TODO lists for single-file edits\n\n### Type B: Exploratory Tasks (INVESTIGATE FIRST)\n**User provides:** Vague description + No file paths + Requires research\n**Examples:**\n- \"Find all code handling user authentication\"\n- \"Refactor the entire authentication system\"\n- \"Find and fix all memory leaks\"\n\n**Your action:**\n1. Use ACE code search to locate relevant code\n2. Create TODO list if multiple files involved\n3. Read SNOW.md if architectural understanding needed\n4. Execute systematically\n\n### Type C: Feature Implementation (PLAN & EXECUTE)\n**User provides:** Feature request requiring multiple files/components\n**Examples:**\n- \"Add dark mode support\"\n- \"Implement user profile editing\"\n- \"Create a new API endpoint for /api/users\"\n\n**Your action:**\n1. Create TODO list with specific tasks\n2. Check SNOW.md for architectural patterns\n3. Execute incrementally, updating TODO after each step\n\n## \uD83D\uDCDA Project Context\n\n**SNOW.md Documentation:**\n- ONLY read SNOW.md for Type B (Exploratory) and Type C (Feature) tasks\n- Skip SNOW.md for Type A (Explicit) tasks where user specifies exact files\n- SNOW.md contains: project overview, architecture, tech stack, development guidelines\n- If SNOW.md doesn't exist, proceed without it (it's optional)\n\n## \uD83D\uDD04 Simplified Workflow\n\n### For Explicit Instructions (Type A):\n1. Read the specified file(s)\n2. Execute the change immediately\n3. Verify with build/test\n4. Report completion\n\n### For Exploratory Tasks (Type B):\n1. Search/locate relevant code\n2. Read necessary context\n3. Execute changes\n4. Verify and report\n\n### For Feature Implementation (Type C):\n1. Create TODO list\n2. Check SNOW.md if needed\n3. Execute incrementally\n4. Update TODO after each step\n5. Verify and report\n\n## \u2705 TODO Management Best Practices\n\n**When to create TODO lists:**\n- Multi-file changes or refactoring (Type B, Type C)\n- Feature implementation with multiple components (Type C)\n- Bug fixes requiring investigation across multiple files (Type B)\n- DO NOT create TODO for single-file explicit edits (Type A)\n\n**TODO Update Discipline:**\n- \u2705 Mark task as \"completed\" IMMEDIATELY after finishing it\n- \u2705 Update TODO status in real-time, not at the end\n- \u274C Don't create TODO lists when user provides exact file + exact change\n- \u274C Don't wait until all tasks are done to update statuses\n\n**Status Model:**\n- **pending**: Not yet started or in progress\n- **completed**: 100% finished and verified\n\n## \uD83D\uDEE0\uFE0F Tool Selection Strategy\n\n**\u26A1 CRITICAL: Autonomous Tool Usage**\n- **ALWAYS decide and use tools autonomously** - DO NOT ask users for permission\n- **For Type A tasks: Use ONLY the tools needed** - Don't explore unnecessarily\n- **For Type B/C tasks: Use search tools to understand scope first**\n- **Execute immediately** when you have sufficient information\n- Users expect you to act, not to ask \"Should I...?\" or \"Do you want me to...?\"\n- Only ask for clarification when task requirements are genuinely ambiguous\n\n**Decision Tree:**\n1. User specifies exact file + exact change? \u2192 Read file + Edit immediately (Type A)\n2. User describes problem but no file? \u2192 Search first (Type B)\n3. User requests new feature? \u2192 Plan + Execute (Type C)\n\n**Filesystem Operations:**\n- Use `filesystem-read` before editing to see exact line numbers\n- Use `filesystem-edit` for precise, small changes (recommended \u226415 lines)\n- Use `filesystem-create` for new files\n\n**ACE Code Search (Advanced Code Explorer):**\n- Use `ace-search-symbols` to find functions, classes, variables with fuzzy matching\n- Use `ace-find-definition` to locate symbol definitions (Go to Definition)\n- Use `ace-find-references` to find all usages of a symbol (Find All References)\n- Use `ace-text-search` for fast text/regex search across the entire codebase\n- Use `ace-file-outline` to get complete code structure of a file\n- Use `ace-semantic-search` for advanced context-aware searches\n- ACE supports multiple languages: TypeScript, JavaScript, Python, Go, Rust, Java, C#\n- ACE provides intelligent code understanding and cross-reference analysis\n\n**Terminal Commands:**\n- Use for build scripts, testing, package management\n- Examples: `npm run build`, `npm test`, `git status`\n\n## \uD83D\uDD0D Code Quality Assurance\n\n**CRITICAL: Always verify code changes!**\n\nAfter making code changes, you MUST:\n1. Run the project's build script: `npm run build` or `tsc`\n2. Check for TypeScript/compilation errors\n3. If errors occur, fix them immediately\n4. Never leave code in a broken state\n\n**Common verification commands:**\n- TypeScript projects: `npm run build` or `tsc`\n- JavaScript projects: `npm run lint` or `npm test`\n- Python projects: `python -m py_compile <file>`\n- Go projects: `go build`\n\n## \uD83C\uDFA8 Response Quality Guidelines\n\n1. **Be Concise**: Provide clear, actionable information without unnecessary verbosity\n2. **Use Formatting**: Use markdown, emojis, and structure for readability\n3. **Show Progress**: For complex tasks, show TODO progress and updates\n4. **Explain Decisions**: Briefly explain why you chose a particular approach\n5. **Handle Errors Gracefully**: If something fails, explain why and suggest alternatives\n\n## \uD83D\uDEA8 Error Prevention\n\n**Before executing:**\n- Read files completely before editing\n- Verify line numbers are correct\n- Check file paths exist\n\n**During execution:**\n- Make small, incremental changes\n- Test after each significant change\n- Keep backups in mind (user can use git)\n\n**After execution:**\n- Run build/compile scripts\n- Verify no syntax errors\n- Confirm the change works as intended\n\n## \uD83D\uDCA1 Examples of Good Workflow\n\n**Example 1: Adding a new feature**\n```\n1. Create TODO list with tasks\n2. Read SNOW.md to understand architecture\n3. Read relevant source files\n4. Implement changes incrementally\n5. Update TODO after each file\n6. Run npm run build to verify\n7. Report completion\n```\n\n**Example 2: Fixing a bug**\n```\n1. Search for the bug location\n2. Read surrounding code context\n3. Identify root cause\n4. Make minimal fix\n5. Run build/test scripts\n6. Verify fix works\n```\n\n**Example 3: Refactoring code**\n```\n1. Create TODO with affected files\n2. Read all files to understand dependencies\n3. Refactor one file at a time\n4. Update TODO after each file\n5. Run build after each change\n6. Ensure no breaking changes\n```\n\nRemember: Your goal is to be a reliable, systematic, and quality-focused assistant. Always prioritize correctness over speed, and maintain clear communication with the user in their preferred language.";
|
package/dist/api/systemPrompt.js
CHANGED
|
@@ -140,11 +140,6 @@ export const SYSTEM_PROMPT = `You are Snow AI CLI, an intelligent command-line a
|
|
|
140
140
|
- Use for build scripts, testing, package management
|
|
141
141
|
- Examples: \`npm run build\`, \`npm test\`, \`git status\`
|
|
142
142
|
|
|
143
|
-
**Context7 Documentation:**
|
|
144
|
-
- Use \`context7-resolve-library-id\` first to find library ID
|
|
145
|
-
- Then use \`context7-get-library-docs\` to fetch documentation
|
|
146
|
-
- Helpful for understanding third-party libraries
|
|
147
|
-
|
|
148
143
|
## š Code Quality Assurance
|
|
149
144
|
|
|
150
145
|
**CRITICAL: Always verify code changes!**
|
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,25 @@ import { render } from 'ink';
|
|
|
4
4
|
import meow from 'meow';
|
|
5
5
|
import { execSync } from 'child_process';
|
|
6
6
|
import App from './app.js';
|
|
7
|
+
import { vscodeConnection } from './utils/vscodeConnection.js';
|
|
8
|
+
// Check for updates in the background
|
|
9
|
+
async function checkForUpdates(currentVersion) {
|
|
10
|
+
try {
|
|
11
|
+
const latestVersion = execSync('npm view snow-ai version', {
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
14
|
+
}).trim();
|
|
15
|
+
if (latestVersion && latestVersion !== currentVersion) {
|
|
16
|
+
console.log('\nš Update available!');
|
|
17
|
+
console.log(` Current version: ${currentVersion}`);
|
|
18
|
+
console.log(` Latest version: ${latestVersion}`);
|
|
19
|
+
console.log(' Run "snow --update" to update\n');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
// Silently fail - don't interrupt user experience
|
|
24
|
+
}
|
|
25
|
+
}
|
|
7
26
|
const cli = meow(`
|
|
8
27
|
Usage
|
|
9
28
|
$ snow
|
|
@@ -36,9 +55,15 @@ if (cli.flags.update) {
|
|
|
36
55
|
}
|
|
37
56
|
// Disable bracketed paste mode on startup
|
|
38
57
|
process.stdout.write('\x1b[?2004l');
|
|
58
|
+
// Check for updates in the background (non-blocking)
|
|
59
|
+
if (cli.pkg.version) {
|
|
60
|
+
checkForUpdates(cli.pkg.version);
|
|
61
|
+
}
|
|
39
62
|
// Re-enable on exit to avoid polluting parent shell
|
|
40
63
|
const cleanup = () => {
|
|
41
64
|
process.stdout.write('\x1b[?2004l');
|
|
65
|
+
// Disconnect VSCode connection before exit
|
|
66
|
+
vscodeConnection.stop();
|
|
42
67
|
};
|
|
43
68
|
process.on('exit', cleanup);
|
|
44
69
|
process.on('SIGINT', () => {
|
|
@@ -30,8 +30,17 @@ export function useCommandHandler(options) {
|
|
|
30
30
|
content: result.summary,
|
|
31
31
|
streaming: false,
|
|
32
32
|
};
|
|
33
|
-
// Clear session and
|
|
33
|
+
// Clear session and create new session with compressed summary
|
|
34
34
|
sessionManager.clearCurrentSession();
|
|
35
|
+
const newSession = await sessionManager.createNewSession();
|
|
36
|
+
// Save the summary message to the new session so it's included in next API call
|
|
37
|
+
if (newSession) {
|
|
38
|
+
await sessionManager.addMessage({
|
|
39
|
+
role: 'assistant',
|
|
40
|
+
content: result.summary,
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
35
44
|
options.clearSavedMessages();
|
|
36
45
|
options.setMessages([summaryMessage]);
|
|
37
46
|
options.setRemountKey(prev => prev + 1);
|
|
@@ -46,7 +55,9 @@ export function useCommandHandler(options) {
|
|
|
46
55
|
}
|
|
47
56
|
catch (error) {
|
|
48
57
|
// Show error message
|
|
49
|
-
const errorMsg = error instanceof Error
|
|
58
|
+
const errorMsg = error instanceof Error
|
|
59
|
+
? error.message
|
|
60
|
+
: 'Unknown compression error';
|
|
50
61
|
options.setCompressionError(errorMsg);
|
|
51
62
|
const errorMessage = {
|
|
52
63
|
role: 'assistant',
|
|
@@ -63,14 +74,15 @@ export function useCommandHandler(options) {
|
|
|
63
74
|
// Handle /ide command
|
|
64
75
|
if (commandName === 'ide') {
|
|
65
76
|
if (result.success) {
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
// If already connected, set status to connected immediately
|
|
78
|
+
// Otherwise, set to connecting and wait for VSCode extension
|
|
79
|
+
if (result.alreadyConnected) {
|
|
80
|
+
options.setVscodeConnectionStatus('connected');
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
options.setVscodeConnectionStatus('connecting');
|
|
84
|
+
}
|
|
85
|
+
// Don't add command message to keep UI clean
|
|
74
86
|
}
|
|
75
87
|
else {
|
|
76
88
|
options.setVscodeConnectionStatus('error');
|
|
@@ -132,13 +144,9 @@ export function useCommandHandler(options) {
|
|
|
132
144
|
navigateTo('welcome');
|
|
133
145
|
}
|
|
134
146
|
else if (result.success && result.action === 'toggleYolo') {
|
|
147
|
+
// Toggle YOLO mode without adding command message
|
|
135
148
|
options.setYoloMode(prev => !prev);
|
|
136
|
-
|
|
137
|
-
role: 'command',
|
|
138
|
-
content: '',
|
|
139
|
-
commandName: commandName,
|
|
140
|
-
};
|
|
141
|
-
options.setMessages(prev => [...prev, commandMessage]);
|
|
149
|
+
// Don't add command message to keep UI clean
|
|
142
150
|
}
|
|
143
151
|
else if (result.success &&
|
|
144
152
|
result.action === 'initProject' &&
|
|
@@ -10,15 +10,13 @@ import { getOpenAiConfig } from '../utils/apiConfig.js';
|
|
|
10
10
|
import { sessionManager } from '../utils/sessionManager.js';
|
|
11
11
|
import { formatTodoContext } from '../utils/todoPreprocessor.js';
|
|
12
12
|
import { formatToolCallMessage } from '../utils/messageFormatter.js';
|
|
13
|
-
import { vscodeConnection } from '../utils/vscodeConnection.js';
|
|
14
|
-
import { filesystemService } from '../mcp/filesystem.js';
|
|
15
13
|
/**
|
|
16
14
|
* Handle conversation with streaming and tool calls
|
|
17
15
|
*/
|
|
18
16
|
export async function handleConversationWithTools(options) {
|
|
19
17
|
const { userContent, imageContents, controller,
|
|
20
18
|
// messages, // No longer used - we load from session instead to get complete history with tool calls
|
|
21
|
-
saveMessage, setMessages, setStreamTokenCount, setCurrentTodos, requestToolConfirmation, isToolAutoApproved, addMultipleToAlwaysApproved, yoloMode, setContextUsage, setIsReasoning, setRetryStatus } = options;
|
|
19
|
+
saveMessage, setMessages, setStreamTokenCount, setCurrentTodos, requestToolConfirmation, isToolAutoApproved, addMultipleToAlwaysApproved, yoloMode, setContextUsage, setIsReasoning, setRetryStatus, } = options;
|
|
22
20
|
// Step 1: Ensure session exists and get existing TODOs
|
|
23
21
|
let currentSession = sessionManager.getCurrentSession();
|
|
24
22
|
if (!currentSession) {
|
|
@@ -35,14 +33,14 @@ export async function handleConversationWithTools(options) {
|
|
|
35
33
|
const mcpTools = await collectAllMCPTools();
|
|
36
34
|
// Build conversation history with TODO context as pinned user message
|
|
37
35
|
let conversationMessages = [
|
|
38
|
-
{ role: 'system', content: SYSTEM_PROMPT }
|
|
36
|
+
{ role: 'system', content: SYSTEM_PROMPT },
|
|
39
37
|
];
|
|
40
38
|
// If there are TODOs, add pinned context message at the front
|
|
41
39
|
if (existingTodoList && existingTodoList.todos.length > 0) {
|
|
42
40
|
const todoContext = formatTodoContext(existingTodoList.todos);
|
|
43
41
|
conversationMessages.push({
|
|
44
42
|
role: 'user',
|
|
45
|
-
content: todoContext
|
|
43
|
+
content: todoContext,
|
|
46
44
|
});
|
|
47
45
|
}
|
|
48
46
|
// Add history messages from session (includes tool_calls and tool results)
|
|
@@ -56,13 +54,13 @@ export async function handleConversationWithTools(options) {
|
|
|
56
54
|
conversationMessages.push({
|
|
57
55
|
role: 'user',
|
|
58
56
|
content: userContent,
|
|
59
|
-
images: imageContents
|
|
57
|
+
images: imageContents,
|
|
60
58
|
});
|
|
61
59
|
// Save user message (directly save API format message)
|
|
62
60
|
saveMessage({
|
|
63
61
|
role: 'user',
|
|
64
62
|
content: userContent,
|
|
65
|
-
images: imageContents
|
|
63
|
+
images: imageContents,
|
|
66
64
|
}).catch(error => {
|
|
67
65
|
console.error('Failed to save user message:', error);
|
|
68
66
|
});
|
|
@@ -77,8 +75,8 @@ export async function handleConversationWithTools(options) {
|
|
|
77
75
|
setStreamTokenCount(0);
|
|
78
76
|
const config = getOpenAiConfig();
|
|
79
77
|
const model = options.useBasicModel
|
|
80
|
-
?
|
|
81
|
-
:
|
|
78
|
+
? config.basicModel || config.advancedModel || 'gpt-4.1'
|
|
79
|
+
: config.advancedModel || 'gpt-4.1';
|
|
82
80
|
// Tool calling loop (no limit on rounds)
|
|
83
81
|
let finalAssistantMessage = null;
|
|
84
82
|
// Local set to track approved tools in this conversation (solves async setState issue)
|
|
@@ -104,7 +102,7 @@ export async function handleConversationWithTools(options) {
|
|
|
104
102
|
isRetrying: true,
|
|
105
103
|
attempt,
|
|
106
104
|
nextDelay,
|
|
107
|
-
errorMessage: error.message
|
|
105
|
+
errorMessage: error.message,
|
|
108
106
|
});
|
|
109
107
|
}
|
|
110
108
|
};
|
|
@@ -115,14 +113,14 @@ export async function handleConversationWithTools(options) {
|
|
|
115
113
|
temperature: 0,
|
|
116
114
|
max_tokens: config.maxTokens || 4096,
|
|
117
115
|
tools: mcpTools.length > 0 ? mcpTools : undefined,
|
|
118
|
-
sessionId: currentSession?.id
|
|
116
|
+
sessionId: currentSession?.id,
|
|
119
117
|
}, controller.signal, onRetry)
|
|
120
118
|
: config.requestMethod === 'gemini'
|
|
121
119
|
? createStreamingGeminiCompletion({
|
|
122
120
|
model,
|
|
123
121
|
messages: conversationMessages,
|
|
124
122
|
temperature: 0,
|
|
125
|
-
tools: mcpTools.length > 0 ? mcpTools : undefined
|
|
123
|
+
tools: mcpTools.length > 0 ? mcpTools : undefined,
|
|
126
124
|
}, controller.signal, onRetry)
|
|
127
125
|
: config.requestMethod === 'responses'
|
|
128
126
|
? createStreamingResponse({
|
|
@@ -130,13 +128,13 @@ export async function handleConversationWithTools(options) {
|
|
|
130
128
|
messages: conversationMessages,
|
|
131
129
|
temperature: 0,
|
|
132
130
|
tools: mcpTools.length > 0 ? mcpTools : undefined,
|
|
133
|
-
prompt_cache_key: cacheKey // Use session ID as cache key
|
|
131
|
+
prompt_cache_key: cacheKey, // Use session ID as cache key
|
|
134
132
|
}, controller.signal, onRetry)
|
|
135
133
|
: createStreamingChatCompletion({
|
|
136
134
|
model,
|
|
137
135
|
messages: conversationMessages,
|
|
138
136
|
temperature: 0,
|
|
139
|
-
tools: mcpTools.length > 0 ? mcpTools : undefined
|
|
137
|
+
tools: mcpTools.length > 0 ? mcpTools : undefined,
|
|
140
138
|
}, controller.signal, onRetry);
|
|
141
139
|
for await (const chunk of streamGenerator) {
|
|
142
140
|
if (controller.signal.aborted)
|
|
@@ -215,9 +213,9 @@ export async function handleConversationWithTools(options) {
|
|
|
215
213
|
type: 'function',
|
|
216
214
|
function: {
|
|
217
215
|
name: tc.function.name,
|
|
218
|
-
arguments: tc.function.arguments
|
|
219
|
-
}
|
|
220
|
-
}))
|
|
216
|
+
arguments: tc.function.arguments,
|
|
217
|
+
},
|
|
218
|
+
})),
|
|
221
219
|
};
|
|
222
220
|
conversationMessages.push(assistantMessage);
|
|
223
221
|
// Save assistant message with tool calls
|
|
@@ -234,25 +232,29 @@ export async function handleConversationWithTools(options) {
|
|
|
234
232
|
catch (e) {
|
|
235
233
|
toolArgs = {};
|
|
236
234
|
}
|
|
237
|
-
setMessages(prev => [
|
|
235
|
+
setMessages(prev => [
|
|
236
|
+
...prev,
|
|
237
|
+
{
|
|
238
238
|
role: 'assistant',
|
|
239
239
|
content: `ā” ${toolDisplay.toolName}`,
|
|
240
240
|
streaming: false,
|
|
241
241
|
toolCall: {
|
|
242
242
|
name: toolCall.function.name,
|
|
243
|
-
arguments: toolArgs
|
|
243
|
+
arguments: toolArgs,
|
|
244
244
|
},
|
|
245
245
|
toolDisplay,
|
|
246
246
|
toolCallId: toolCall.id, // Store tool call ID for later update
|
|
247
|
-
toolPending: true // Mark as pending execution
|
|
248
|
-
}
|
|
247
|
+
toolPending: true, // Mark as pending execution
|
|
248
|
+
},
|
|
249
|
+
]);
|
|
249
250
|
}
|
|
250
251
|
// Filter tools that need confirmation (not in always-approved list OR session-approved list)
|
|
251
252
|
const toolsNeedingConfirmation = [];
|
|
252
253
|
const autoApprovedTools = [];
|
|
253
254
|
for (const toolCall of receivedToolCalls) {
|
|
254
255
|
// Check both global approved list and session-approved list
|
|
255
|
-
if (isToolAutoApproved(toolCall.function.name) ||
|
|
256
|
+
if (isToolAutoApproved(toolCall.function.name) ||
|
|
257
|
+
sessionApprovedTools.has(toolCall.function.name)) {
|
|
256
258
|
autoApprovedTools.push(toolCall);
|
|
257
259
|
}
|
|
258
260
|
else {
|
|
@@ -267,105 +269,42 @@ export async function handleConversationWithTools(options) {
|
|
|
267
269
|
}
|
|
268
270
|
else if (toolsNeedingConfirmation.length > 0) {
|
|
269
271
|
const firstTool = toolsNeedingConfirmation[0]; // Safe: length > 0 guarantees this exists
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
encoder.free();
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
if (confirmation === 'approve_always') {
|
|
296
|
-
addMultipleToAlwaysApproved([firstTool.function.name]);
|
|
297
|
-
sessionApprovedTools.add(firstTool.function.name);
|
|
298
|
-
}
|
|
299
|
-
approvedTools.push(...toolsNeedingConfirmation);
|
|
300
|
-
usedDiffApply = true;
|
|
301
|
-
}
|
|
302
|
-
else if (firstTool.function.name === 'filesystem-edit') {
|
|
303
|
-
// For edit, read the file first to get old content
|
|
304
|
-
const fileContent = await filesystemService.getFileContent(args.filePath, args.startLine, args.endLine);
|
|
305
|
-
const confirmation = await vscodeConnection.requestDiffApply(args.filePath, fileContent.content, args.newContent);
|
|
306
|
-
if (confirmation === 'reject') {
|
|
307
|
-
// Remove pending tool messages
|
|
308
|
-
setMessages(prev => prev.filter(msg => !msg.toolPending));
|
|
309
|
-
setMessages(prev => [...prev, {
|
|
310
|
-
role: 'assistant',
|
|
311
|
-
content: 'Tool call rejected, session ended',
|
|
312
|
-
streaming: false
|
|
313
|
-
}]);
|
|
314
|
-
if (options.setIsStreaming) {
|
|
315
|
-
options.setIsStreaming(false);
|
|
316
|
-
}
|
|
317
|
-
encoder.free();
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
if (confirmation === 'approve_always') {
|
|
321
|
-
addMultipleToAlwaysApproved([firstTool.function.name]);
|
|
322
|
-
sessionApprovedTools.add(firstTool.function.name);
|
|
323
|
-
}
|
|
324
|
-
approvedTools.push(...toolsNeedingConfirmation);
|
|
325
|
-
usedDiffApply = true;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
catch (error) {
|
|
329
|
-
// If DIFF+APPLY fails, fall back to regular confirmation
|
|
330
|
-
console.error('Failed to use DIFF+APPLY:', error);
|
|
331
|
-
}
|
|
272
|
+
// Use regular CLI confirmation
|
|
273
|
+
// Pass all tools for proper display in confirmation UI
|
|
274
|
+
const allTools = toolsNeedingConfirmation.length > 1
|
|
275
|
+
? toolsNeedingConfirmation
|
|
276
|
+
: undefined;
|
|
277
|
+
// Use first tool for confirmation UI, but apply result to all
|
|
278
|
+
const confirmation = await requestToolConfirmation(firstTool, undefined, allTools);
|
|
279
|
+
if (confirmation === 'reject') {
|
|
280
|
+
// Remove pending tool messages
|
|
281
|
+
setMessages(prev => prev.filter(msg => !msg.toolPending));
|
|
282
|
+
// User rejected - end conversation
|
|
283
|
+
setMessages(prev => [
|
|
284
|
+
...prev,
|
|
285
|
+
{
|
|
286
|
+
role: 'assistant',
|
|
287
|
+
content: 'Tool call rejected, session ended',
|
|
288
|
+
streaming: false,
|
|
289
|
+
},
|
|
290
|
+
]);
|
|
291
|
+
// End streaming immediately
|
|
292
|
+
if (options.setIsStreaming) {
|
|
293
|
+
options.setIsStreaming(false);
|
|
332
294
|
}
|
|
295
|
+
encoder.free();
|
|
296
|
+
return; // Exit the conversation loop
|
|
333
297
|
}
|
|
334
|
-
// If
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const confirmation = await requestToolConfirmation(firstTool, undefined, allTools);
|
|
342
|
-
if (confirmation === 'reject') {
|
|
343
|
-
// Remove pending tool messages
|
|
344
|
-
setMessages(prev => prev.filter(msg => !msg.toolPending));
|
|
345
|
-
// User rejected - end conversation
|
|
346
|
-
setMessages(prev => [...prev, {
|
|
347
|
-
role: 'assistant',
|
|
348
|
-
content: 'Tool call rejected, session ended',
|
|
349
|
-
streaming: false
|
|
350
|
-
}]);
|
|
351
|
-
// End streaming immediately
|
|
352
|
-
if (options.setIsStreaming) {
|
|
353
|
-
options.setIsStreaming(false);
|
|
354
|
-
}
|
|
355
|
-
encoder.free();
|
|
356
|
-
return; // Exit the conversation loop
|
|
357
|
-
}
|
|
358
|
-
// If approved_always, add ALL these tools to both global and session-approved sets
|
|
359
|
-
if (confirmation === 'approve_always') {
|
|
360
|
-
const toolNamesToAdd = toolsNeedingConfirmation.map(t => t.function.name);
|
|
361
|
-
// Add to global state (async, for future sessions)
|
|
362
|
-
addMultipleToAlwaysApproved(toolNamesToAdd);
|
|
363
|
-
// Add to local session set (sync, for this conversation)
|
|
364
|
-
toolNamesToAdd.forEach(name => sessionApprovedTools.add(name));
|
|
365
|
-
}
|
|
366
|
-
// Add all tools to approved list
|
|
367
|
-
approvedTools.push(...toolsNeedingConfirmation);
|
|
298
|
+
// If approved_always, add ALL these tools to both global and session-approved sets
|
|
299
|
+
if (confirmation === 'approve_always') {
|
|
300
|
+
const toolNamesToAdd = toolsNeedingConfirmation.map(t => t.function.name);
|
|
301
|
+
// Add to global state (async, for future sessions)
|
|
302
|
+
addMultipleToAlwaysApproved(toolNamesToAdd);
|
|
303
|
+
// Add to local session set (sync, for this conversation)
|
|
304
|
+
toolNamesToAdd.forEach(name => sessionApprovedTools.add(name));
|
|
368
305
|
}
|
|
306
|
+
// Add all tools to approved list
|
|
307
|
+
approvedTools.push(...toolsNeedingConfirmation);
|
|
369
308
|
}
|
|
370
309
|
// Execute approved tools
|
|
371
310
|
const toolResults = await executeToolCalls(approvedTools);
|
|
@@ -390,7 +329,9 @@ export async function handleConversationWithTools(options) {
|
|
|
390
329
|
const statusText = isError ? `\n āā ${result.content}` : '';
|
|
391
330
|
// Check if this is an edit tool with diff data
|
|
392
331
|
let editDiffData;
|
|
393
|
-
if ((toolCall.function.name === 'filesystem-edit' ||
|
|
332
|
+
if ((toolCall.function.name === 'filesystem-edit' ||
|
|
333
|
+
toolCall.function.name === 'filesystem-edit_search') &&
|
|
334
|
+
!isError) {
|
|
394
335
|
try {
|
|
395
336
|
const resultData = JSON.parse(result.content);
|
|
396
337
|
if (resultData.oldContent && resultData.newContent) {
|
|
@@ -400,7 +341,7 @@ export async function handleConversationWithTools(options) {
|
|
|
400
341
|
filename: JSON.parse(toolCall.function.arguments).filePath,
|
|
401
342
|
completeOldContent: resultData.completeOldContent,
|
|
402
343
|
completeNewContent: resultData.completeNewContent,
|
|
403
|
-
contextStartLine: resultData.contextStartLine
|
|
344
|
+
contextStartLine: resultData.contextStartLine,
|
|
404
345
|
};
|
|
405
346
|
}
|
|
406
347
|
}
|
|
@@ -418,7 +359,7 @@ export async function handleConversationWithTools(options) {
|
|
|
418
359
|
stdout: resultData.stdout || '',
|
|
419
360
|
stderr: resultData.stderr || '',
|
|
420
361
|
exitCode: resultData.exitCode || 0,
|
|
421
|
-
command: resultData.command
|
|
362
|
+
command: resultData.command,
|
|
422
363
|
};
|
|
423
364
|
}
|
|
424
365
|
}
|
|
@@ -433,15 +374,19 @@ export async function handleConversationWithTools(options) {
|
|
|
433
374
|
...msg,
|
|
434
375
|
content: `${statusIcon} ${toolCall.function.name}${statusText}`,
|
|
435
376
|
toolPending: false,
|
|
436
|
-
toolCall: editDiffData
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
377
|
+
toolCall: editDiffData
|
|
378
|
+
? {
|
|
379
|
+
name: toolCall.function.name,
|
|
380
|
+
arguments: editDiffData,
|
|
381
|
+
}
|
|
382
|
+
: terminalResultData
|
|
383
|
+
? {
|
|
384
|
+
name: toolCall.function.name,
|
|
385
|
+
arguments: terminalResultData,
|
|
386
|
+
}
|
|
387
|
+
: msg.toolCall,
|
|
443
388
|
// Store tool result for preview rendering
|
|
444
|
-
toolResult: !isError ? result.content : undefined
|
|
389
|
+
toolResult: !isError ? result.content : undefined,
|
|
445
390
|
};
|
|
446
391
|
}
|
|
447
392
|
return msg;
|
|
@@ -461,8 +406,8 @@ export async function handleConversationWithTools(options) {
|
|
|
461
406
|
role: 'assistant',
|
|
462
407
|
content: '',
|
|
463
408
|
streaming: false,
|
|
464
|
-
showTodoTree: true
|
|
465
|
-
}
|
|
409
|
+
showTodoTree: true,
|
|
410
|
+
},
|
|
466
411
|
]);
|
|
467
412
|
}
|
|
468
413
|
// Check if there are pending user messages to insert
|
|
@@ -474,17 +419,20 @@ export async function handleConversationWithTools(options) {
|
|
|
474
419
|
// Combine multiple pending messages into one
|
|
475
420
|
const combinedMessage = pendingMessages.join('\n\n');
|
|
476
421
|
// Add user message to UI
|
|
477
|
-
const userMessage = {
|
|
422
|
+
const userMessage = {
|
|
423
|
+
role: 'user',
|
|
424
|
+
content: combinedMessage,
|
|
425
|
+
};
|
|
478
426
|
setMessages(prev => [...prev, userMessage]);
|
|
479
427
|
// Add user message to conversation history
|
|
480
428
|
conversationMessages.push({
|
|
481
429
|
role: 'user',
|
|
482
|
-
content: combinedMessage
|
|
430
|
+
content: combinedMessage,
|
|
483
431
|
});
|
|
484
432
|
// Save user message
|
|
485
433
|
saveMessage({
|
|
486
434
|
role: 'user',
|
|
487
|
-
content: combinedMessage
|
|
435
|
+
content: combinedMessage,
|
|
488
436
|
}).catch(error => {
|
|
489
437
|
console.error('Failed to save pending user message:', error);
|
|
490
438
|
});
|
|
@@ -499,13 +447,13 @@ export async function handleConversationWithTools(options) {
|
|
|
499
447
|
role: 'assistant',
|
|
500
448
|
content: streamedContent.trim(),
|
|
501
449
|
streaming: false,
|
|
502
|
-
discontinued: controller.signal.aborted
|
|
450
|
+
discontinued: controller.signal.aborted,
|
|
503
451
|
};
|
|
504
452
|
setMessages(prev => [...prev, finalAssistantMessage]);
|
|
505
453
|
// Add to conversation history and save
|
|
506
454
|
const assistantMessage = {
|
|
507
455
|
role: 'assistant',
|
|
508
|
-
content: streamedContent.trim()
|
|
456
|
+
content: streamedContent.trim(),
|
|
509
457
|
};
|
|
510
458
|
conversationMessages.push(assistantMessage);
|
|
511
459
|
saveMessage(assistantMessage).catch(error => {
|
|
@@ -26,6 +26,15 @@ export function useKeyboardInput(options) {
|
|
|
26
26
|
useInput((input, key) => {
|
|
27
27
|
if (disabled)
|
|
28
28
|
return;
|
|
29
|
+
// Shift+Tab - Toggle YOLO mode
|
|
30
|
+
if (key.shift && key.tab) {
|
|
31
|
+
executeCommand('yolo').then(result => {
|
|
32
|
+
if (onCommand) {
|
|
33
|
+
onCommand('yolo', result);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
29
38
|
// Handle escape key for double-ESC history navigation
|
|
30
39
|
if (key.escape) {
|
|
31
40
|
// Close file picker if open
|
|
@@ -34,18 +34,18 @@ export function useVSCodeState() {
|
|
|
34
34
|
if (vscodeConnectionStatus !== 'connecting') {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
// Set timeout for connecting state (30 seconds to allow for
|
|
37
|
+
// Set timeout for connecting state (30 seconds to allow for IDE plugin reconnection)
|
|
38
38
|
const connectingTimeout = setTimeout(() => {
|
|
39
39
|
const isConnected = vscodeConnection.isConnected();
|
|
40
|
-
const
|
|
40
|
+
const isClientRunning = vscodeConnection.isClientRunning();
|
|
41
41
|
// Only set error if still not connected after timeout
|
|
42
42
|
if (!isConnected) {
|
|
43
|
-
if (
|
|
44
|
-
//
|
|
43
|
+
if (isClientRunning) {
|
|
44
|
+
// Client is running but no connection - show error with helpful message
|
|
45
45
|
setVscodeConnectionStatus('error');
|
|
46
46
|
}
|
|
47
47
|
else {
|
|
48
|
-
//
|
|
48
|
+
// Client not running - go back to disconnected
|
|
49
49
|
setVscodeConnectionStatus('disconnected');
|
|
50
50
|
}
|
|
51
51
|
}
|
package/dist/mcp/filesystem.d.ts
CHANGED
|
@@ -131,8 +131,6 @@ export declare class FilesystemMCPService {
|
|
|
131
131
|
totalLines: number;
|
|
132
132
|
structureAnalysis?: StructureAnalysis;
|
|
133
133
|
diagnostics?: Diagnostic[];
|
|
134
|
-
completeOldContent?: string;
|
|
135
|
-
completeNewContent?: string;
|
|
136
134
|
}>;
|
|
137
135
|
/**
|
|
138
136
|
* Edit a file by replacing lines within a specified range
|
|
@@ -158,8 +156,6 @@ export declare class FilesystemMCPService {
|
|
|
158
156
|
linesModified: number;
|
|
159
157
|
structureAnalysis?: StructureAnalysis;
|
|
160
158
|
diagnostics?: Diagnostic[];
|
|
161
|
-
completeOldContent?: string;
|
|
162
|
-
completeNewContent?: string;
|
|
163
159
|
}>;
|
|
164
160
|
/**
|
|
165
161
|
* Resolve path relative to base path and normalize it
|