snow-ai 0.3.36 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/agents/codebaseIndexAgent.js +1 -0
  2. package/dist/agents/codebaseReviewAgent.d.ts +61 -0
  3. package/dist/agents/codebaseReviewAgent.js +301 -0
  4. package/dist/agents/promptOptimizeAgent.d.ts +54 -0
  5. package/dist/agents/promptOptimizeAgent.js +268 -0
  6. package/dist/api/anthropic.js +1 -0
  7. package/dist/api/chat.js +1 -0
  8. package/dist/api/embedding.js +1 -0
  9. package/dist/api/gemini.js +2 -1
  10. package/dist/api/responses.js +1 -0
  11. package/dist/api/systemPrompt.d.ts +1 -5
  12. package/dist/api/systemPrompt.js +168 -100
  13. package/dist/app.js +14 -6
  14. package/dist/cli.js +1 -1
  15. package/dist/hooks/useCommandPanel.js +48 -46
  16. package/dist/hooks/useConversation.d.ts +2 -1
  17. package/dist/hooks/useConversation.js +116 -30
  18. package/dist/hooks/useGlobalExit.js +4 -2
  19. package/dist/hooks/useStreamingState.d.ts +9 -0
  20. package/dist/hooks/useStreamingState.js +3 -0
  21. package/dist/i18n/I18nContext.d.ts +14 -0
  22. package/dist/i18n/I18nContext.js +24 -0
  23. package/dist/i18n/index.d.ts +3 -0
  24. package/dist/i18n/index.js +2 -0
  25. package/dist/i18n/lang/en.d.ts +2 -0
  26. package/dist/i18n/lang/en.js +483 -0
  27. package/dist/i18n/lang/es.d.ts +2 -0
  28. package/dist/i18n/lang/es.js +483 -0
  29. package/dist/i18n/lang/ja.d.ts +2 -0
  30. package/dist/i18n/lang/ja.js +483 -0
  31. package/dist/i18n/lang/ko.d.ts +2 -0
  32. package/dist/i18n/lang/ko.js +483 -0
  33. package/dist/i18n/lang/zh-TW.d.ts +2 -0
  34. package/dist/i18n/lang/zh-TW.js +483 -0
  35. package/dist/i18n/lang/zh.d.ts +2 -0
  36. package/dist/i18n/lang/zh.js +483 -0
  37. package/dist/i18n/translations.d.ts +2 -0
  38. package/dist/i18n/translations.js +14 -0
  39. package/dist/i18n/types.d.ts +459 -0
  40. package/dist/i18n/types.js +1 -0
  41. package/dist/mcp/aceCodeSearch.d.ts +17 -48
  42. package/dist/mcp/aceCodeSearch.js +24 -56
  43. package/dist/mcp/bash.js +8 -1
  44. package/dist/mcp/codebaseSearch.d.ts +1 -1
  45. package/dist/mcp/codebaseSearch.js +159 -30
  46. package/dist/mcp/filesystem.d.ts +3 -80
  47. package/dist/mcp/filesystem.js +23 -103
  48. package/dist/mcp/subagent.d.ts +2 -1
  49. package/dist/mcp/subagent.js +54 -5
  50. package/dist/ui/components/ChatInput.js +22 -25
  51. package/dist/ui/components/CommandPanel.d.ts +1 -1
  52. package/dist/ui/components/CommandPanel.js +20 -13
  53. package/dist/ui/components/DiffViewer.d.ts +1 -1
  54. package/dist/ui/components/DiffViewer.js +101 -91
  55. package/dist/ui/components/FileList.js +22 -11
  56. package/dist/ui/components/HelpPanel.js +47 -21
  57. package/dist/ui/components/Menu.js +6 -2
  58. package/dist/ui/components/MessageList.d.ts +6 -0
  59. package/dist/ui/components/MessageList.js +1 -1
  60. package/dist/ui/components/ToolConfirmation.d.ts +4 -1
  61. package/dist/ui/components/ToolConfirmation.js +28 -2
  62. package/dist/ui/components/ToolResultPreview.d.ts +2 -1
  63. package/dist/ui/components/ToolResultPreview.js +41 -25
  64. package/dist/ui/pages/ChatScreen.js +177 -56
  65. package/dist/ui/pages/CodeBaseConfigScreen.js +54 -30
  66. package/dist/ui/pages/ConfigScreen.js +138 -98
  67. package/dist/ui/pages/CustomHeadersScreen.js +75 -69
  68. package/dist/ui/pages/LanguageSettingsScreen.d.ts +7 -0
  69. package/dist/ui/pages/LanguageSettingsScreen.js +89 -0
  70. package/dist/ui/pages/ProxyConfigScreen.js +27 -23
  71. package/dist/ui/pages/SensitiveCommandConfigScreen.js +32 -25
  72. package/dist/ui/pages/SubAgentConfigScreen.js +88 -75
  73. package/dist/ui/pages/SystemPromptConfigScreen.js +31 -26
  74. package/dist/ui/pages/WelcomeScreen.js +40 -26
  75. package/dist/utils/apiConfig.d.ts +2 -0
  76. package/dist/utils/codebaseConfig.d.ts +1 -5
  77. package/dist/utils/codebaseConfig.js +2 -10
  78. package/dist/utils/codebaseSearchEvents.d.ts +16 -0
  79. package/dist/utils/codebaseSearchEvents.js +13 -0
  80. package/dist/utils/commands/agent.js +2 -2
  81. package/dist/utils/commands/init.js +1 -1
  82. package/dist/utils/configManager.js +26 -5
  83. package/dist/utils/contextCompressor.js +1 -1
  84. package/dist/utils/languageConfig.d.ts +21 -0
  85. package/dist/utils/languageConfig.js +61 -0
  86. package/dist/utils/mcpToolsManager.js +0 -9
  87. package/dist/utils/notebookManager.js +11 -4
  88. package/dist/utils/sessionConverter.js +13 -3
  89. package/dist/utils/sessionManager.d.ts +1 -0
  90. package/dist/utils/subAgentConfig.d.ts +10 -5
  91. package/dist/utils/subAgentConfig.js +112 -19
  92. package/dist/utils/subAgentExecutor.d.ts +9 -1
  93. package/dist/utils/subAgentExecutor.js +122 -9
  94. package/dist/utils/toolExecutor.d.ts +2 -1
  95. package/dist/utils/toolExecutor.js +1 -2
  96. package/dist/utils/usageLogger.js +18 -3
  97. package/package.json +2 -1
