snow-ai 0.3.33 → 0.3.34

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.
@@ -19,9 +19,10 @@ export async function createEmbeddings(options) {
19
19
  if (!baseUrl) {
20
20
  throw new Error('Embedding base URL is required');
21
21
  }
22
- if (!apiKey) {
23
- throw new Error('Embedding API key is required');
24
- }
22
+ // API key is optional for local deployments (e.g., Ollama)
23
+ // if (!apiKey) {
24
+ // throw new Error('Embedding API key is required');
25
+ // }
25
26
  if (!input || input.length === 0) {
26
27
  throw new Error('Input texts are required');
27
28
  }
@@ -40,12 +41,16 @@ export async function createEmbeddings(options) {
40
41
  const url = baseUrl.endsWith('/embeddings')
41
42
  ? baseUrl
42
43
  : `${baseUrl.replace(/\/$/, '')}/embeddings`;
44
+ // Build headers - only include Authorization if API key is provided
45
+ const headers = {
46
+ 'Content-Type': 'application/json',
47
+ };
48
+ if (apiKey) {
49
+ headers['Authorization'] = `Bearer ${apiKey}`;
50
+ }
43
51
  const fetchOptions = addProxyToFetchOptions(url, {
44
52
  method: 'POST',
45
- headers: {
46
- 'Content-Type': 'application/json',
47
- Authorization: `Bearer ${apiKey}`,
48
- },
53
+ headers,
49
54
  body: JSON.stringify(requestBody),
50
55
  });
51
56
  const response = await fetch(url, fetchOptions);
@@ -317,10 +317,14 @@ function hasCodebaseSearchTool(tools) {
317
317
  function getWorkflowSection(hasCodebase) {
318
318
  if (hasCodebase) {
319
319
  return `**Your workflow:**
320
- 1. **Understand the task** - For conceptual questions, try \\\`codebase-search\\\` FIRST (semantic search)
320
+ 1. **🚀 START WITH SEMANTIC SEARCH** - Use \\\`codebase-search\\\` as your PRIMARY exploration tool
321
+ - 🎯 ALWAYS try \\\`codebase-search\\\` FIRST for ANY code understanding task
322
+ - 💡 Examples: "authentication logic", "error handling", "user validation", "database queries"
323
+ - ⚡ Dramatically faster than reading multiple files manually
324
+ - 📊 Returns relevant code snippets with context - read results to understand the codebase
321
325
  2. Read the primary file(s) mentioned (or files found by codebase search)
322
326
  3. Check dependencies/imports that directly impact the change
323
- 4. For precise symbol lookup, use \\\`ace-search-symbols\\\`, \\\`ace-find-definition\\\`, or \\\`ace-find-references\\\`
327
+ 4. For precise symbol lookup AFTER understanding context, use \\\`ace-search-symbols\\\`, \\\`ace-find-definition\\\`, or \\\`ace-find-references\\\`
324
328
  5. Read related files ONLY if they're critical to understanding the task
325
329
  6. Write/modify code with proper context
326
330
  7. Verify with build
@@ -351,16 +355,17 @@ function getCodeSearchSection(hasCodebase) {
351
355
 
352
356
  🎯 **Priority Order (use in this sequence):**
353
357
 
354
- 1. **Codebase Semantic Search** (⚡ HIGHEST PRIORITY):
358
+ 1. **Codebase Semantic Search** (⚡ ALWAYS TRY THIS FIRST!):
355
359
  - \\\`codebase-search\\\` - Semantic search using embeddings
356
360
  - 🔍 Find code by MEANING, not just keywords
357
- - 🎯 Best for: "how is authentication handled", "error handling patterns"
361
+ - 🎯 Best for: "how is authentication handled", "error handling patterns", "validation logic"
358
362
  - 📊 Returns: Full code content + similarity scores + file locations
359
- - 💡 **IMPORTANT**: Always try this FIRST for conceptual queries!
360
- - 🚀 **When to use**: Understanding concepts, finding similar code, pattern discovery
361
- - **When to skip**: Exact symbol names, file-specific searches (use ACE instead)
363
+ - 💡 **CRITICAL**: Use this as your PRIMARY tool for understanding codebase
364
+ - 🚀 **When to use**: ANY code understanding task, finding implementations, pattern discovery
365
+ - **Example queries**: "user authentication", "database connection", "API error handling"
366
+ - ❌ **When to skip**: ONLY skip if you need exact symbol names or regex patterns
362
367
 
363
- 2. **ACE Code Search** (Fallback for precise lookups):
368
+ 2. **ACE Code Search** (Use AFTER semantic search for precise lookups):
364
369
  - \\\`ace-search-symbols\\\` - Find functions/classes/variables by exact name
365
370
  - \\\`ace-find-definition\\\` - Go to definition of a symbol
366
371
  - \\\`ace-find-references\\\` - Find all usages of a symbol
@@ -8,13 +8,42 @@ export function useClipboard(buffer, updateCommandPanelState, updateFilePickerSt
8
8
  if (process.platform === 'win32') {
9
9
  // Windows: Use PowerShell to read image from clipboard
10
10
  try {
11
- const psScript = `Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $clipboard = [System.Windows.Forms.Clipboard]::GetImage(); if ($clipboard -ne $null) { $ms = New-Object System.IO.MemoryStream; $clipboard.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); $bytes = $ms.ToArray(); $ms.Close(); [Convert]::ToBase64String($bytes) }`;
12
- const base64Raw = execSync(`powershell -Command "${psScript}"`, {
11
+ // Optimized PowerShell script with compression for large images
12
+ const psScript = 'Add-Type -AssemblyName System.Windows.Forms; ' +
13
+ 'Add-Type -AssemblyName System.Drawing; ' +
14
+ '$clipboard = [System.Windows.Forms.Clipboard]::GetImage(); ' +
15
+ 'if ($clipboard -ne $null) { ' +
16
+ '$ms = New-Object System.IO.MemoryStream; ' +
17
+ '$width = $clipboard.Width; ' +
18
+ '$height = $clipboard.Height; ' +
19
+ '$maxSize = 2048; ' +
20
+ 'if ($width -gt $maxSize -or $height -gt $maxSize) { ' +
21
+ '$ratio = [Math]::Min($maxSize / $width, $maxSize / $height); ' +
22
+ '$newWidth = [int]($width * $ratio); ' +
23
+ '$newHeight = [int]($height * $ratio); ' +
24
+ '$resized = New-Object System.Drawing.Bitmap($newWidth, $newHeight); ' +
25
+ '$graphics = [System.Drawing.Graphics]::FromImage($resized); ' +
26
+ '$graphics.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality; ' +
27
+ '$graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic; ' +
28
+ '$graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality; ' +
29
+ '$graphics.DrawImage($clipboard, 0, 0, $newWidth, $newHeight); ' +
30
+ '$resized.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); ' +
31
+ '$graphics.Dispose(); ' +
32
+ '$resized.Dispose(); ' +
33
+ '} else { ' +
34
+ '$clipboard.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); ' +
35
+ '}; ' +
36
+ '$bytes = $ms.ToArray(); ' +
37
+ '$ms.Close(); ' +
38
+ '[Convert]::ToBase64String($bytes); ' +
39
+ '}';
40
+ const base64Raw = execSync(`powershell -NoProfile -Command "${psScript}"`, {
13
41
  encoding: 'utf-8',
14
- timeout: 5000,
42
+ timeout: 10000,
43
+ maxBuffer: 50 * 1024 * 1024, // 50MB buffer
15
44
  });
16
- // 清理所有空白字符(包括换行符)
17
- const base64 = base64Raw.replace(/\s+/g, '');
45
+ // 高效清理:一次性移除所有空白字符
46
+ const base64 = base64Raw.replace(/\s/g, '');
18
47
  if (base64 && base64.length > 100) {
19
48
  // 直接传入 base64 数据,不需要 data URL 前缀
20
49
  buffer.insertImage(base64, 'image/png');
@@ -28,6 +57,7 @@ export function useClipboard(buffer, updateCommandPanelState, updateFilePickerSt
28
57
  }
29
58
  catch (imgError) {
30
59
  // No image in clipboard or error, fall through to text
60
+ logger.error('Failed to read image from Windows clipboard:', imgError);
31
61
  }
32
62
  }
33
63
  else if (process.platform === 'darwin') {
@@ -52,13 +82,34 @@ end try'`;
52
82
  encoding: 'utf-8',
53
83
  timeout: 3000,
54
84
  });
55
- // Read the file as base64
56
- const base64Raw = execSync(`base64 -i "${tmpFile}"`, {
85
+ // Use sips to resize if needed, then convert to base64
86
+ // First check image size
87
+ const sizeCheck = execSync(`sips -g pixelWidth -g pixelHeight "${tmpFile}" | grep -E "pixelWidth|pixelHeight" | awk '{print $2}'`, {
57
88
  encoding: 'utf-8',
58
89
  timeout: 2000,
59
90
  });
60
- // 清理所有空白字符(包括换行符)
61
- const base64 = base64Raw.replace(/\s+/g, '');
91
+ const [widthStr, heightStr] = sizeCheck.trim().split('\n');
92
+ const width = parseInt(widthStr || '0', 10);
93
+ const height = parseInt(heightStr || '0', 10);
94
+ const maxSize = 2048;
95
+ // Resize if too large
96
+ if (width > maxSize || height > maxSize) {
97
+ const ratio = Math.min(maxSize / width, maxSize / height);
98
+ const newWidth = Math.floor(width * ratio);
99
+ const newHeight = Math.floor(height * ratio);
100
+ execSync(`sips -z ${newHeight} ${newWidth} "${tmpFile}" --out "${tmpFile}"`, {
101
+ encoding: 'utf-8',
102
+ timeout: 5000,
103
+ });
104
+ }
105
+ // Read the file as base64 with optimized buffer
106
+ const base64Raw = execSync(`base64 -i "${tmpFile}"`, {
107
+ encoding: 'utf-8',
108
+ timeout: 5000,
109
+ maxBuffer: 50 * 1024 * 1024, // 50MB buffer
110
+ });
111
+ // 高效清理:一次性移除所有空白字符
112
+ const base64 = base64Raw.replace(/\s/g, '');
62
113
  // Clean up temp file
63
114
  try {
64
115
  execSync(`rm "${tmpFile}"`, { timeout: 1000 });
@@ -85,9 +85,10 @@ export default function CodeBaseConfigScreen({ onBack, onSave, inlineMode = fals
85
85
  }
86
86
  if (!embeddingBaseUrl.trim()) {
87
87
  validationErrors.push('Embedding base URL is required when enabled');
88
- }
89
- if (!embeddingApiKey.trim()) {
90
- validationErrors.push('Embedding API key is required when enabled');
88
+ // Embedding API key is optional (for local deployments like Ollama)
89
+ // if (!embeddingApiKey.trim()) {
90
+ // validationErrors.push('Embedding API key is required when enabled');
91
+ // }
91
92
  }
92
93
  if (embeddingDimensions <= 0) {
93
94
  validationErrors.push('Embedding dimensions must be greater than 0');
@@ -175,7 +176,7 @@ export default function CodeBaseConfigScreen({ onBack, onSave, inlineMode = fals
175
176
  return (React.createElement(Box, { key: field, flexDirection: "column" },
176
177
  React.createElement(Text, { color: isActive ? 'green' : 'white' },
177
178
  isActive ? '❯ ' : ' ',
178
- "Embedding API Key:"),
179
+ "Embedding API Key (Optional for local):"),
179
180
  isCurrentlyEditing && (React.createElement(Box, { marginLeft: 3 },
180
181
  React.createElement(Text, { color: "cyan" },
181
182
  React.createElement(TextInput, { value: embeddingApiKey, onChange: value => setEmbeddingApiKey(stripFocusArtifacts(value)), onSubmit: () => setIsEditing(false), mask: "*" })))),
@@ -41,7 +41,7 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
41
41
  {
42
42
  label: 'CodeBase Settings',
43
43
  value: 'codebase',
44
- infoText: 'Configure codebase indexing with embedding and LLM models',
44
+ infoText: 'Configure codebase indexing with embedding models',
45
45
  },
46
46
  {
47
47
  label: 'System Prompt Settings',
@@ -260,7 +260,7 @@ function migrateSystemPromptFromTxt() {
260
260
  writeFileSync(SYSTEM_PROMPT_JSON_FILE, JSON.stringify(config, null, 2), 'utf8');
261
261
  // 删除旧文件
262
262
  unlinkSync(SYSTEM_PROMPT_FILE);
263
- console.log('✅ Migrated system prompt from txt to json format.');
263
+ // console.log('✅ Migrated system prompt from txt to json format.');
264
264
  }
265
265
  catch (error) {
266
266
  console.error('Failed to migrate system prompt:', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.3.33",
3
+ "version": "0.3.34",
4
4
  "description": "Intelligent Command Line Assistant powered by AI",
5
5
  "license": "MIT",
6
6
  "bin": {