snow-ai 0.4.11 → 0.4.13
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/cli.js +72 -42
- package/dist/i18n/lang/en.js +0 -3
- package/dist/i18n/lang/es.js +0 -3
- package/dist/i18n/lang/ja.js +0 -3
- package/dist/i18n/lang/ko.js +0 -3
- package/dist/i18n/lang/zh-TW.js +0 -3
- package/dist/i18n/lang/zh.js +0 -3
- package/dist/i18n/types.d.ts +0 -3
- package/dist/ui/pages/ChatScreen.d.ts +0 -15
- package/dist/ui/pages/ChatScreen.js +25 -16
- package/dist/ui/pages/ConfigScreen.js +8 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,19 +2,37 @@
|
|
|
2
2
|
// Show loading indicator immediately before any imports
|
|
3
3
|
process.stdout.write('\x1b[?25l'); // Hide cursor
|
|
4
4
|
process.stdout.write('⠋ Loading...\r');
|
|
5
|
+
// Import only critical dependencies synchronously
|
|
5
6
|
import React from 'react';
|
|
6
7
|
import { render, Text, Box } from 'ink';
|
|
7
8
|
import Spinner from 'ink-spinner';
|
|
8
9
|
import meow from 'meow';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
// Load heavy dependencies asynchronously
|
|
12
|
+
async function loadDependencies() {
|
|
13
|
+
const [appModule, vscodeModule, resourceModule, configModule, processModule, devModeModule, childProcessModule, utilModule,] = await Promise.all([
|
|
14
|
+
import('./app.js'),
|
|
15
|
+
import('./utils/vscodeConnection.js'),
|
|
16
|
+
import('./utils/resourceMonitor.js'),
|
|
17
|
+
import('./utils/configManager.js'),
|
|
18
|
+
import('./utils/processManager.js'),
|
|
19
|
+
import('./utils/devMode.js'),
|
|
20
|
+
import('child_process'),
|
|
21
|
+
import('util'),
|
|
22
|
+
]);
|
|
23
|
+
return {
|
|
24
|
+
App: appModule.default,
|
|
25
|
+
vscodeConnection: vscodeModule.vscodeConnection,
|
|
26
|
+
resourceMonitor: resourceModule.resourceMonitor,
|
|
27
|
+
initializeProfiles: configModule.initializeProfiles,
|
|
28
|
+
processManager: processModule.processManager,
|
|
29
|
+
enableDevMode: devModeModule.enableDevMode,
|
|
30
|
+
getDevUserId: devModeModule.getDevUserId,
|
|
31
|
+
exec: childProcessModule.exec,
|
|
32
|
+
promisify: utilModule.promisify,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
let execAsync;
|
|
18
36
|
// Check for updates asynchronously
|
|
19
37
|
async function checkForUpdates(currentVersion) {
|
|
20
38
|
try {
|
|
@@ -78,39 +96,46 @@ if (cli.flags.update) {
|
|
|
78
96
|
process.exit(1);
|
|
79
97
|
}
|
|
80
98
|
}
|
|
81
|
-
//
|
|
82
|
-
if (cli.flags.dev) {
|
|
83
|
-
enableDevMode();
|
|
84
|
-
const userId = getDevUserId();
|
|
85
|
-
console.log('🔧 Developer mode enabled');
|
|
86
|
-
console.log(`📝 Using persistent userId: ${userId}`);
|
|
87
|
-
console.log(`📂 Stored in: ~/.snow/dev-user-id\n`);
|
|
88
|
-
}
|
|
89
|
-
// Start resource monitoring in development/debug mode
|
|
90
|
-
if (process.env['NODE_ENV'] === 'development' || process.env['DEBUG']) {
|
|
91
|
-
resourceMonitor.startMonitoring(30000); // Monitor every 30 seconds
|
|
92
|
-
// Check for leaks every 5 minutes
|
|
93
|
-
setInterval(() => {
|
|
94
|
-
const { hasLeak, reasons } = resourceMonitor.checkForLeaks();
|
|
95
|
-
if (hasLeak) {
|
|
96
|
-
console.error('⚠️ Potential memory leak detected:');
|
|
97
|
-
reasons.forEach(reason => console.error(` - ${reason}`));
|
|
98
|
-
}
|
|
99
|
-
}, 5 * 60 * 1000);
|
|
100
|
-
}
|
|
99
|
+
// Dev mode and resource monitoring will be initialized in Startup component
|
|
101
100
|
// Startup component that shows loading spinner during update check
|
|
102
|
-
const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
|
|
101
|
+
const Startup = ({ version, skipWelcome, headlessPrompt, isDevMode, }) => {
|
|
103
102
|
const [appReady, setAppReady] = React.useState(false);
|
|
103
|
+
const [AppComponent, setAppComponent] = React.useState(null);
|
|
104
104
|
React.useEffect(() => {
|
|
105
105
|
let mounted = true;
|
|
106
106
|
const init = async () => {
|
|
107
|
-
//
|
|
107
|
+
// Load all dependencies in parallel
|
|
108
|
+
const deps = await loadDependencies();
|
|
109
|
+
// Setup execAsync for checkForUpdates
|
|
110
|
+
execAsync = deps.promisify(deps.exec);
|
|
111
|
+
// Initialize profiles system
|
|
108
112
|
try {
|
|
109
|
-
initializeProfiles();
|
|
113
|
+
deps.initializeProfiles();
|
|
110
114
|
}
|
|
111
115
|
catch (error) {
|
|
112
116
|
console.error('Failed to initialize profiles:', error);
|
|
113
117
|
}
|
|
118
|
+
// Handle dev mode
|
|
119
|
+
if (isDevMode) {
|
|
120
|
+
deps.enableDevMode();
|
|
121
|
+
const userId = deps.getDevUserId();
|
|
122
|
+
console.log('🔧 Developer mode enabled');
|
|
123
|
+
console.log(`📝 Using persistent userId: ${userId}`);
|
|
124
|
+
console.log(`📂 Stored in: ~/.snow/dev-user-id\n`);
|
|
125
|
+
}
|
|
126
|
+
// Start resource monitoring in development/debug mode
|
|
127
|
+
if (process.env['NODE_ENV'] === 'development' || process.env['DEBUG']) {
|
|
128
|
+
deps.resourceMonitor.startMonitoring(30000);
|
|
129
|
+
setInterval(() => {
|
|
130
|
+
const { hasLeak, reasons } = deps.resourceMonitor.checkForLeaks();
|
|
131
|
+
if (hasLeak) {
|
|
132
|
+
console.error('⚠️ Potential memory leak detected:');
|
|
133
|
+
reasons.forEach((reason) => console.error(` - ${reason}`));
|
|
134
|
+
}
|
|
135
|
+
}, 5 * 60 * 1000);
|
|
136
|
+
}
|
|
137
|
+
// Store for cleanup
|
|
138
|
+
global.__deps = deps;
|
|
114
139
|
// Check for updates with timeout
|
|
115
140
|
const updateCheckPromise = version
|
|
116
141
|
? checkForUpdates(version)
|
|
@@ -121,6 +146,7 @@ const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
|
|
|
121
146
|
new Promise(resolve => setTimeout(resolve, 3000)),
|
|
122
147
|
]);
|
|
123
148
|
if (mounted) {
|
|
149
|
+
setAppComponent(() => deps.App);
|
|
124
150
|
setAppReady(true);
|
|
125
151
|
}
|
|
126
152
|
};
|
|
@@ -128,15 +154,15 @@ const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
|
|
|
128
154
|
return () => {
|
|
129
155
|
mounted = false;
|
|
130
156
|
};
|
|
131
|
-
}, [version]);
|
|
132
|
-
if (!appReady) {
|
|
157
|
+
}, [version, isDevMode]);
|
|
158
|
+
if (!appReady || !AppComponent) {
|
|
133
159
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
134
160
|
React.createElement(Box, null,
|
|
135
161
|
React.createElement(Text, { color: "cyan" },
|
|
136
162
|
React.createElement(Spinner, { type: "dots" })),
|
|
137
163
|
React.createElement(Text, null, " Loading..."))));
|
|
138
164
|
}
|
|
139
|
-
return (React.createElement(
|
|
165
|
+
return (React.createElement(AppComponent, { version: version, skipWelcome: skipWelcome, headlessPrompt: headlessPrompt }));
|
|
140
166
|
};
|
|
141
167
|
// Disable bracketed paste mode on startup
|
|
142
168
|
process.stdout.write('\x1b[?2004l');
|
|
@@ -146,12 +172,16 @@ process.stdout.write('\x1b[?25h'); // Show cursor
|
|
|
146
172
|
// Re-enable on exit to avoid polluting parent shell
|
|
147
173
|
const cleanup = () => {
|
|
148
174
|
process.stdout.write('\x1b[?2004l');
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
175
|
+
// Cleanup loaded dependencies if available
|
|
176
|
+
const deps = global.__deps;
|
|
177
|
+
if (deps) {
|
|
178
|
+
// Kill all child processes first
|
|
179
|
+
deps.processManager.killAll();
|
|
180
|
+
// Stop resource monitoring
|
|
181
|
+
deps.resourceMonitor.stopMonitoring();
|
|
182
|
+
// Disconnect VSCode connection before exit
|
|
183
|
+
deps.vscodeConnection.stop();
|
|
184
|
+
}
|
|
155
185
|
};
|
|
156
186
|
process.on('exit', cleanup);
|
|
157
187
|
process.on('SIGINT', () => {
|
|
@@ -162,7 +192,7 @@ process.on('SIGTERM', () => {
|
|
|
162
192
|
cleanup();
|
|
163
193
|
process.exit(0);
|
|
164
194
|
});
|
|
165
|
-
render(React.createElement(Startup, { version: cli.pkg.version, skipWelcome: cli.flags.c, headlessPrompt: cli.flags.ask }), {
|
|
195
|
+
render(React.createElement(Startup, { version: cli.pkg.version, skipWelcome: cli.flags.c, headlessPrompt: cli.flags.ask, isDevMode: cli.flags.dev }), {
|
|
166
196
|
exitOnCtrlC: false,
|
|
167
197
|
patchConsole: true,
|
|
168
198
|
});
|
package/dist/i18n/lang/en.js
CHANGED
|
@@ -139,9 +139,6 @@ export const en = {
|
|
|
139
139
|
disabled: '[ ] Disabled',
|
|
140
140
|
toggleHint: '(Press Enter to toggle)',
|
|
141
141
|
enterValue: 'Enter value:',
|
|
142
|
-
low: 'Low',
|
|
143
|
-
medium: 'Medium',
|
|
144
|
-
high: 'High',
|
|
145
142
|
createNewProfile: 'Create New Profile',
|
|
146
143
|
enterProfileName: 'Enter a name for the new configuration profile',
|
|
147
144
|
profileNamePlaceholder: 'e.g., work, personal, test',
|
package/dist/i18n/lang/es.js
CHANGED
|
@@ -139,9 +139,6 @@ export const es = {
|
|
|
139
139
|
disabled: '[ ] Deshabilitado',
|
|
140
140
|
toggleHint: '(Presiona Enter para alternar)',
|
|
141
141
|
enterValue: 'Ingresa valor:',
|
|
142
|
-
low: 'Bajo',
|
|
143
|
-
medium: 'Medio',
|
|
144
|
-
high: 'Alto',
|
|
145
142
|
createNewProfile: 'Crear Nuevo Perfil',
|
|
146
143
|
enterProfileName: 'Ingresa el nombre del nuevo perfil',
|
|
147
144
|
profileNamePlaceholder: 'Ej: work, personal, test',
|
package/dist/i18n/lang/ja.js
CHANGED
|
@@ -139,9 +139,6 @@ export const ja = {
|
|
|
139
139
|
disabled: '[ ] 無効',
|
|
140
140
|
toggleHint: '(Enterキーで切り替え)',
|
|
141
141
|
enterValue: '値を入力:',
|
|
142
|
-
low: '低',
|
|
143
|
-
medium: '中',
|
|
144
|
-
high: '高',
|
|
145
142
|
createNewProfile: '新しいプロファイルを作成',
|
|
146
143
|
enterProfileName: '新しいプロファイルの名前を入力',
|
|
147
144
|
profileNamePlaceholder: '例: work, personal, test',
|
package/dist/i18n/lang/ko.js
CHANGED
|
@@ -139,9 +139,6 @@ export const ko = {
|
|
|
139
139
|
disabled: '[ ] 비활성화됨',
|
|
140
140
|
toggleHint: '(Enter 키로 토글)',
|
|
141
141
|
enterValue: '값 입력:',
|
|
142
|
-
low: '낮음',
|
|
143
|
-
medium: '중간',
|
|
144
|
-
high: '높음',
|
|
145
142
|
createNewProfile: '새 프로필 생성',
|
|
146
143
|
enterProfileName: '새 프로필 이름 입력',
|
|
147
144
|
profileNamePlaceholder: '예: work, personal, test',
|
package/dist/i18n/lang/zh-TW.js
CHANGED
|
@@ -139,9 +139,6 @@ export const zhTW = {
|
|
|
139
139
|
disabled: '[ ] 已停用',
|
|
140
140
|
toggleHint: '(按 Enter 切換)',
|
|
141
141
|
enterValue: '輸入值:',
|
|
142
|
-
low: '低',
|
|
143
|
-
medium: '中',
|
|
144
|
-
high: '高',
|
|
145
142
|
createNewProfile: '建立新配置',
|
|
146
143
|
enterProfileName: '輸入新配置的名稱',
|
|
147
144
|
profileNamePlaceholder: '例如: work, personal, test',
|
package/dist/i18n/lang/zh.js
CHANGED
|
@@ -139,9 +139,6 @@ export const zh = {
|
|
|
139
139
|
disabled: '[ ] 已禁用',
|
|
140
140
|
toggleHint: '(按 Enter 切换)',
|
|
141
141
|
enterValue: '输入值:',
|
|
142
|
-
low: '低',
|
|
143
|
-
medium: '中',
|
|
144
|
-
high: '高',
|
|
145
142
|
createNewProfile: '创建新配置',
|
|
146
143
|
enterProfileName: '输入新配置的名称',
|
|
147
144
|
profileNamePlaceholder: '例如: work, personal, test',
|
package/dist/i18n/types.d.ts
CHANGED
|
@@ -140,9 +140,6 @@ export type TranslationKeys = {
|
|
|
140
140
|
disabled: string;
|
|
141
141
|
toggleHint: string;
|
|
142
142
|
enterValue: string;
|
|
143
|
-
low: string;
|
|
144
|
-
medium: string;
|
|
145
|
-
high: string;
|
|
146
143
|
createNewProfile: string;
|
|
147
144
|
enterProfileName: string;
|
|
148
145
|
profileNamePlaceholder: string;
|
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import '../../utils/commands/clear.js';
|
|
3
|
-
import '../../utils/commands/resume.js';
|
|
4
|
-
import '../../utils/commands/mcp.js';
|
|
5
|
-
import '../../utils/commands/yolo.js';
|
|
6
|
-
import '../../utils/commands/init.js';
|
|
7
|
-
import '../../utils/commands/ide.js';
|
|
8
|
-
import '../../utils/commands/compact.js';
|
|
9
|
-
import '../../utils/commands/home.js';
|
|
10
|
-
import '../../utils/commands/review.js';
|
|
11
|
-
import '../../utils/commands/role.js';
|
|
12
|
-
import '../../utils/commands/usage.js';
|
|
13
|
-
import '../../utils/commands/export.js';
|
|
14
|
-
import '../../utils/commands/agent.js';
|
|
15
|
-
import '../../utils/commands/todoPicker.js';
|
|
16
|
-
import '../../utils/commands/help.js';
|
|
17
2
|
type Props = {
|
|
18
3
|
skipWelcome?: boolean;
|
|
19
4
|
};
|
|
@@ -39,22 +39,6 @@ import { CodebaseIndexAgent } from '../../agents/codebaseIndexAgent.js';
|
|
|
39
39
|
import { loadCodebaseConfig } from '../../utils/codebaseConfig.js';
|
|
40
40
|
import { codebaseSearchEvents } from '../../utils/codebaseSearchEvents.js';
|
|
41
41
|
import { logger } from '../../utils/logger.js';
|
|
42
|
-
// Import commands to register them
|
|
43
|
-
import '../../utils/commands/clear.js';
|
|
44
|
-
import '../../utils/commands/resume.js';
|
|
45
|
-
import '../../utils/commands/mcp.js';
|
|
46
|
-
import '../../utils/commands/yolo.js';
|
|
47
|
-
import '../../utils/commands/init.js';
|
|
48
|
-
import '../../utils/commands/ide.js';
|
|
49
|
-
import '../../utils/commands/compact.js';
|
|
50
|
-
import '../../utils/commands/home.js';
|
|
51
|
-
import '../../utils/commands/review.js';
|
|
52
|
-
import '../../utils/commands/role.js';
|
|
53
|
-
import '../../utils/commands/usage.js';
|
|
54
|
-
import '../../utils/commands/export.js';
|
|
55
|
-
import '../../utils/commands/agent.js';
|
|
56
|
-
import '../../utils/commands/todoPicker.js';
|
|
57
|
-
import '../../utils/commands/help.js';
|
|
58
42
|
export default function ChatScreen({ skipWelcome }) {
|
|
59
43
|
const { t } = useI18n();
|
|
60
44
|
const { theme } = useTheme();
|
|
@@ -110,6 +94,29 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
110
94
|
useEffect(() => {
|
|
111
95
|
pendingMessagesRef.current = pendingMessages;
|
|
112
96
|
}, [pendingMessages]);
|
|
97
|
+
// Load commands dynamically to avoid blocking initial render
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
// Use Promise.all to load all commands in parallel
|
|
100
|
+
Promise.all([
|
|
101
|
+
import('../../utils/commands/clear.js'),
|
|
102
|
+
import('../../utils/commands/resume.js'),
|
|
103
|
+
import('../../utils/commands/mcp.js'),
|
|
104
|
+
import('../../utils/commands/yolo.js'),
|
|
105
|
+
import('../../utils/commands/init.js'),
|
|
106
|
+
import('../../utils/commands/ide.js'),
|
|
107
|
+
import('../../utils/commands/compact.js'),
|
|
108
|
+
import('../../utils/commands/home.js'),
|
|
109
|
+
import('../../utils/commands/review.js'),
|
|
110
|
+
import('../../utils/commands/role.js'),
|
|
111
|
+
import('../../utils/commands/usage.js'),
|
|
112
|
+
import('../../utils/commands/export.js'),
|
|
113
|
+
import('../../utils/commands/agent.js'),
|
|
114
|
+
import('../../utils/commands/todoPicker.js'),
|
|
115
|
+
import('../../utils/commands/help.js'),
|
|
116
|
+
]).catch(error => {
|
|
117
|
+
console.error('Failed to load commands:', error);
|
|
118
|
+
});
|
|
119
|
+
}, []);
|
|
113
120
|
// Auto-start codebase indexing on mount if enabled
|
|
114
121
|
useEffect(() => {
|
|
115
122
|
const startCodebaseIndexing = async () => {
|
|
@@ -147,6 +154,7 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
147
154
|
}
|
|
148
155
|
});
|
|
149
156
|
setWatcherEnabled(true);
|
|
157
|
+
setCodebaseIndexing(false); // Ensure loading UI is hidden
|
|
150
158
|
return;
|
|
151
159
|
}
|
|
152
160
|
// If watcher was enabled before but indexing not completed, restore it
|
|
@@ -174,6 +182,7 @@ export default function ChatScreen({ skipWelcome }) {
|
|
|
174
182
|
}
|
|
175
183
|
});
|
|
176
184
|
setWatcherEnabled(true);
|
|
185
|
+
setCodebaseIndexing(false); // Ensure loading UI is hidden when restoring watcher
|
|
177
186
|
}
|
|
178
187
|
// Start or resume indexing in background
|
|
179
188
|
setCodebaseIndexing(true);
|
|
@@ -555,9 +555,10 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
555
555
|
React.createElement(Text, { color: theme.colors.menuSecondary }, responsesReasoningEffort.toUpperCase()))),
|
|
556
556
|
isCurrentlyEditing && (React.createElement(Box, { marginLeft: 3 },
|
|
557
557
|
React.createElement(Select, { options: [
|
|
558
|
-
{ label:
|
|
559
|
-
{ label:
|
|
560
|
-
{ label:
|
|
558
|
+
{ label: 'LOW', value: 'low' },
|
|
559
|
+
{ label: 'MEDIUM', value: 'medium' },
|
|
560
|
+
{ label: 'HIGH', value: 'high' },
|
|
561
|
+
{ label: 'XHIGH', value: 'xhigh' },
|
|
561
562
|
], defaultValue: responsesReasoningEffort, onChange: value => {
|
|
562
563
|
setResponsesReasoningEffort(value);
|
|
563
564
|
setIsEditing(false);
|
|
@@ -1046,9 +1047,10 @@ export default function ConfigScreen({ onBack, onSave, inlineMode = false, }) {
|
|
|
1046
1047
|
searchTerm),
|
|
1047
1048
|
React.createElement(Select, { options: getCurrentOptions(), defaultValue: getCurrentValue(), onChange: handleModelChange }))),
|
|
1048
1049
|
currentField === 'responsesReasoningEffort' && (React.createElement(Select, { options: [
|
|
1049
|
-
{ label:
|
|
1050
|
-
{ label:
|
|
1051
|
-
{ label:
|
|
1050
|
+
{ label: 'LOW', value: 'low' },
|
|
1051
|
+
{ label: 'MEDIUM', value: 'medium' },
|
|
1052
|
+
{ label: 'HIGH', value: 'high' },
|
|
1053
|
+
{ label: 'XHIGH', value: 'xhigh' },
|
|
1052
1054
|
], defaultValue: responsesReasoningEffort, onChange: value => {
|
|
1053
1055
|
setResponsesReasoningEffort(value);
|
|
1054
1056
|
setIsEditing(false);
|