@@ -4,6 +4,7 @@ import TextInput from 'ink-text-input';
4
4
  import { Alert, Spinner } from '@inkjs/ui';
5
5
  import { getMCPServicesInfo } from '../../utils/mcpToolsManager.js';
6
6
  import { createSubAgent, updateSubAgent, getSubAgent, validateSubAgent, } from '../../utils/subAgentConfig.js';
7
+ import { useI18n } from '../../i18n/index.js';
7
8
  // Focus event handling - prevent terminal focus events from appearing as input
8
9
  const focusEventTokenRegex = /(?:\x1b)?\[[0-9;]*[IO]/g;
9
10
  const isFocusEventInput = (value) => {
@@ -37,59 +38,8 @@ const stripFocusArtifacts = (value) => {
37
38
  .replace(/\[[0-9;]*[IO]/g, '')
38
39
  .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
39
40
  };
40
- const toolCategories = [
41
- {
42
- name: 'Filesystem Tools',
43
- tools: [
44
- 'filesystem-read',
45
- 'filesystem-create',
46
- 'filesystem-edit',
47
- 'filesystem-edit_search',
48
- 'filesystem-delete',
49
- 'filesystem-list',
50
- ],
51
- },
52
- {
53
- name: 'ACE Code Search Tools',
54
- tools: [
55
- 'ace-search_symbols',
56
- 'ace-find_definition',
57
- 'ace-find_references',
58
- 'ace-semantic_search',
59
- 'ace-text_search',
60
- 'ace-file_outline',
61
- 'ace-index_stats',
62
- 'ace-clear_cache',
63
- ],
64
- },
65
- {
66
- name: 'Codebase Search Tools',
67
- tools: ['codebase-search'],
68
- },
69
- {
70
- name: 'Terminal Tools',
71
- tools: ['terminal-execute'],
72
- },
73
- {
74
- name: 'TODO Management Tools',
75
- tools: [
76
- 'todo-create',
77
- 'todo-get',
78
- 'todo-update',
79
- 'todo-add',
80
- 'todo-delete',
81
- ],
82
- },
83
- {
84
- name: 'Web Search Tools',
85
- tools: ['websearch-search', 'websearch-fetch'],
86
- },
87
- {
88
- name: 'IDE Diagnostics Tools',
89
- tools: ['ide-get_diagnostics'],
90
- },
91
- ];
92
41
  export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = false, agentId, }) {
42
+ const { t } = useI18n();
93
43
  const [agentName, setAgentName] = useState('');
94
44
  const [description, setDescription] = useState('');
95
45
  const [role, setRole] = useState('');
@@ -103,6 +53,56 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
103
53
  const [mcpServices, setMcpServices] = useState([]);
104
54
  const [loadError, setLoadError] = useState(null);
105
55
  const isEditMode = !!agentId;
56
+ // Tool categories with translations
57
+ const toolCategories = [
58
+ {
59
+ name: t.subAgentConfig.filesystemTools,
60
+ tools: [
61
+ 'filesystem-read',
62
+ 'filesystem-create',
63
+ 'filesystem-edit',
64
+ 'filesystem-edit_search',
65
+ ],
66
+ },
67
+ {
68
+ name: t.subAgentConfig.aceTools,
69
+ tools: [
70
+ 'ace-find_definition',
71
+ 'ace-find_references',
72
+ 'ace-semantic_search',
73
+ 'ace-text_search',
74
+ 'ace-file_outline',
75
+ 'ace-index_stats',
76
+ 'ace-clear_cache',
77
+ ],
78
+ },
79
+ {
80
+ name: t.subAgentConfig.codebaseTools,
81
+ tools: ['codebase-search'],
82
+ },
83
+ {
84
+ name: t.subAgentConfig.terminalTools,
85
+ tools: ['terminal-execute'],
86
+ },
87
+ {
88
+ name: t.subAgentConfig.todoTools,
89
+ tools: [
90
+ 'todo-create',
91
+ 'todo-get',
92
+ 'todo-update',
93
+ 'todo-add',
94
+ 'todo-delete',
95
+ ],
96
+ },
97
+ {
98
+ name: t.subAgentConfig.webSearchTools,
99
+ tools: ['websearch-search', 'websearch-fetch'],
100
+ },
101
+ {
102
+ name: t.subAgentConfig.ideTools,
103
+ tools: ['ide-get_diagnostics'],
104
+ },
105
+ ];
106
106
  // Load existing agent data in edit mode
107
107
  useEffect(() => {
108
108
  if (agentId) {
@@ -142,13 +142,13 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
142
142
  for (const service of mcpServices) {
143
143
  if (!service.isBuiltIn && service.connected && service.tools.length > 0) {
144
144
  categories.push({
145
- name: `${service.serviceName} (MCP)`,
145
+ name: `${service.serviceName} ${t.subAgentConfig.categoryMCP}`,
146
146
  tools: service.tools.map(t => t.name),
147
147
  });
148
148
  }
149
149
  }
150
150
  return categories;
151
- }, [mcpServices]);
151
+ }, [mcpServices, toolCategories, t]);
152
152
  // Get all available tools
153
153
  const allTools = useMemo(() => allToolCategories.flatMap(cat => cat.tools), [allToolCategories]);
154
154
  const handleToggleTool = useCallback((tool) => {
@@ -204,7 +204,7 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
204
204
  tools: Array.from(selectedTools),
205
205
  });
206
206
  if (errors.length > 0) {
207
- setSaveError(errors[0] || 'Validation failed');
207
+ setSaveError(errors[0] || t.subAgentConfig.validationFailed);
208
208
  return;
209
209
  }
210
210
  try {
@@ -228,7 +228,7 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
228
228
  }, 1500);
