snow-ai 0.4.12 → 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 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 { exec, execSync } from 'child_process';
10
- import { promisify } from 'util';
11
- import App from './app.js';
12
- import { vscodeConnection } from './utils/vscodeConnection.js';
13
- import { resourceMonitor } from './utils/resourceMonitor.js';
14
- import { initializeProfiles } from './utils/configManager.js';
15
- import { processManager } from './utils/processManager.js';
16
- import { enableDevMode, getDevUserId } from './utils/devMode.js';
17
- const execAsync = promisify(exec);
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
- // Handle dev mode flag
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
- // Initialize profiles system first
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(App, { version: version, skipWelcome: skipWelcome, headlessPrompt: headlessPrompt }));
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
- // Kill all child processes first
150
- processManager.killAll();
151
- // Stop resource monitoring
152
- resourceMonitor.stopMonitoring();
153
- // Disconnect VSCode connection before exit
154
- vscodeConnection.stop();
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
  });
@@ -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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.4.12",
3
+ "version": "0.4.13",
4
4
  "description": "Intelligent Command Line Assistant powered by AI",
5
5
  "license": "MIT",
6
6
  "bin": {