snow-ai 0.4.12 ā 0.4.14
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 +74 -43
- package/dist/ui/pages/ChatScreen.d.ts +0 -15
- package/dist/ui/pages/ChatScreen.js +25 -16
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,26 +2,45 @@
|
|
|
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 {
|
|
21
|
-
const { stdout } = await execAsync('npm view snow-ai version', {
|
|
39
|
+
const { stdout } = await execAsync('npm view snow-ai version --registry https://registry.npmjs.org', {
|
|
22
40
|
encoding: 'utf8',
|
|
23
41
|
});
|
|
24
42
|
const latestVersion = stdout.trim();
|
|
43
|
+
// Simple string comparison - force registry fetch ensures no cache issues
|
|
25
44
|
if (latestVersion && latestVersion !== currentVersion) {
|
|
26
45
|
console.log('\nš Update available!');
|
|
27
46
|
console.log(` Current version: ${currentVersion}`);
|
|
@@ -78,39 +97,46 @@ if (cli.flags.update) {
|
|
|
78
97
|
process.exit(1);
|
|
79
98
|
}
|
|
80
99
|
}
|
|
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
|
-
}
|
|
100
|
+
// Dev mode and resource monitoring will be initialized in Startup component
|
|
101
101
|
// Startup component that shows loading spinner during update check
|
|
102
|
-
const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
|
|
102
|
+
const Startup = ({ version, skipWelcome, headlessPrompt, isDevMode, }) => {
|
|
103
103
|
const [appReady, setAppReady] = React.useState(false);
|
|
104
|
+
const [AppComponent, setAppComponent] = React.useState(null);
|
|
104
105
|
React.useEffect(() => {
|
|
105
106
|
let mounted = true;
|
|
106
107
|
const init = async () => {
|
|
107
|
-
//
|
|
108
|
+
// Load all dependencies in parallel
|
|
109
|
+
const deps = await loadDependencies();
|
|
110
|
+
// Setup execAsync for checkForUpdates
|
|
111
|
+
execAsync = deps.promisify(deps.exec);
|
|
112
|
+
// Initialize profiles system
|
|
108
113
|
try {
|
|
109
|
-
initializeProfiles();
|
|
114
|
+
deps.initializeProfiles();
|
|
110
115
|
}
|
|
111
116
|
catch (error) {
|
|
112
117
|
console.error('Failed to initialize profiles:', error);
|
|
113
118
|
}
|
|
119
|
+
// Handle dev mode
|
|
120
|
+
if (isDevMode) {
|
|
121
|
+
deps.enableDevMode();
|
|
122
|
+
const userId = deps.getDevUserId();
|
|
123
|
+
console.log('š§ Developer mode enabled');
|
|
124
|
+
console.log(`š Using persistent userId: ${userId}`);
|
|
125
|
+
console.log(`š Stored in: ~/.snow/dev-user-id\n`);
|
|
126
|
+
}
|
|
127
|
+
// Start resource monitoring in development/debug mode
|
|
128
|
+
if (process.env['NODE_ENV'] === 'development' || process.env['DEBUG']) {
|
|
129
|
+
deps.resourceMonitor.startMonitoring(30000);
|
|
130
|
+
setInterval(() => {
|
|
131
|
+
const { hasLeak, reasons } = deps.resourceMonitor.checkForLeaks();
|
|
132
|
+
if (hasLeak) {
|
|
133
|
+
console.error('ā ļø Potential memory leak detected:');
|
|
134
|
+
reasons.forEach((reason) => console.error(` - ${reason}`));
|
|
135
|
+
}
|
|
136
|
+
}, 5 * 60 * 1000);
|
|
137
|
+
}
|
|
138
|
+
// Store for cleanup
|
|
139
|
+
global.__deps = deps;
|
|
114
140
|
// Check for updates with timeout
|
|
115
141
|
const updateCheckPromise = version
|
|
116
142
|
? checkForUpdates(version)
|
|
@@ -121,6 +147,7 @@ const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
|
|
|
121
147
|
new Promise(resolve => setTimeout(resolve, 3000)),
|
|
122
148
|
]);
|
|
123
149
|
if (mounted) {
|
|
150
|
+
setAppComponent(() => deps.App);
|
|
124
151
|
setAppReady(true);
|
|
125
152
|
}
|
|
126
153
|
};
|
|
@@ -128,15 +155,15 @@ const Startup = ({ version, skipWelcome, headlessPrompt, }) => {
|
|
|
128
155
|
return () => {
|
|
129
156
|
mounted = false;
|
|
130
157
|
};
|
|
131
|
-
}, [version]);
|
|
132
|
-
if (!appReady) {
|
|
158
|
+
}, [version, isDevMode]);
|
|
159
|
+
if (!appReady || !AppComponent) {
|
|
133
160
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
134
161
|
React.createElement(Box, null,
|
|
135
162
|
React.createElement(Text, { color: "cyan" },
|
|
136
163
|
React.createElement(Spinner, { type: "dots" })),
|
|
137
164
|
React.createElement(Text, null, " Loading..."))));
|
|
138
165
|
}
|
|
139
|
-
return (React.createElement(
|
|
166
|
+
return (React.createElement(AppComponent, { version: version, skipWelcome: skipWelcome, headlessPrompt: headlessPrompt }));
|
|
140
167
|
};
|
|
141
168
|
// Disable bracketed paste mode on startup
|
|
142
169
|
process.stdout.write('\x1b[?2004l');
|
|
@@ -146,12 +173,16 @@ process.stdout.write('\x1b[?25h'); // Show cursor
|
|
|
146
173
|
// Re-enable on exit to avoid polluting parent shell
|
|
147
174
|
const cleanup = () => {
|
|
148
175
|
process.stdout.write('\x1b[?2004l');
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
176
|
+
// Cleanup loaded dependencies if available
|
|
177
|
+
const deps = global.__deps;
|
|
178
|
+
if (deps) {
|
|
179
|
+
// Kill all child processes first
|
|
180
|
+
deps.processManager.killAll();
|
|
181
|
+
// Stop resource monitoring
|
|
182
|
+
deps.resourceMonitor.stopMonitoring();
|
|
183
|
+
// Disconnect VSCode connection before exit
|
|
184
|
+
deps.vscodeConnection.stop();
|
|
185
|
+
}
|
|
155
186
|
};
|
|
156
187
|
process.on('exit', cleanup);
|
|
157
188
|
process.on('SIGINT', () => {
|
|
@@ -162,7 +193,7 @@ process.on('SIGTERM', () => {
|
|
|
162
193
|
cleanup();
|
|
163
194
|
process.exit(0);
|
|
164
195
|
});
|
|
165
|
-
render(React.createElement(Startup, { version: cli.pkg.version, skipWelcome: cli.flags.c, headlessPrompt: cli.flags.ask }), {
|
|
196
|
+
render(React.createElement(Startup, { version: cli.pkg.version, skipWelcome: cli.flags.c, headlessPrompt: cli.flags.ask, isDevMode: cli.flags.dev }), {
|
|
166
197
|
exitOnCtrlC: false,
|
|
167
198
|
patchConsole: true,
|
|
168
199
|
});
|
|
@@ -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);
|