229
229
  }
230
230
  catch (error) {
231
- setSaveError(error instanceof Error ? error.message : 'Failed to save sub-agent');
231
+ setSaveError(error instanceof Error ? error.message : t.subAgentConfig.saveError);
232
232
  }
233
233
  }, [
234
234
  agentName,
@@ -238,6 +238,7 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
238
238
  onSave,
239
239
  isEditMode,
240
240
  agentId,
241
+ t,
241
242
  ]);
242
243
  useInput((rawInput, key) => {
243
244
  const input = stripFocusArtifacts(rawInput);
@@ -351,12 +352,13 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
351
352
  });
352
353
  const renderToolSelection = () => {
353
354
  return (React.createElement(Box, { flexDirection: "column" },
354
- React.createElement(Text, { bold: true, color: "cyan" }, "Tool Selection:"),
355
+ React.createElement(Text, { bold: true, color: "cyan" }, t.subAgentConfig.toolSelection),
355
356
  isLoadingMCP && (React.createElement(Box, null,
356
- React.createElement(Spinner, { label: "Loading MCP services..." }))),
357
+ React.createElement(Spinner, { label: t.subAgentConfig.loadingMCP }))),
357
358
  loadError && (React.createElement(Box, null,
358
359
  React.createElement(Text, { color: "yellow" },
359
- "\u26A0 ",
360
+ t.subAgentConfig.mcpLoadError,
361
+ " ",
360
362
  loadError))),
361
363
  allToolCategories.map((category, catIndex) => {
362
364
  const isCurrent = catIndex === selectedCategoryIndex;
@@ -382,39 +384,50 @@ export default function SubAgentConfigScreen({ onBack, onSave, inlineMode = fals
382
384
  })))));
383
385
  }),
384
386
  React.createElement(Text, { color: "gray", dimColor: true },
385
- "Selected: ",
387
+ t.subAgentConfig.selectedTools,
388
+ " ",
386
389
  selectedTools.size,
387
- " / ",
390
+ " /",
391
+ ' ',
388
392
  allTools.length,
389
- " tools")));
393
+ " ",
394
+ t.subAgentConfig.toolsCount)));
390
395
  };
