snow-ai 0.2.19 → 0.2.20

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.
@@ -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**Context7 Documentation:**\n- Use `context7-resolve-library-id` first to find library ID\n- Then use `context7-get-library-docs` to fetch documentation\n- Helpful for understanding third-party libraries\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.";
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.";
@@ -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 set new compressed state
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 ? error.message : 'Unknown compression 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
- options.setVscodeConnectionStatus('connecting');
67
- // Add command execution feedback
68
- const commandMessage = {
69
- role: 'command',
70
- content: '',
71
- commandName: commandName,
72
- };
73
- options.setMessages(prev => [...prev, commandMessage]);
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
- const commandMessage = {
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
- ? (config.basicModel || config.advancedModel || 'gpt-4.1')
81
- : (config.advancedModel || 'gpt-4.1');
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 => [...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) || sessionApprovedTools.has(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
- // Check if we should use DIFF+APPLY for filesystem tools
271
- let usedDiffApply = false;
272
- if (vscodeConnection.isConnected()) {
273
- // Try to use DIFF+APPLY for filesystem_create or filesystem_edit
274
- if (firstTool.function.name === 'filesystem-create' || firstTool.function.name === 'filesystem-edit') {
275
- try {
276
- const args = JSON.parse(firstTool.function.arguments);
277
- if (firstTool.function.name === 'filesystem-create') {
278
- // For create, show diff with empty old content
279
- const confirmation = await vscodeConnection.requestDiffApply(args.filePath, '', // Empty old content for new file
280
- args.content);
281
- if (confirmation === 'reject') {
282
- // Remove pending tool messages
283
- setMessages(prev => prev.filter(msg => !msg.toolPending));
284
- setMessages(prev => [...prev, {
285
- role: 'assistant',
286
- content: 'Tool call rejected, session ended',
287
- streaming: false
288
- }]);
289
- if (options.setIsStreaming) {
290
- options.setIsStreaming(false);
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 we didn't use DIFF+APPLY, fall back to regular CLI confirmation
335
- if (!usedDiffApply) {
336
- // Pass all tools for proper display in confirmation UI
337
- const allTools = toolsNeedingConfirmation.length > 1
338
- ? toolsNeedingConfirmation
339
- : undefined;
340
- // Use first tool for confirmation UI, but apply result to all
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' || toolCall.function.name === 'filesystem-edit_search') && !isError) {
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
- name: toolCall.function.name,
438
- arguments: editDiffData
439
- } : terminalResultData ? {
440
- name: toolCall.function.name,
441
- arguments: terminalResultData
442
- } : msg.toolCall,
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 = { role: 'user', content: combinedMessage };
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
@@ -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