snow-ai 0.2.20 → 0.2.22
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/hooks/useVSCodeState.js +5 -5
- package/dist/ui/components/FileList.js +1 -1
- package/dist/ui/pages/ChatScreen.js +4 -4
- package/dist/utils/commands/ide.js +9 -21
- package/dist/utils/vscodeConnection.d.ts +32 -4
- package/dist/utils/vscodeConnection.js +201 -47
- package/package.json +1 -1
- package/readme.md +7 -1
|
@@ -34,18 +34,18 @@ export function useVSCodeState() {
|
|
|
34
34
|
if (vscodeConnectionStatus !== 'connecting') {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
// Set timeout for connecting state (30 seconds to allow for
|
|
37
|
+
// Set timeout for connecting state (30 seconds to allow for IDE plugin reconnection)
|
|
38
38
|
const connectingTimeout = setTimeout(() => {
|
|
39
39
|
const isConnected = vscodeConnection.isConnected();
|
|
40
|
-
const
|
|
40
|
+
const isClientRunning = vscodeConnection.isClientRunning();
|
|
41
41
|
// Only set error if still not connected after timeout
|
|
42
42
|
if (!isConnected) {
|
|
43
|
-
if (
|
|
44
|
-
//
|
|
43
|
+
if (isClientRunning) {
|
|
44
|
+
// Client is running but no connection - show error with helpful message
|
|
45
45
|
setVscodeConnectionStatus('error');
|
|
46
46
|
}
|
|
47
47
|
else {
|
|
48
|
-
//
|
|
48
|
+
// Client not running - go back to disconnected
|
|
49
49
|
setVscodeConnectionStatus('disconnected');
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -177,7 +177,7 @@ const FileList = memo(forwardRef(({ query, selectedIndex, visible, maxItems = 10
|
|
|
177
177
|
return (React.createElement(Box, { paddingX: 1, marginTop: 1, flexDirection: "column" },
|
|
178
178
|
React.createElement(Box, { marginBottom: 1 },
|
|
179
179
|
React.createElement(Text, { color: "blue", bold: true },
|
|
180
|
-
"\
|
|
180
|
+
"\u2261 Files",
|
|
181
181
|
' ',
|
|
182
182
|
allFilteredFiles.length > effectiveMaxItems &&
|
|
183
183
|
`(${selectedIndex + 1}/${allFilteredFiles.length})`)),
|
|
@@ -691,12 +691,12 @@ export default function ChatScreen({}) {
|
|
|
691
691
|
"\u25CF",
|
|
692
692
|
' ',
|
|
693
693
|
vscodeState.vscodeConnectionStatus === 'connecting'
|
|
694
|
-
? '
|
|
694
|
+
? 'Connecting to IDE...'
|
|
695
695
|
: vscodeState.vscodeConnectionStatus === 'connected'
|
|
696
|
-
? '
|
|
696
|
+
? 'IDE Connected'
|
|
697
697
|
: vscodeState.vscodeConnectionStatus === 'error'
|
|
698
|
-
? 'Connection Failed - Make sure Snow CLI
|
|
699
|
-
: '
|
|
698
|
+
? 'Connection Failed - Make sure Snow CLI plugin is installed and active in your IDE'
|
|
699
|
+
: 'IDE',
|
|
700
700
|
vscodeState.vscodeConnectionStatus === 'connected' &&
|
|
701
701
|
vscodeState.editorContext.activeFile &&
|
|
702
702
|
` | ${vscodeState.editorContext.activeFile}`,
|
|
@@ -3,42 +3,30 @@ import { vscodeConnection } from '../vscodeConnection.js';
|
|
|
3
3
|
// IDE connection command handler
|
|
4
4
|
registerCommand('ide', {
|
|
5
5
|
execute: async () => {
|
|
6
|
-
// Check if
|
|
7
|
-
if (vscodeConnection.
|
|
8
|
-
const isConnected = vscodeConnection.isConnected();
|
|
6
|
+
// Check if already connected to IDE plugin
|
|
7
|
+
if (vscodeConnection.isConnected()) {
|
|
9
8
|
return {
|
|
10
9
|
success: true,
|
|
11
10
|
action: 'info',
|
|
12
|
-
alreadyConnected:
|
|
13
|
-
message:
|
|
14
|
-
? `Connected to VSCode (server running on port ${vscodeConnection.getPort()})`
|
|
15
|
-
: `VSCode connection server is running on port ${vscodeConnection.getPort()}\nWaiting for VSCode extension to connect...`
|
|
11
|
+
alreadyConnected: true,
|
|
12
|
+
message: `Already connected to IDE (port ${vscodeConnection.getPort()})`
|
|
16
13
|
};
|
|
17
14
|
}
|
|
18
|
-
//
|
|
15
|
+
// Try to connect to IDE plugin server
|
|
19
16
|
try {
|
|
20
17
|
await vscodeConnection.start();
|
|
21
18
|
return {
|
|
22
19
|
success: true,
|
|
23
20
|
action: 'info',
|
|
24
|
-
message: `
|
|
21
|
+
message: `Connected to IDE on port ${vscodeConnection.getPort()}\nMake sure your IDE plugin (VSCode/JetBrains) is active and running.`
|
|
25
22
|
};
|
|
26
23
|
}
|
|
27
24
|
catch (error) {
|
|
28
|
-
// Handle EADDRINUSE error specifically
|
|
29
|
-
if (error instanceof Error && 'code' in error && error.code === 'EADDRINUSE') {
|
|
30
|
-
// Port is in use by another Snow CLI process - this is OK!
|
|
31
|
-
// Return success and indicate already connected
|
|
32
|
-
return {
|
|
33
|
-
success: true,
|
|
34
|
-
action: 'info',
|
|
35
|
-
alreadyConnected: true, // Treat as already connected since another terminal has the connection
|
|
36
|
-
message: `VSCode connection is already active in another Snow CLI terminal.\nNo additional connection needed - context will be shared through VSCode extension.`
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
25
|
return {
|
|
40
26
|
success: false,
|
|
41
|
-
message: error instanceof Error
|
|
27
|
+
message: error instanceof Error
|
|
28
|
+
? `Failed to connect to IDE: ${error.message}\nMake sure your IDE plugin is installed and active.`
|
|
29
|
+
: 'Failed to connect to IDE. Make sure your IDE plugin is installed and active.'
|
|
42
30
|
};
|
|
43
31
|
}
|
|
44
32
|
}
|
|
@@ -16,26 +16,54 @@ interface Diagnostic {
|
|
|
16
16
|
code?: string | number;
|
|
17
17
|
}
|
|
18
18
|
declare class VSCodeConnectionManager {
|
|
19
|
-
private
|
|
20
|
-
private
|
|
19
|
+
private client;
|
|
20
|
+
private reconnectTimer;
|
|
21
|
+
private reconnectAttempts;
|
|
22
|
+
private readonly MAX_RECONNECT_ATTEMPTS;
|
|
23
|
+
private readonly BASE_RECONNECT_DELAY;
|
|
24
|
+
private readonly MAX_RECONNECT_DELAY;
|
|
25
|
+
private readonly VSCODE_BASE_PORT;
|
|
26
|
+
private readonly VSCODE_MAX_PORT;
|
|
27
|
+
private readonly JETBRAINS_BASE_PORT;
|
|
28
|
+
private readonly JETBRAINS_MAX_PORT;
|
|
21
29
|
private port;
|
|
22
30
|
private editorContext;
|
|
23
31
|
private listeners;
|
|
32
|
+
private currentWorkingDirectory;
|
|
24
33
|
start(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Normalize path for cross-platform compatibility
|
|
36
|
+
* - Converts Windows backslashes to forward slashes
|
|
37
|
+
* - Converts drive letters to lowercase for consistent comparison
|
|
38
|
+
*/
|
|
39
|
+
private normalizePath;
|
|
40
|
+
/**
|
|
41
|
+
* Find the correct port for the current workspace
|
|
42
|
+
*/
|
|
43
|
+
private findPortForWorkspace;
|
|
44
|
+
/**
|
|
45
|
+
* Check if we should handle this message based on workspace folder
|
|
46
|
+
*/
|
|
47
|
+
private shouldHandleMessage;
|
|
48
|
+
private scheduleReconnect;
|
|
25
49
|
stop(): void;
|
|
26
50
|
isConnected(): boolean;
|
|
27
|
-
|
|
51
|
+
isClientRunning(): boolean;
|
|
28
52
|
getContext(): EditorContext;
|
|
29
53
|
onContextUpdate(listener: (context: EditorContext) => void): () => void;
|
|
30
54
|
private handleMessage;
|
|
31
55
|
private notifyListeners;
|
|
32
56
|
getPort(): number;
|
|
33
57
|
/**
|
|
34
|
-
* Request diagnostics for a specific file from
|
|
58
|
+
* Request diagnostics for a specific file from IDE
|
|
35
59
|
* @param filePath - The file path to get diagnostics for
|
|
36
60
|
* @returns Promise that resolves with diagnostics array
|
|
37
61
|
*/
|
|
38
62
|
requestDiagnostics(filePath: string): Promise<Diagnostic[]>;
|
|
63
|
+
/**
|
|
64
|
+
* Reset reconnection attempts (e.g., when user manually triggers reconnect)
|
|
65
|
+
*/
|
|
66
|
+
resetReconnectAttempts(): void;
|
|
39
67
|
}
|
|
40
68
|
export declare const vscodeConnection: VSCodeConnectionManager;
|
|
41
69
|
export type { EditorContext, Diagnostic };
|
|
@@ -1,17 +1,69 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
2
5
|
class VSCodeConnectionManager {
|
|
3
6
|
constructor() {
|
|
4
|
-
Object.defineProperty(this, "
|
|
7
|
+
Object.defineProperty(this, "client", {
|
|
5
8
|
enumerable: true,
|
|
6
9
|
configurable: true,
|
|
7
10
|
writable: true,
|
|
8
11
|
value: null
|
|
9
12
|
});
|
|
10
|
-
Object.defineProperty(this, "
|
|
13
|
+
Object.defineProperty(this, "reconnectTimer", {
|
|
11
14
|
enumerable: true,
|
|
12
15
|
configurable: true,
|
|
13
16
|
writable: true,
|
|
14
|
-
value:
|
|
17
|
+
value: null
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(this, "reconnectAttempts", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: 0
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(this, "MAX_RECONNECT_ATTEMPTS", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: 10
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(this, "BASE_RECONNECT_DELAY", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: 2000
|
|
36
|
+
}); // 2 seconds
|
|
37
|
+
Object.defineProperty(this, "MAX_RECONNECT_DELAY", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
value: 30000
|
|
42
|
+
}); // 30 seconds
|
|
43
|
+
// Port ranges: VSCode uses 9527-9537, JetBrains uses 9538-9548
|
|
44
|
+
Object.defineProperty(this, "VSCODE_BASE_PORT", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: 9527
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, "VSCODE_MAX_PORT", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true,
|
|
54
|
+
value: 9537
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(this, "JETBRAINS_BASE_PORT", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
configurable: true,
|
|
59
|
+
writable: true,
|
|
60
|
+
value: 9538
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperty(this, "JETBRAINS_MAX_PORT", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
writable: true,
|
|
66
|
+
value: 9548
|
|
15
67
|
});
|
|
16
68
|
Object.defineProperty(this, "port", {
|
|
17
69
|
enumerable: true,
|
|
@@ -31,64 +83,162 @@ class VSCodeConnectionManager {
|
|
|
31
83
|
writable: true,
|
|
32
84
|
value: []
|
|
33
85
|
});
|
|
86
|
+
Object.defineProperty(this, "currentWorkingDirectory", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
configurable: true,
|
|
89
|
+
writable: true,
|
|
90
|
+
value: process.cwd()
|
|
91
|
+
});
|
|
34
92
|
}
|
|
35
93
|
async start() {
|
|
36
|
-
// If already
|
|
37
|
-
if (this.
|
|
94
|
+
// If already connected, just return success
|
|
95
|
+
if (this.client?.readyState === WebSocket.OPEN) {
|
|
38
96
|
return Promise.resolve();
|
|
39
97
|
}
|
|
98
|
+
// Try to find the correct port for this workspace
|
|
99
|
+
const targetPort = this.findPortForWorkspace();
|
|
40
100
|
return new Promise((resolve, reject) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
//
|
|
45
|
-
this.
|
|
46
|
-
|
|
101
|
+
const tryConnect = (port) => {
|
|
102
|
+
// Check both VSCode and JetBrains port ranges
|
|
103
|
+
if (port > this.VSCODE_MAX_PORT && port < this.JETBRAINS_BASE_PORT) {
|
|
104
|
+
// Jump from VSCode range to JetBrains range
|
|
105
|
+
tryConnect(this.JETBRAINS_BASE_PORT);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (port > this.JETBRAINS_MAX_PORT) {
|
|
109
|
+
reject(new Error(`Failed to connect: no IDE server found on ports ${this.VSCODE_BASE_PORT}-${this.VSCODE_MAX_PORT} or ${this.JETBRAINS_BASE_PORT}-${this.JETBRAINS_MAX_PORT}`));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
this.client = new WebSocket(`ws://localhost:${port}`);
|
|
114
|
+
this.client.on('open', () => {
|
|
115
|
+
// Reset reconnect attempts on successful connection
|
|
116
|
+
this.reconnectAttempts = 0;
|
|
117
|
+
this.port = port;
|
|
118
|
+
resolve();
|
|
119
|
+
});
|
|
120
|
+
this.client.on('message', message => {
|
|
47
121
|
try {
|
|
48
122
|
const data = JSON.parse(message.toString());
|
|
49
|
-
|
|
123
|
+
// Filter messages by workspace folder
|
|
124
|
+
if (this.shouldHandleMessage(data)) {
|
|
125
|
+
this.handleMessage(data);
|
|
126
|
+
}
|
|
50
127
|
}
|
|
51
128
|
catch (error) {
|
|
52
129
|
// Ignore invalid JSON
|
|
53
130
|
}
|
|
54
131
|
});
|
|
55
|
-
|
|
56
|
-
this.
|
|
132
|
+
this.client.on('close', () => {
|
|
133
|
+
this.client = null;
|
|
134
|
+
this.scheduleReconnect();
|
|
57
135
|
});
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
this.
|
|
136
|
+
this.client.on('error', _error => {
|
|
137
|
+
// On initial connection, try next port
|
|
138
|
+
if (this.reconnectAttempts === 0) {
|
|
139
|
+
this.client = null;
|
|
140
|
+
tryConnect(port + 1);
|
|
141
|
+
}
|
|
142
|
+
// For reconnections, silently handle and let close event trigger reconnect
|
|
61
143
|
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
reject(error);
|
|
72
|
-
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
tryConnect(port + 1);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
tryConnect(targetPort);
|
|
73
150
|
});
|
|
74
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Normalize path for cross-platform compatibility
|
|
154
|
+
* - Converts Windows backslashes to forward slashes
|
|
155
|
+
* - Converts drive letters to lowercase for consistent comparison
|
|
156
|
+
*/
|
|
157
|
+
normalizePath(filePath) {
|
|
158
|
+
let normalized = filePath.replace(/\\/g, '/');
|
|
159
|
+
// Convert Windows drive letter to lowercase (C: -> c:)
|
|
160
|
+
if (/^[A-Z]:/.test(normalized)) {
|
|
161
|
+
normalized = normalized.charAt(0).toLowerCase() + normalized.slice(1);
|
|
162
|
+
}
|
|
163
|
+
return normalized;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Find the correct port for the current workspace
|
|
167
|
+
*/
|
|
168
|
+
findPortForWorkspace() {
|
|
169
|
+
try {
|
|
170
|
+
const portInfoPath = path.join(os.tmpdir(), 'snow-cli-ports.json');
|
|
171
|
+
if (fs.existsSync(portInfoPath)) {
|
|
172
|
+
const portInfo = JSON.parse(fs.readFileSync(portInfoPath, 'utf8'));
|
|
173
|
+
// Normalize cwd for consistent comparison
|
|
174
|
+
const cwd = this.normalizePath(this.currentWorkingDirectory);
|
|
175
|
+
// Direct match
|
|
176
|
+
if (portInfo[cwd]) {
|
|
177
|
+
return portInfo[cwd];
|
|
178
|
+
}
|
|
179
|
+
// Check if cwd is within any of the workspace folders
|
|
180
|
+
for (const [workspace, port] of Object.entries(portInfo)) {
|
|
181
|
+
const normalizedWorkspace = this.normalizePath(workspace);
|
|
182
|
+
if (cwd.startsWith(normalizedWorkspace)) {
|
|
183
|
+
return port;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
// Ignore errors, will fall back to VSCODE_BASE_PORT
|
|
190
|
+
}
|
|
191
|
+
// Start with VSCode port range by default
|
|
192
|
+
return this.VSCODE_BASE_PORT;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Check if we should handle this message based on workspace folder
|
|
196
|
+
*/
|
|
197
|
+
shouldHandleMessage(data) {
|
|
198
|
+
// If no workspace folder in message, accept it (backwards compatibility)
|
|
199
|
+
if (!data.workspaceFolder) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
// Normalize paths for consistent comparison across platforms
|
|
203
|
+
const cwd = this.normalizePath(this.currentWorkingDirectory);
|
|
204
|
+
const workspaceFolder = this.normalizePath(data.workspaceFolder);
|
|
205
|
+
// Bidirectional check: either cwd is within IDE workspace, or IDE workspace is within cwd
|
|
206
|
+
const cwdInWorkspace = cwd.startsWith(workspaceFolder);
|
|
207
|
+
const workspaceInCwd = workspaceFolder.startsWith(cwd);
|
|
208
|
+
const matches = cwdInWorkspace || workspaceInCwd;
|
|
209
|
+
return matches;
|
|
210
|
+
}
|
|
211
|
+
scheduleReconnect() {
|
|
212
|
+
if (this.reconnectTimer) {
|
|
213
|
+
clearTimeout(this.reconnectTimer);
|
|
214
|
+
}
|
|
215
|
+
this.reconnectAttempts++;
|
|
216
|
+
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const delay = Math.min(this.BASE_RECONNECT_DELAY * Math.pow(1.5, this.reconnectAttempts - 1), this.MAX_RECONNECT_DELAY);
|
|
220
|
+
this.reconnectTimer = setTimeout(() => {
|
|
221
|
+
this.start().catch(() => {
|
|
222
|
+
// Silently handle reconnection failures
|
|
223
|
+
});
|
|
224
|
+
}, delay);
|
|
225
|
+
}
|
|
75
226
|
stop() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
227
|
+
if (this.reconnectTimer) {
|
|
228
|
+
clearTimeout(this.reconnectTimer);
|
|
229
|
+
this.reconnectTimer = null;
|
|
79
230
|
}
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
this.server = null;
|
|
231
|
+
if (this.client) {
|
|
232
|
+
this.client.close();
|
|
233
|
+
this.client = null;
|
|
84
234
|
}
|
|
235
|
+
this.reconnectAttempts = 0;
|
|
85
236
|
}
|
|
86
237
|
isConnected() {
|
|
87
|
-
return
|
|
88
|
-
Array.from(this.clients).some(client => client.readyState === WebSocket.OPEN));
|
|
238
|
+
return this.client?.readyState === WebSocket.OPEN;
|
|
89
239
|
}
|
|
90
|
-
|
|
91
|
-
return this.
|
|
240
|
+
isClientRunning() {
|
|
241
|
+
return this.client !== null;
|
|
92
242
|
}
|
|
93
243
|
getContext() {
|
|
94
244
|
return { ...this.editorContext };
|
|
@@ -119,15 +269,13 @@ class VSCodeConnectionManager {
|
|
|
119
269
|
return this.port;
|
|
120
270
|
}
|
|
121
271
|
/**
|
|
122
|
-
* Request diagnostics for a specific file from
|
|
272
|
+
* Request diagnostics for a specific file from IDE
|
|
123
273
|
* @param filePath - The file path to get diagnostics for
|
|
124
274
|
* @returns Promise that resolves with diagnostics array
|
|
125
275
|
*/
|
|
126
276
|
async requestDiagnostics(filePath) {
|
|
127
277
|
return new Promise(resolve => {
|
|
128
|
-
|
|
129
|
-
const client = Array.from(this.clients).find(c => c.readyState === WebSocket.OPEN);
|
|
130
|
-
if (!client) {
|
|
278
|
+
if (!this.client || this.client.readyState !== WebSocket.OPEN) {
|
|
131
279
|
resolve([]); // Return empty array if not connected
|
|
132
280
|
return;
|
|
133
281
|
}
|
|
@@ -150,15 +298,21 @@ class VSCodeConnectionManager {
|
|
|
150
298
|
};
|
|
151
299
|
const cleanup = () => {
|
|
152
300
|
clearTimeout(timeout);
|
|
153
|
-
client?.removeListener('message', handler);
|
|
301
|
+
this.client?.removeListener('message', handler);
|
|
154
302
|
};
|
|
155
|
-
client.on('message', handler);
|
|
156
|
-
client.send(JSON.stringify({
|
|
303
|
+
this.client.on('message', handler);
|
|
304
|
+
this.client.send(JSON.stringify({
|
|
157
305
|
type: 'getDiagnostics',
|
|
158
306
|
requestId,
|
|
159
307
|
filePath,
|
|
160
308
|
}));
|
|
161
309
|
});
|
|
162
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Reset reconnection attempts (e.g., when user manually triggers reconnect)
|
|
313
|
+
*/
|
|
314
|
+
resetReconnectAttempts() {
|
|
315
|
+
this.reconnectAttempts = 0;
|
|
316
|
+
}
|
|
163
317
|
}
|
|
164
318
|
export const vscodeConnection = new VSCodeConnectionManager();
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -57,10 +57,16 @@ $ npm uninstall --global snow-ai
|
|
|
57
57
|
|
|
58
58
|
## Install VSCode Extension
|
|
59
59
|
|
|
60
|
-
* download [VSIX/snow-cli-
|
|
60
|
+
* download [VSIX/snow-cli-x.x.x.vsix](https://github.com/MayDay-wpf/snow-cli/blob/main/VSIX/)
|
|
61
61
|
|
|
62
62
|
* open VSCode, click `Extensions` -> `Install from VSIX...` -> select `snow-cli-0.2.6.vsix`
|
|
63
63
|
|
|
64
|
+
## Install JetBrains plugin
|
|
65
|
+
|
|
66
|
+
* download [JetBrains/build/distributions](https://github.com/MayDay-wpf/snow-cli/tree/main/JetBrains/build/distributions)
|
|
67
|
+
|
|
68
|
+
* File > Settings > Plugins
|
|
69
|
+
|
|
64
70
|
## Live View
|
|
65
71
|
* **Welcome & Settings**
|
|
66
72
|
|