391
396
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
392
397
  !inlineMode && (React.createElement(Box, { marginBottom: 1 },
393
398
  React.createElement(Text, { bold: true, color: "cyan" },
394
- "\u2746 ",
395
- isEditMode ? 'Edit' : 'New',
396
- " Sub-Agent"))),
399
+ "\u2746",
400
+ ' ',
401
+ isEditMode
402
+ ? t.subAgentConfig.titleEdit
403
+ : t.subAgentConfig.titleNew,
404
+ ' ',
405
+ t.subAgentConfig.title))),
397
406
  showSuccess && (React.createElement(Box, { marginBottom: 1 },
398
407
  React.createElement(Alert, { variant: "success" },
399
- "Sub-agent ",
400
- isEditMode ? 'updated' : 'created',
401
- " successfully!"))),
408
+ "Sub-agent",
409
+ ' ',
410
+ isEditMode
411
+ ? t.subAgentConfig.saveSuccessEdit
412
+ : t.subAgentConfig.saveSuccessCreate,
413
+ ' ',
414
+ "successfully!"))),
402
415
  saveError && (React.createElement(Box, { marginBottom: 1 },
403
416
  React.createElement(Alert, { variant: "error" }, saveError))),
404
417
  React.createElement(Box, { flexDirection: "column" },
405
418
  React.createElement(Box, { flexDirection: "column" },
406
- React.createElement(Text, { bold: true, color: currentField === 'name' ? 'green' : 'white' }, "Agent Name:"),
419
+ React.createElement(Text, { bold: true, color: currentField === 'name' ? 'green' : 'white' }, t.subAgentConfig.agentName),
407
420
  React.createElement(Box, { marginLeft: 2 },
408
- React.createElement(TextInput, { value: agentName, onChange: value => setAgentName(stripFocusArtifacts(value)), placeholder: "Enter agent name...", focus: currentField === 'name' }))),
421
+ React.createElement(TextInput, { value: agentName, onChange: value => setAgentName(stripFocusArtifacts(value)), placeholder: t.subAgentConfig.agentNamePlaceholder, focus: currentField === 'name' }))),
409
422
  React.createElement(Box, { flexDirection: "column" },
410
- React.createElement(Text, { bold: true, color: currentField === 'description' ? 'green' : 'white' }, "Description:"),
423
+ React.createElement(Text, { bold: true, color: currentField === 'description' ? 'green' : 'white' }, t.subAgentConfig.description),
411
424
  React.createElement(Box, { marginLeft: 2 },
412
- React.createElement(TextInput, { value: description, onChange: value => setDescription(stripFocusArtifacts(value)), placeholder: "Enter agent description...", focus: currentField === 'description' }))),
425
+ React.createElement(TextInput, { value: description, onChange: value => setDescription(stripFocusArtifacts(value)), placeholder: t.subAgentConfig.descriptionPlaceholder, focus: currentField === 'description' }))),
413
426
  React.createElement(Box, { flexDirection: "column" },
414
- React.createElement(Text, { bold: true, color: currentField === 'role' ? 'green' : 'white' }, "Role (Optional):"),
427
+ React.createElement(Text, { bold: true, color: currentField === 'role' ? 'green' : 'white' }, t.subAgentConfig.roleOptional),
415
428
  React.createElement(Box, { marginLeft: 2 },
416
- React.createElement(TextInput, { value: role, onChange: value => setRole(stripFocusArtifacts(value)), placeholder: "Specify agent role to guide output and focus...", focus: currentField === 'role' }))),
429
+ React.createElement(TextInput, { value: role, onChange: value => setRole(stripFocusArtifacts(value)), placeholder: t.subAgentConfig.rolePlaceholder, focus: currentField === 'role' }))),
417
430
  renderToolSelection(),
418
431
  React.createElement(Box, { marginTop: 1 },
419
- React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193: Navigate | \u2190\u2192: Switch category | Space: Toggle | A: Toggle all | Enter: Save | Esc: Back")))));
432
+ React.createElement(Text, { color: "gray", dimColor: true }, t.subAgentConfig.navigationHint)))));
420
433
  }
@@ -4,7 +4,9 @@ import Gradient from 'ink-gradient';
4
4
  import { Alert } from '@inkjs/ui';
5
5
  import TextInput from 'ink-text-input';
6
6
  import { getSystemPromptConfig, saveSystemPromptConfig, } from '../../utils/apiConfig.js';
7
+ import { useI18n } from '../../i18n/index.js';
7
8
  export default function SystemPromptConfigScreen({ onBack }) {
9
+ const { t } = useI18n();
8
10
  const [config, setConfig] = useState(() => {
9
11
  return (getSystemPromptConfig() || {
10
12
  active: '',
@@ -39,7 +41,7 @@ export default function SystemPromptConfigScreen({ onBack }) {
39
41
  return true;
40
42
  }
41
43
  catch (err) {
42
- setError(err instanceof Error ? err.message : 'Failed to save');
44
+ setError(err instanceof Error ? err.message : t.systemPromptConfig.saveError);
43
45
  return false;
44
46
  }
45
47
  };
@@ -231,18 +233,18 @@ export default function SystemPromptConfigScreen({ onBack }) {
231
233
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
232
234
  React.createElement(Box, { marginBottom: 1, borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 },
233
235
  React.createElement(Box, { flexDirection: "column" },
234
- React.createElement(Gradient, { name: "rainbow" }, "System Prompt Management"),
235
- React.createElement(Text, { color: "gray", dimColor: true }, "Manage multiple system prompts and switch between them"))),
236
+ React.createElement(Gradient, { name: "rainbow" }, t.systemPromptConfig.title),
237
+ React.createElement(Text, { color: "gray", dimColor: true }, t.systemPromptConfig.subtitle))),
236
238
  error && (React.createElement(Box, { marginBottom: 1 },
237
239
  React.createElement(Alert, { variant: "error" }, error))),
238
240
  React.createElement(Box, { marginBottom: 1 },
239
241
  React.createElement(Text, { bold: true },
240
- "Active Prompt:",
242
+ t.systemPromptConfig.activePrompt,
241
243
  ' ',
242
- React.createElement(Text, { color: "green" }, activePrompt?.name || 'None'))),
244
+ React.createElement(Text, { color: "green" }, activePrompt?.name || t.systemPromptConfig.none))),
243
245
  config.prompts.length === 0 ? (React.createElement(Box, { marginBottom: 1 },
244
- React.createElement(Text, { color: "yellow" }, "No system prompts configured. Press Enter to add one."))) : (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
245
- React.createElement(Text, { bold: true, color: "cyan" }, "Available Prompts:"),
246
+ React.createElement(Text, { color: "yellow" }, t.systemPromptConfig.noPromptsConfigured))) : (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
247
+ React.createElement(Text, { bold: true, color: "cyan" }, t.systemPromptConfig.availablePrompts),
246
248
  config.prompts.map((prompt, index) => (React.createElement(Box, { key: prompt.id, marginLeft: 2 },
247
249
  React.createElement(Text, { color: index === selectedIndex
248
250
  ? 'green'
@@ -258,23 +260,25 @@ export default function SystemPromptConfigScreen({ onBack }) {
258
260
  prompt.content.substring(0, 50),
259
261
  prompt.content.length > 50 ? '...' : '')))))))),
260
262
  React.createElement(Box, { marginBottom: 1 },
261
- React.createElement(Text, { bold: true, color: "cyan" }, "Actions:")),
263
+ React.createElement(Text, { bold: true, color: "cyan" }, t.systemPromptConfig.actions)),
262
264
  React.createElement(Box, { flexDirection: "column", marginBottom: 1, marginLeft: 2 }, actions.map(action => (React.createElement(Text, { key: action, color: currentAction === action ? 'green' : 'gray', bold: currentAction === action },
263
265
  currentAction === action ? '❯ ' : ' ',
264
- action === 'activate' && 'Activate',
265
- action === 'deactivate' && 'Deactivate',
266
- action === 'edit' && 'Edit',
267
- action === 'delete' && 'Delete',
268
- action === 'add' && 'Add New',
269
- action === 'back' && '[ESC] Back')))),
266
+ action === 'activate' && t.systemPromptConfig.activate,
267
+ action === 'deactivate' && t.systemPromptConfig.deactivate,
268
+ action === 'edit' && t.systemPromptConfig.edit,
269
+ action === 'delete' && t.systemPromptConfig.delete,
270
+ action === 'add' && t.systemPromptConfig.addNew,
271
+ action === 'back' && t.systemPromptConfig.escBack)))),
270
272
  React.createElement(Box, { marginTop: 1 },
271
- React.createElement(Text, { color: "gray", dimColor: true }, "Use \u2191\u2193 to select prompt, \u2190\u2192 to select action, Enter to confirm"))));
273
+ React.createElement(Text, { color: "gray", dimColor: true }, t.systemPromptConfig.navigationHint))));
272
274
  }
273
275
  // Render add/edit view
274
276
  if (view === 'add' || view === 'edit') {
275
277
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
276
278
  React.createElement(Box, { marginBottom: 1, borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 },
277
- React.createElement(Gradient, { name: "rainbow" }, view === 'add' ? 'Add New System Prompt' : 'Edit System Prompt')),
279
+ React.createElement(Gradient, { name: "rainbow" }, view === 'add'
280
+ ? t.systemPromptConfig.addNewTitle
281
+ : t.systemPromptConfig.editTitle)),
278
282
  error && (React.createElement(Box, { marginBottom: 1 },
279
283
  React.createElement(Alert, { variant: "error" }, error))),
280
284
  React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
@@ -282,38 +286,39 @@ export default function SystemPromptConfigScreen({ onBack }) {
282
286
  React.createElement(Box, { flexDirection: "column" },
283
287
  React.createElement(Text, { color: editingField === 'name' ? 'green' : 'white' },
284
288
  editingField === 'name' ? '❯ ' : ' ',
285
- "Name:"),
289
+ t.systemPromptConfig.nameLabel),
286
290
  editingField === 'name' && isEditing && (React.createElement(Box, { marginLeft: 3 },
287
- React.createElement(TextInput, { value: editName, onChange: setEditName, placeholder: "Enter prompt name" }))),
291
+ React.createElement(TextInput, { value: editName, onChange: setEditName, placeholder: t.systemPromptConfig.enterPromptName }))),
288
292
  (!isEditing || editingField !== 'name') && (React.createElement(Box, { marginLeft: 3 },
289
- React.createElement(Text, { color: "gray" }, editName || 'Not set'))))),
293
+ React.createElement(Text, { color: "gray" }, editName || t.systemPromptConfig.notSet))))),
290
294
  React.createElement(Box, { marginBottom: 1 },
291
295
  React.createElement(Box, { flexDirection: "column" },
292
296
  React.createElement(Text, { color: editingField === 'content' ? 'green' : 'white' },
293
297
  editingField === 'content' ? '❯ ' : ' ',
294
- "Content:"),
298
+ t.systemPromptConfig.contentLabel),
295
299
  editingField === 'content' && isEditing && (React.createElement(Box, { marginLeft: 3 },
296
- React.createElement(TextInput, { value: editContent, onChange: setEditContent, placeholder: "Enter prompt content" }))),
300
+ React.createElement(TextInput, { value: editContent, onChange: setEditContent, placeholder: t.systemPromptConfig.enterPromptContent }))),
297
301
  (!isEditing || editingField !== 'content') && (React.createElement(Box, { marginLeft: 3 },
298
302
  React.createElement(Text, { color: "gray" }, editContent
299
303
  ? editContent.substring(0, 100) +
300
304
  (editContent.length > 100 ? '...' : '')
301
- : 'Not set')))))),
305
+ : t.systemPromptConfig.notSet)))))),
302
306
  React.createElement(Box, { marginTop: 1 },
303
- React.createElement(Text, { color: "gray", dimColor: true }, "\u2191\u2193: Navigate fields | Enter: Edit | Ctrl+S: Save | ESC: Cancel"))));
307
+ React.createElement(Text, { color: "gray", dimColor: true }, t.systemPromptConfig.editingHint))));
304
308
  }
305
309
  // Render delete confirmation
306
310
  if (view === 'confirmDelete') {
307
311
  const promptToDelete = config.prompts.length > 0 ? config.prompts[selectedIndex] : null;
308
312
  return (React.createElement(Box, { flexDirection: "column", padding: 1 },
309
- React.createElement(Alert, { variant: "warning" }, "Confirm Delete"),
313
+ React.createElement(Alert, { variant: "warning" }, t.systemPromptConfig.confirmDelete),
310
314
  React.createElement(Box, { marginBottom: 1 },
311
315
  React.createElement(Text, null,
312
- "Are you sure you want to delete \"",
316
+ t.systemPromptConfig.deleteConfirmMessage,
317
+ " \"",
313
318
  React.createElement(Text, { bold: true, color: "yellow" }, promptToDelete?.name),
314
319
  "\"?")),
315
320
  React.createElement(Box, { marginTop: 1 },
316
- React.createElement(Text, { color: "gray", dimColor: true }, "Press Y to confirm, N or ESC to cancel"))));
321
+ React.createElement(Text, { color: "gray", dimColor: true }, t.systemPromptConfig.confirmHint))));
317
322
  }
318
323
  return null;
319
324
  }
@@ -13,68 +13,76 @@ import SensitiveCommandConfigScreen from './SensitiveCommandConfigScreen.js';
13
13
  import CodeBaseConfigScreen from './CodeBaseConfigScreen.js';
14
14
  import SystemPromptConfigScreen from './SystemPromptConfigScreen.js';
15
15
  import CustomHeadersScreen from './CustomHeadersScreen.js';
16
+ import LanguageSettingsScreen from './LanguageSettingsScreen.js';
17
+ import { useI18n } from '../../i18n/index.js';
16
18
  export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
17
- const [infoText, setInfoText] = useState('Start a new chat conversation');
19
+ const { t } = useI18n();
20
+ const [infoText, setInfoText] = useState(t.welcome.startChatInfo);
18
21
  const [inlineView, setInlineView] = useState('menu');
19
22
  const [editingAgentId, setEditingAgentId] = useState();
20
23
  const { columns: terminalWidth } = useTerminalSize();
21
24
  const { stdout } = useStdout();
22
25
  const isInitialMount = useRef(true);
23
- const [remountKey, setRemountKey] = useState(0);
24
26
  const menuOptions = useMemo(() => [
25
27
  {
26
- label: 'Start',
28
+ label: t.welcome.startChat,
27
29
  value: 'chat',
28
- infoText: 'Start a new chat conversation',
30
+ infoText: t.welcome.startChatInfo,
29
31
  clearTerminal: true,
30
32
  },
31
33
  {
32
- label: 'API & Model Settings',
34
+ label: t.welcome.apiSettings,
33
35
  value: 'config',
34
- infoText: 'Configure API settings, AI models, and manage profiles',
36
+ infoText: t.welcome.apiSettingsInfo,
35
37
  },
36
38
  {
37
- label: 'Proxy & Browser Settings',
39
+ label: t.welcome.proxySettings,
38
40
  value: 'proxy',
39
- infoText: 'Configure system proxy and browser for web search and fetch',
41
+ infoText: t.welcome.proxySettingsInfo,
40
42
  },
41
43
  {
42
- label: 'CodeBase Settings',
44
+ label: t.welcome.codebaseSettings,
43
45
  value: 'codebase',
44
- infoText: 'Configure codebase indexing with embedding models',
46
+ infoText: t.welcome.codebaseSettingsInfo,
45
47
  },
46
48
  {
47
- label: 'System Prompt Settings',
49
+ label: t.welcome.systemPromptSettings,
48
50
  value: 'systemprompt',
49
- infoText: 'Configure custom system prompt (overrides default)',
51
+ infoText: t.welcome.systemPromptSettingsInfo,
50
52
  },
51
53
  {
52
- label: 'Custom Headers Settings',
54
+ label: t.welcome.customHeadersSettings,
53
55
  value: 'customheaders',
54
- infoText: 'Configure custom HTTP headers for API requests',
56
+ infoText: t.welcome.customHeadersSettingsInfo,
55
57
  },
56
58
  {
57
- label: 'MCP Settings',
59
+ label: t.welcome.mcpSettings,
58
60
  value: 'mcp',
59
- infoText: 'Configure Model Context Protocol servers',
61
+ infoText: t.welcome.mcpSettingsInfo,
60
62
  },
61
63
  {
62
- label: 'Sub-Agent Settings',
64
+ label: t.welcome.subAgentSettings,
63
65
  value: 'subagent',
64
- infoText: 'Configure sub-agents with custom tool permissions',
66
+ infoText: t.welcome.subAgentSettingsInfo,
65
67
  },
66
68
  {
67
- label: 'Sensitive Commands',
69
+ label: t.welcome.sensitiveCommands,
68
70
  value: 'sensitive-commands',
69
- infoText: 'Configure commands that require confirmation even in YOLO mode',
71
+ infoText: t.welcome.sensitiveCommandsInfo,
72
+ },
73
+ {
74
+ label: t.welcome.languageSettings,
75
+ value: 'language',
76
+ infoText: t.welcome.languageSettingsInfo,
70
77
  },
71
78
  {
72
- label: 'Exit',
79
+ label: t.welcome.exit,
73
80
  value: 'exit',
74
81
  color: 'rgb(232, 131, 136)',
75
- infoText: 'Exit the application',
82
+ infoText: t.welcome.exitInfo,
76
83
  },
77
- ], []);
84
+ ], [t]);
85
+ const [remountKey, setRemountKey] = useState(0);
78
86
  const handleSelectionChange = useCallback((newInfoText) => {
79
87
  setInfoText(newInfoText);
80
88
  }, []);
@@ -101,6 +109,9 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
101
109
  else if (value === 'customheaders') {
102
110
  setInlineView('customheaders');
103
111
  }
112
+ else if (value === 'language') {
113
+ setInlineView('language-settings');
114
+ }
104
115
  else {
105
116
  // Pass through to parent for other actions (chat, exit, etc.)
106
117
  onMenuSelect?.(value);
@@ -143,11 +154,12 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
143
154
  React.createElement(Box, { key: "welcome-header", flexDirection: "row", paddingLeft: 2, paddingTop: 1, paddingBottom: 0, width: terminalWidth },
144
155
  React.createElement(Box, { flexDirection: "column", justifyContent: "center" },
145
156
  React.createElement(Text, { bold: true },
146
- React.createElement(Gradient, { name: "rainbow" }, "\u2746 SNOW AI CLI")),
157
+ React.createElement(Gradient, { name: "rainbow" }, t.welcome.title)),
147
158
  React.createElement(Text, { color: "gray", dimColor: true },
148
159
  "v",
149
160
  version,
150
- " \u2022 Intelligent Command Line Assistant"))),
161
+ " \u2022 ",
162
+ t.welcome.subtitle))),
151
163
  ] }, item => item),
152
164
  onMenuSelect && inlineView === 'menu' && (React.createElement(Box, { paddingX: 1 },
153
165
  React.createElement(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1 },
@@ -171,5 +183,7 @@ export default function WelcomeScreen({ version = '1.0.0', onMenuSelect, }) {
171
183
  inlineView === 'systemprompt' && (React.createElement(Box, { paddingX: 1 },
172
184
  React.createElement(SystemPromptConfigScreen, { onBack: handleBackToMenu }))),
173
185
  inlineView === 'customheaders' && (React.createElement(Box, { paddingX: 1 },
174
- React.createElement(CustomHeadersScreen, { onBack: handleBackToMenu })))));
186
+ React.createElement(CustomHeadersScreen, { onBack: handleBackToMenu }))),
187
+ inlineView === 'language-settings' && (React.createElement(Box, { paddingX: 1 },
188
+ React.createElement(LanguageSettingsScreen, { onBack: handleBackToMenu, inlineMode: true })))));
175
189
  }
@@ -27,6 +27,8 @@ export interface ApiConfig {
27
27
  thinking?: ThinkingConfig;
28
28
  geminiThinking?: GeminiThinkingConfig;
29
29
  responsesReasoning?: ResponsesReasoningConfig;
30
+ enablePromptOptimization?: boolean;
31
+ enableAutoCompress?: boolean;
30
32
  }
31
33
  export interface MCPServer {
32
34
  url?: string;
@@ -1,16 +1,12 @@
1
1
  export interface CodebaseConfig {
2
2
  enabled: boolean;
3
+ enableAgentReview: boolean;
3
4
  embedding: {
4
5
  modelName: string;
5
6
  baseUrl: string;
6
7
  apiKey: string;
7
8
  dimensions: number;
8
9
  };
9
- llm: {
10
- modelName: string;
11
- baseUrl: string;
12
- apiKey: string;
13
- };
14
10
  batch: {
15
11
  maxLines: number;
16
12
  concurrency: number;
@@ -3,17 +3,13 @@ import path from 'path';
3
3
  import os from 'os';
4
4
  const DEFAULT_CONFIG = {
5
5
  enabled: false,
6
+ enableAgentReview: true,
6
7
  embedding: {
7
8
  modelName: '',
8
9
  baseUrl: '',
9
10
  apiKey: '',
10
11
  dimensions: 1536,
11
12
  },
12
- llm: {
13
- modelName: '',
14
- baseUrl: '',
15
- apiKey: '',
16
- },
17
13
  batch: {
18
14
  maxLines: 10,
19
15
  concurrency: 3,
@@ -41,17 +37,13 @@ export const loadCodebaseConfig = () => {
41
37
  // Merge with defaults to ensure all fields exist
42
38
  return {
43
39
  enabled: config.enabled ?? DEFAULT_CONFIG.enabled,
40
+ enableAgentReview: config.enableAgentReview ?? DEFAULT_CONFIG.enableAgentReview,
44
41
  embedding: {
45
42
  modelName: config.embedding?.modelName ?? DEFAULT_CONFIG.embedding.modelName,
46
43
  baseUrl: config.embedding?.baseUrl ?? DEFAULT_CONFIG.embedding.baseUrl,
47
44
  apiKey: config.embedding?.apiKey ?? DEFAULT_CONFIG.embedding.apiKey,
48
45
  dimensions: config.embedding?.dimensions ?? DEFAULT_CONFIG.embedding.dimensions,
49
46
  },
50
- llm: {
51
- modelName: config.llm?.modelName ?? DEFAULT_CONFIG.llm.modelName,
52
- baseUrl: config.llm?.baseUrl ?? DEFAULT_CONFIG.llm.baseUrl,
53
- apiKey: config.llm?.apiKey ?? DEFAULT_CONFIG.llm.apiKey,
54
- },
55
47
  batch: {
56
48
  maxLines: config.batch?.maxLines ?? DEFAULT_CONFIG.batch.maxLines,
57
49
  concurrency: config.batch?.concurrency ?? DEFAULT_CONFIG.batch.concurrency,
@@ -0,0 +1,16 @@
1
+ import { EventEmitter } from 'events';
2
+ export type CodebaseSearchEvent = {
3
+ type: 'search-start' | 'search-retry' | 'search-complete';
4
+ attempt: number;
5
+ maxAttempts: number;
6
+ currentTopN: number;
7
+ message: string;
8
+ query?: string;
9
+ };
10
+ declare class CodebaseSearchEventEmitter extends EventEmitter {
11
+ emitSearchEvent(event: CodebaseSearchEvent): void;
12
+ onSearchEvent(callback: (event: CodebaseSearchEvent) => void): void;
13
+ removeSearchEventListener(callback: (event: CodebaseSearchEvent) => void): void;
14
+ }
15
+ export declare const codebaseSearchEvents: CodebaseSearchEventEmitter;
16
+ export {};
@@ -0,0 +1,13 @@
1
+ import { EventEmitter } from 'events';
2
+ class CodebaseSearchEventEmitter extends EventEmitter {
3
+ emitSearchEvent(event) {
4
+ this.emit('codebase-search', event);
5
+ }
6
+ onSearchEvent(callback) {
7
+ this.on('codebase-search', callback);
8
+ }
9
+ removeSearchEventListener(callback) {
10
+ this.off('codebase-search', callback);
11
+ }
12
+ }
13
+ export const codebaseSearchEvents = new CodebaseSearchEventEmitter();
@@ -5,8 +5,8 @@ registerCommand('agent-', {
5
5
  return {
6
6
  success: true,
7
7
  action: 'showAgentPicker',
8
- message: 'Showing sub-agent selection panel'
8
+ message: 'Showing sub-agent selection panel',
9
9
  };
10
- }
10
+ },
11
11
  });
12
12
  export default {};
@@ -77,7 +77,7 @@ License information (check package.json or LICENSE file)
77
77
  ---
78
78
 
79
79
  **Important instructions:**
80
- - Use filesystem-list to explore directories recursively
80
+ - Use filesystem-read to explore directories (it automatically lists contents when path is a directory)
81
81
  - Use filesystem-read to read important files
82
82
  - Use terminal-execute to run commands like 'npm run' to discover available scripts
83
83
  - Be thorough but concise - focus on essential information