pi-lens 3.6.2 → 3.6.4
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/CHANGELOG.md +10 -2
- package/package.json +4 -4
- package/tsconfig.json +1 -1
- package/clients/__tests__/file-time.test.js +0 -216
- package/clients/__tests__/file-time.test.ts +0 -276
- package/clients/__tests__/format-service.test.js +0 -245
- package/clients/__tests__/format-service.test.ts +0 -339
- package/clients/__tests__/formatters.test.js +0 -271
- package/clients/__tests__/formatters.test.ts +0 -401
- package/clients/agent-behavior-client.js +0 -110
- package/clients/agent-behavior-client.test.js +0 -94
- package/clients/agent-behavior-client.test.ts +0 -116
- package/clients/amain-types.js +0 -164
- package/clients/architect-client.js +0 -291
- package/clients/ast-grep-client.js +0 -253
- package/clients/ast-grep-parser.js +0 -84
- package/clients/ast-grep-rule-manager.js +0 -89
- package/clients/ast-grep-types.js +0 -9
- package/clients/auto-loop.js +0 -131
- package/clients/biome-client.js +0 -420
- package/clients/biome-client.test.js +0 -144
- package/clients/biome-client.test.ts +0 -163
- package/clients/cache/rule-cache.js +0 -72
- package/clients/cache-manager.js +0 -245
- package/clients/cache-manager.test.js +0 -197
- package/clients/cache-manager.test.ts +0 -299
- package/clients/complexity-client.js +0 -675
- package/clients/complexity-client.test.js +0 -234
- package/clients/complexity-client.test.ts +0 -255
- package/clients/config-validator.js +0 -465
- package/clients/dependency-checker.js +0 -325
- package/clients/dependency-checker.test.js +0 -60
- package/clients/dependency-checker.test.ts +0 -71
- package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
- package/clients/dispatch/__tests__/autofix-integration.test.ts +0 -300
- package/clients/dispatch/__tests__/runner-registration.test.js +0 -234
- package/clients/dispatch/__tests__/runner-registration.test.ts +0 -286
- package/clients/dispatch/debug.log +0 -1
- package/clients/dispatch/dispatcher.edge.test.js +0 -82
- package/clients/dispatch/dispatcher.edge.test.ts +0 -100
- package/clients/dispatch/dispatcher.format.test.js +0 -46
- package/clients/dispatch/dispatcher.format.test.ts +0 -58
- package/clients/dispatch/dispatcher.inline.test.js +0 -74
- package/clients/dispatch/dispatcher.inline.test.ts +0 -93
- package/clients/dispatch/dispatcher.js +0 -381
- package/clients/dispatch/dispatcher.test.js +0 -116
- package/clients/dispatch/dispatcher.test.ts +0 -149
- package/clients/dispatch/integration.js +0 -108
- package/clients/dispatch/plan.js +0 -183
- package/clients/dispatch/runners/architect.js +0 -83
- package/clients/dispatch/runners/architect.test.js +0 -138
- package/clients/dispatch/runners/architect.test.ts +0 -162
- package/clients/dispatch/runners/ast-grep-napi.js +0 -405
- package/clients/dispatch/runners/ast-grep-napi.test.js +0 -107
- package/clients/dispatch/runners/ast-grep-napi.test.ts +0 -129
- package/clients/dispatch/runners/ast-grep.js +0 -157
- package/clients/dispatch/runners/biome.js +0 -55
- package/clients/dispatch/runners/config-validation.js +0 -67
- package/clients/dispatch/runners/go-vet.js +0 -48
- package/clients/dispatch/runners/index.js +0 -47
- package/clients/dispatch/runners/lsp.js +0 -102
- package/clients/dispatch/runners/oxlint.js +0 -67
- package/clients/dispatch/runners/oxlint.test.js +0 -230
- package/clients/dispatch/runners/oxlint.test.ts +0 -303
- package/clients/dispatch/runners/pyright.js +0 -100
- package/clients/dispatch/runners/pyright.test.js +0 -98
- package/clients/dispatch/runners/pyright.test.ts +0 -121
- package/clients/dispatch/runners/python-slop.js +0 -97
- package/clients/dispatch/runners/python-slop.test.js +0 -203
- package/clients/dispatch/runners/python-slop.test.ts +0 -298
- package/clients/dispatch/runners/ruff.js +0 -48
- package/clients/dispatch/runners/rust-clippy.js +0 -102
- package/clients/dispatch/runners/scan_codebase.test.js +0 -89
- package/clients/dispatch/runners/scan_codebase.test.ts +0 -105
- package/clients/dispatch/runners/shellcheck.js +0 -147
- package/clients/dispatch/runners/shellcheck.test.js +0 -98
- package/clients/dispatch/runners/shellcheck.test.ts +0 -129
- package/clients/dispatch/runners/similarity.js +0 -230
- package/clients/dispatch/runners/spellcheck.js +0 -106
- package/clients/dispatch/runners/spellcheck.test.js +0 -158
- package/clients/dispatch/runners/spellcheck.test.ts +0 -214
- package/clients/dispatch/runners/tree-sitter.js +0 -246
- package/clients/dispatch/runners/ts-lsp.js +0 -125
- package/clients/dispatch/runners/ts-slop.js +0 -113
- package/clients/dispatch/runners/type-safety.js +0 -142
- package/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -134
- package/clients/dispatch/runners/utils/runner-helpers.js +0 -115
- package/clients/dispatch/runners/utils.js +0 -51
- package/clients/dispatch/runners/yaml-rule-parser.js +0 -360
- package/clients/dispatch/types.js +0 -16
- package/clients/dispatch/utils/format-utils.js +0 -44
- package/clients/dogfood.test.js +0 -201
- package/clients/dogfood.test.ts +0 -269
- package/clients/file-kinds.js +0 -177
- package/clients/file-kinds.test.js +0 -169
- package/clients/file-kinds.test.ts +0 -210
- package/clients/file-time.js +0 -152
- package/clients/file-utils.js +0 -40
- package/clients/fix-scanners.js +0 -204
- package/clients/format-service.js +0 -184
- package/clients/formatters.js +0 -488
- package/clients/go-client.js +0 -203
- package/clients/go-client.test.js +0 -127
- package/clients/go-client.test.ts +0 -143
- package/clients/installer/index.js +0 -403
- package/clients/interviewer-templates.js +0 -75
- package/clients/interviewer.js +0 -173
- package/clients/jscpd-client.js +0 -196
- package/clients/jscpd-client.test.js +0 -127
- package/clients/jscpd-client.test.ts +0 -145
- package/clients/knip-client.js +0 -239
- package/clients/knip-client.test.js +0 -112
- package/clients/knip-client.test.ts +0 -128
- package/clients/latency-logger.js +0 -40
- package/clients/lsp/__tests__/client.test.js +0 -310
- package/clients/lsp/__tests__/client.test.ts +0 -412
- package/clients/lsp/__tests__/config.test.js +0 -167
- package/clients/lsp/__tests__/config.test.ts +0 -217
- package/clients/lsp/__tests__/error-recovery.test.js +0 -213
- package/clients/lsp/__tests__/error-recovery.test.ts +0 -279
- package/clients/lsp/__tests__/integration.test.js +0 -127
- package/clients/lsp/__tests__/integration.test.ts +0 -160
- package/clients/lsp/__tests__/launch.test.js +0 -313
- package/clients/lsp/__tests__/launch.test.ts +0 -394
- package/clients/lsp/__tests__/server.test.js +0 -259
- package/clients/lsp/__tests__/server.test.ts +0 -332
- package/clients/lsp/__tests__/service.test.js +0 -438
- package/clients/lsp/__tests__/service.test.ts +0 -530
- package/clients/lsp/client.js +0 -350
- package/clients/lsp/config.js +0 -112
- package/clients/lsp/index.js +0 -318
- package/clients/lsp/installer/index.js +0 -391
- package/clients/lsp/interactive-install.js +0 -221
- package/clients/lsp/language.js +0 -170
- package/clients/lsp/launch.js +0 -329
- package/clients/lsp/lsp/launch.js +0 -116
- package/clients/lsp/lsp/server.js +0 -532
- package/clients/lsp/lsp-index.js +0 -10
- package/clients/lsp/path-utils.js +0 -5
- package/clients/lsp/server.js +0 -725
- package/clients/lsp/test-py-spawn/requirements.txt +0 -1
- package/clients/lsp/test-py-spawn/test.py +0 -3
- package/clients/lsp/test-py-svc/requirements.txt +0 -1
- package/clients/lsp/test-py-svc/test.py +0 -3
- package/clients/lsp/test-python-project/requirements.txt +0 -1
- package/clients/lsp/test-python-project/test.py +0 -5
- package/clients/metrics-client.js +0 -107
- package/clients/metrics-client.test.js +0 -128
- package/clients/metrics-client.test.ts +0 -163
- package/clients/metrics-history.js +0 -367
- package/clients/path-utils.js +0 -142
- package/clients/pipeline.js +0 -272
- package/clients/production-readiness.js +0 -522
- package/clients/project-index.js +0 -255
- package/clients/project-metadata.js +0 -531
- package/clients/ruff-client.js +0 -325
- package/clients/ruff-client.test.js +0 -132
- package/clients/ruff-client.test.ts +0 -153
- package/clients/rules-scanner.js +0 -97
- package/clients/runner-tracker.js +0 -152
- package/clients/rust-client.js +0 -205
- package/clients/rust-client.test.js +0 -108
- package/clients/rust-client.test.ts +0 -130
- package/clients/safe-spawn-async.js +0 -163
- package/clients/safe-spawn.js +0 -241
- package/clients/sanitize.js +0 -291
- package/clients/sanitize.test.js +0 -177
- package/clients/sanitize.test.ts +0 -223
- package/clients/scan-architectural-debt.js +0 -167
- package/clients/scan-utils.js +0 -83
- package/clients/secrets-scanner.js +0 -119
- package/clients/secrets-scanner.test.js +0 -100
- package/clients/secrets-scanner.test.ts +0 -113
- package/clients/sg-runner.js +0 -292
- package/clients/state-matrix.js +0 -160
- package/clients/subprocess-client.js +0 -65
- package/clients/symbol-types.js +0 -5
- package/clients/test-runner-client.js +0 -523
- package/clients/test-runner-client.test.js +0 -192
- package/clients/test-runner-client.test.ts +0 -253
- package/clients/test-utils.js +0 -27
- package/clients/test-utils.ts +0 -36
- package/clients/todo-scanner.js +0 -200
- package/clients/todo-scanner.test.js +0 -301
- package/clients/todo-scanner.test.ts +0 -352
- package/clients/tool-availability.js +0 -207
- package/clients/tree-sitter-client.js +0 -601
- package/clients/tree-sitter-query-loader.js +0 -355
- package/clients/tree-sitter-symbol-extractor.js +0 -289
- package/clients/ts-service.js +0 -129
- package/clients/type-coverage-client.js +0 -127
- package/clients/type-coverage-client.test.js +0 -105
- package/clients/type-coverage-client.test.ts +0 -125
- package/clients/type-safety-client.js +0 -138
- package/clients/types.js +0 -11
- package/clients/typescript-client.codefix.test.js +0 -157
- package/clients/typescript-client.codefix.test.ts +0 -186
- package/clients/typescript-client.js +0 -509
- package/clients/typescript-client.test.js +0 -105
- package/clients/typescript-client.test.ts +0 -126
- package/commands/booboo.js +0 -1007
- package/commands/fix-from-booboo.js +0 -398
- package/commands/fix-simplified.js +0 -618
- package/commands/rate.js +0 -281
- package/commands/rate.test.js +0 -119
- package/commands/rate.test.ts +0 -131
- package/commands/refactor.js +0 -130
package/clients/lsp/launch.js
DELETED
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LSP Process Launch Utilities
|
|
3
|
-
*
|
|
4
|
-
* Handles spawning LSP servers via various methods:
|
|
5
|
-
* - Direct binary execution (using absolute paths on Windows)
|
|
6
|
-
* - Node.js scripts (npx/bun)
|
|
7
|
-
* - Package manager execution
|
|
8
|
-
*/
|
|
9
|
-
import { execSync, spawn as nodeSpawn, } from "node:child_process";
|
|
10
|
-
import fs from "node:fs";
|
|
11
|
-
import path from "node:path";
|
|
12
|
-
const isWindows = process.platform === "win32";
|
|
13
|
-
/**
|
|
14
|
-
* Find binary in npm global directory
|
|
15
|
-
* Works around PATH caching issue after npm install -g
|
|
16
|
-
*/
|
|
17
|
-
function _findBinaryInNpmGlobal(command) {
|
|
18
|
-
try {
|
|
19
|
-
// Get npm global prefix
|
|
20
|
-
const prefix = execSync("npm prefix -g", { encoding: "utf-8" }).trim();
|
|
21
|
-
// On Windows, binaries are directly in the prefix dir
|
|
22
|
-
// On Unix, they're in prefix/bin
|
|
23
|
-
const binDir = isWindows ? prefix : path.join(prefix, "bin");
|
|
24
|
-
// Check for Windows variants
|
|
25
|
-
const candidates = isWindows
|
|
26
|
-
? [
|
|
27
|
-
path.join(binDir, `${command}.cmd`),
|
|
28
|
-
path.join(binDir, `${command}.exe`),
|
|
29
|
-
path.join(binDir, command),
|
|
30
|
-
]
|
|
31
|
-
: [path.join(binDir, command)];
|
|
32
|
-
for (const candidate of candidates) {
|
|
33
|
-
if (fs.existsSync(candidate)) {
|
|
34
|
-
return candidate;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Try to spawn a process, throwing immediately if it fails
|
|
45
|
-
*/
|
|
46
|
-
function trySpawn(command, args, cwd, env, needsShell) {
|
|
47
|
-
let proc;
|
|
48
|
-
if (needsShell) {
|
|
49
|
-
// Use shell mode with quoted command
|
|
50
|
-
const shellCommand = `"${command}" ${args.map((a) => (a.includes(" ") ? `"${a}"` : a)).join(" ")}`;
|
|
51
|
-
proc = nodeSpawn(shellCommand, [], {
|
|
52
|
-
cwd,
|
|
53
|
-
env,
|
|
54
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
55
|
-
detached: false,
|
|
56
|
-
windowsHide: true,
|
|
57
|
-
shell: true,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
// Use normal spawn without shell
|
|
62
|
-
proc = nodeSpawn(command, args, {
|
|
63
|
-
cwd,
|
|
64
|
-
env,
|
|
65
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
66
|
-
detached: false,
|
|
67
|
-
windowsHide: isWindows,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
71
|
-
throw new Error(`Failed to spawn LSP server: ${command}`);
|
|
72
|
-
}
|
|
73
|
-
// Check if process exited immediately (spawn failure - synchronous check)
|
|
74
|
-
if (proc.exitCode !== null || proc.killed) {
|
|
75
|
-
throw new Error(`LSP server ${command} exited immediately (code: ${proc.exitCode}). ` +
|
|
76
|
-
`The binary may be missing or corrupted.`);
|
|
77
|
-
}
|
|
78
|
-
return proc;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Attach error handler to a spawned process to prevent ENOENT crashes
|
|
82
|
-
* This catches "command not found" errors and other spawn failures
|
|
83
|
-
* Returns a promise that rejects if an immediate error occurs
|
|
84
|
-
*/
|
|
85
|
-
function _attachErrorHandler(proc, context, rejectOnImmediateError) {
|
|
86
|
-
proc.on("error", (err) => {
|
|
87
|
-
// Log the error but don't crash - the caller should handle this gracefully
|
|
88
|
-
console.error(`[lsp] Spawn error for ${context}:`, err.message);
|
|
89
|
-
// If we have a reject function and this is an immediate spawn error, reject
|
|
90
|
-
if (rejectOnImmediateError &&
|
|
91
|
-
err.code === "ENOENT") {
|
|
92
|
-
rejectOnImmediateError(err);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
// Also handle unexpected exit (process crash after successful spawn)
|
|
96
|
-
proc.on("exit", (code, signal) => {
|
|
97
|
-
if (code !== 0 && code !== null) {
|
|
98
|
-
console.error(`[lsp] ${context} exited with code ${code}${signal ? ` (signal: ${signal})` : ""}`);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
proc.on("close", (code, signal) => {
|
|
102
|
-
if (code !== 0 && code !== null) {
|
|
103
|
-
console.error(`[lsp] ${context} closed with code ${code}${signal ? ` (signal: ${signal})` : ""}`);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Spawn an LSP server process
|
|
109
|
-
*
|
|
110
|
-
* Key fixes for Windows:
|
|
111
|
-
* - Uses absolute paths (relative paths fail in shell mode)
|
|
112
|
-
* - Uses shell: true for .cmd files
|
|
113
|
-
* - Uses windowsHide to prevent console window popup
|
|
114
|
-
* - Detects immediate spawn failures (ENOENT) before returning
|
|
115
|
-
*
|
|
116
|
-
* @param command - Command to run (e.g., "typescript-language-server")
|
|
117
|
-
* @param args - Arguments (e.g., ["--stdio"])
|
|
118
|
-
* @param options - Spawn options including cwd, env
|
|
119
|
-
* @returns LSPProcess handle
|
|
120
|
-
*/
|
|
121
|
-
export async function launchLSP(command, args = [], options = {}) {
|
|
122
|
-
const cwd = String(options.cwd ?? process.cwd());
|
|
123
|
-
const env = { ...process.env, ...options.env };
|
|
124
|
-
// Resolve command path
|
|
125
|
-
// - If already absolute, use as-is
|
|
126
|
-
// - If it's a simple command (no path separators), let system find it via PATH
|
|
127
|
-
// - Otherwise, resolve relative to cwd
|
|
128
|
-
const resolvedCommand = path.isAbsolute(command)
|
|
129
|
-
? command
|
|
130
|
-
: command.includes(path.sep) || command.includes("/")
|
|
131
|
-
? path.resolve(cwd, command)
|
|
132
|
-
: command; // Let system find it via PATH
|
|
133
|
-
// Compute needsShell based on command
|
|
134
|
-
// On Windows, shell: true is needed for .cmd/.bat files and extensionless binaries
|
|
135
|
-
// .exe files can be spawned directly, but .cmd/.bat require shell interpretation
|
|
136
|
-
const hasScriptExtension = /\.(cmd|bat)$/i.test(resolvedCommand);
|
|
137
|
-
let needsShell = isWindows &&
|
|
138
|
-
(resolvedCommand.includes(" ") ||
|
|
139
|
-
hasScriptExtension ||
|
|
140
|
-
!/\.(exe|cmd|bat)$/i.test(resolvedCommand));
|
|
141
|
-
// Try to spawn the process
|
|
142
|
-
// If command not found, try npm global as fallback (handles PATH caching after install)
|
|
143
|
-
let spawnCommand = resolvedCommand;
|
|
144
|
-
// First, try to find in npm global if it's a simple command name
|
|
145
|
-
if (!path.isAbsolute(command) &&
|
|
146
|
-
!command.includes(path.sep) &&
|
|
147
|
-
!command.includes("/")) {
|
|
148
|
-
const npmGlobalPath = _findBinaryInNpmGlobal(command);
|
|
149
|
-
if (npmGlobalPath) {
|
|
150
|
-
spawnCommand = npmGlobalPath;
|
|
151
|
-
// Recompute needsShell for npm global path
|
|
152
|
-
needsShell =
|
|
153
|
-
isWindows &&
|
|
154
|
-
(spawnCommand.includes(" ") ||
|
|
155
|
-
/\.(cmd|bat)$/i.test(spawnCommand) ||
|
|
156
|
-
!/\.(exe|cmd|bat)$/i.test(spawnCommand));
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
let proc;
|
|
160
|
-
try {
|
|
161
|
-
proc = trySpawn(spawnCommand, args, cwd, env, needsShell);
|
|
162
|
-
}
|
|
163
|
-
catch (err) {
|
|
164
|
-
// If spawn failed with simple command, try npm global
|
|
165
|
-
if (!path.isAbsolute(command) &&
|
|
166
|
-
!command.includes(path.sep) &&
|
|
167
|
-
!command.includes("/")) {
|
|
168
|
-
const npmGlobalPath = _findBinaryInNpmGlobal(command);
|
|
169
|
-
if (npmGlobalPath && npmGlobalPath !== spawnCommand) {
|
|
170
|
-
console.error(`[lsp] Trying npm global: ${npmGlobalPath}`);
|
|
171
|
-
// Recompute needsShell for npm global path
|
|
172
|
-
const needsShellGlobal = isWindows &&
|
|
173
|
-
(npmGlobalPath.includes(" ") ||
|
|
174
|
-
/\.(cmd|bat)$/i.test(npmGlobalPath) ||
|
|
175
|
-
!/\.(exe|cmd|bat)$/i.test(npmGlobalPath));
|
|
176
|
-
proc = trySpawn(npmGlobalPath, args, cwd, env, needsShellGlobal);
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
throw err;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
throw err;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
187
|
-
throw new Error(`Failed to spawn LSP server: ${command}`);
|
|
188
|
-
}
|
|
189
|
-
// Check if process exited immediately (spawn failure - synchronous check)
|
|
190
|
-
if (proc.exitCode !== null || proc.killed) {
|
|
191
|
-
throw new Error(`LSP server ${command} exited immediately (code: ${proc.exitCode}). ` +
|
|
192
|
-
`The binary may be missing or corrupted.`);
|
|
193
|
-
}
|
|
194
|
-
// For Windows and certain spawn failures, the error is async (ENOENT)
|
|
195
|
-
// We need to wait a small tick to catch immediate spawn failures
|
|
196
|
-
await new Promise((resolve, reject) => {
|
|
197
|
-
let settled = false;
|
|
198
|
-
// Attach error handler that can reject for immediate errors
|
|
199
|
-
proc.on("error", (err) => {
|
|
200
|
-
if (!settled && (err.code === "ENOENT" || err.code === "EINVAL")) {
|
|
201
|
-
settled = true;
|
|
202
|
-
reject(new Error(`LSP server binary not found: ${command}. ` +
|
|
203
|
-
`Install it or check your PATH.`));
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
// Also listen for immediate exit
|
|
207
|
-
proc.on("exit", (code) => {
|
|
208
|
-
if (!settled && code !== null) {
|
|
209
|
-
settled = true;
|
|
210
|
-
reject(new Error(`LSP server ${command} exited immediately with code ${code}. ` +
|
|
211
|
-
`The binary may be missing or corrupted.`));
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
// Give it a small window to fail immediately (ENOENT on Windows is fast)
|
|
215
|
-
setTimeout(() => {
|
|
216
|
-
if (!settled) {
|
|
217
|
-
settled = true;
|
|
218
|
-
resolve();
|
|
219
|
-
}
|
|
220
|
-
}, 50);
|
|
221
|
-
});
|
|
222
|
-
// Re-attach the permanent error handler now that we've passed the danger zone
|
|
223
|
-
_attachErrorHandler(proc, command);
|
|
224
|
-
return {
|
|
225
|
-
process: proc,
|
|
226
|
-
stdin: proc.stdin,
|
|
227
|
-
stdout: proc.stdout,
|
|
228
|
-
stderr: proc.stderr,
|
|
229
|
-
pid: proc.pid ?? 0,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Spawn via package manager (npx/bun)
|
|
234
|
-
*/
|
|
235
|
-
export async function launchViaPackageManager(packageName, args = [], options = {}) {
|
|
236
|
-
// Prefer bun if available, fall back to npx (use .cmd on Windows)
|
|
237
|
-
const isWin = process.platform === "win32";
|
|
238
|
-
if (process.env.BUN_INSTALL) {
|
|
239
|
-
return launchLSP(isWin ? "bun.exe" : "bun", ["x", packageName, ...args], options);
|
|
240
|
-
}
|
|
241
|
-
// For npx on Windows, use shell mode with the full command string
|
|
242
|
-
if (isWin) {
|
|
243
|
-
const argsStr = args.map((a) => (a.includes(" ") ? `"${a}"` : a)).join(" ");
|
|
244
|
-
const shellCommand = `npx -y ${packageName}${argsStr ? ` ${argsStr}` : ""}`;
|
|
245
|
-
const cwd = String(options.cwd ?? process.cwd());
|
|
246
|
-
const env = { ...process.env, ...options.env };
|
|
247
|
-
const proc = nodeSpawn(shellCommand, [], {
|
|
248
|
-
cwd,
|
|
249
|
-
env,
|
|
250
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
251
|
-
detached: false,
|
|
252
|
-
windowsHide: true,
|
|
253
|
-
shell: true,
|
|
254
|
-
});
|
|
255
|
-
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
256
|
-
throw new Error(`Failed to spawn package manager for: ${packageName}`);
|
|
257
|
-
}
|
|
258
|
-
// Check for immediate spawn failure on Windows
|
|
259
|
-
await new Promise((resolve, reject) => {
|
|
260
|
-
let settled = false;
|
|
261
|
-
proc.on("error", (err) => {
|
|
262
|
-
if (!settled && (err.code === "ENOENT" || err.code === "EINVAL")) {
|
|
263
|
-
settled = true;
|
|
264
|
-
reject(new Error(`Package manager not found for: ${packageName}. ` +
|
|
265
|
-
`Install Node.js or check your PATH.`));
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
proc.on("exit", (code) => {
|
|
269
|
-
if (!settled && code !== null) {
|
|
270
|
-
settled = true;
|
|
271
|
-
reject(new Error(`Package manager exited immediately for: ${packageName} (code: ${code})`));
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
setTimeout(() => {
|
|
275
|
-
if (!settled) {
|
|
276
|
-
settled = true;
|
|
277
|
-
resolve();
|
|
278
|
-
}
|
|
279
|
-
}, 50);
|
|
280
|
-
});
|
|
281
|
-
// Attach permanent error handler
|
|
282
|
-
_attachErrorHandler(proc, packageName);
|
|
283
|
-
return {
|
|
284
|
-
process: proc,
|
|
285
|
-
stdin: proc.stdin,
|
|
286
|
-
stdout: proc.stdout,
|
|
287
|
-
stderr: proc.stderr,
|
|
288
|
-
pid: proc.pid ?? 0,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
return launchLSP("npx", ["-y", packageName, ...args], options);
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Spawn via Node.js directly
|
|
295
|
-
*/
|
|
296
|
-
export async function launchViaNode(scriptPath, args = [], options = {}) {
|
|
297
|
-
return launchLSP(process.execPath, [scriptPath, ...args], options);
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Spawn via Python module
|
|
301
|
-
*/
|
|
302
|
-
export async function launchViaPython(moduleName, args = [], options = {}) {
|
|
303
|
-
// On Windows, prefer 'py' launcher, fall back to 'python'
|
|
304
|
-
const pythonCmd = process.platform === "win32" ? "py" : "python3";
|
|
305
|
-
return launchLSP(pythonCmd, ["-m", moduleName, ...args], options);
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Stop an LSP process gracefully
|
|
309
|
-
*/
|
|
310
|
-
export async function stopLSP(handle) {
|
|
311
|
-
return new Promise((resolve) => {
|
|
312
|
-
// Send SIGTERM first
|
|
313
|
-
handle.process.kill("SIGTERM");
|
|
314
|
-
// Force kill after timeout
|
|
315
|
-
const timeout = setTimeout(() => {
|
|
316
|
-
if (!handle.process.killed) {
|
|
317
|
-
handle.process.kill("SIGKILL");
|
|
318
|
-
}
|
|
319
|
-
}, 5000);
|
|
320
|
-
handle.process.on("exit", () => {
|
|
321
|
-
clearTimeout(timeout);
|
|
322
|
-
resolve();
|
|
323
|
-
});
|
|
324
|
-
handle.process.on("error", () => {
|
|
325
|
-
clearTimeout(timeout);
|
|
326
|
-
resolve();
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LSP Process Launch Utilities
|
|
3
|
-
*
|
|
4
|
-
* Handles spawning LSP servers via various methods:
|
|
5
|
-
* - Direct binary execution (using absolute paths on Windows)
|
|
6
|
-
* - Node.js scripts (npx/bun)
|
|
7
|
-
* - Package manager execution
|
|
8
|
-
*/
|
|
9
|
-
import { spawn as nodeSpawn } from "child_process";
|
|
10
|
-
import path from "path";
|
|
11
|
-
// Helper to detect if running on Windows
|
|
12
|
-
const isWindows = process.platform === "win32";
|
|
13
|
-
/**
|
|
14
|
-
* Spawn an LSP server process
|
|
15
|
-
*
|
|
16
|
-
* Key fixes for Windows:
|
|
17
|
-
* - Uses absolute paths (relative paths fail in shell mode)
|
|
18
|
-
* - Uses shell: true for .cmd files
|
|
19
|
-
* - Uses windowsHide to prevent console window popup
|
|
20
|
-
*
|
|
21
|
-
* @param command - Command to run (e.g., "typescript-language-server")
|
|
22
|
-
* @param args - Arguments (e.g., ["--stdio"])
|
|
23
|
-
* @param options - Spawn options including cwd, env
|
|
24
|
-
* @returns LSPProcess handle
|
|
25
|
-
*/
|
|
26
|
-
export function launchLSP(command, args = [], options = {}) {
|
|
27
|
-
const cwd = String(options.cwd ?? process.cwd());
|
|
28
|
-
const env = { ...process.env, ...options.env };
|
|
29
|
-
// Always use absolute path (critical for Windows shell mode)
|
|
30
|
-
const resolvedCommand = path.isAbsolute(command)
|
|
31
|
-
? command
|
|
32
|
-
: path.resolve(cwd, command);
|
|
33
|
-
// On Windows with shell: true, we need to quote the command if it has spaces
|
|
34
|
-
const needsShell = isWindows && (resolvedCommand.includes(" ") || resolvedCommand.includes(".cmd"));
|
|
35
|
-
let proc;
|
|
36
|
-
if (needsShell) {
|
|
37
|
-
// Use shell mode with quoted command
|
|
38
|
-
const shellCommand = `"${resolvedCommand}" ${args.map(a => a.includes(" ") ? `"${a}"` : a).join(" ")}`;
|
|
39
|
-
proc = nodeSpawn(shellCommand, [], {
|
|
40
|
-
cwd,
|
|
41
|
-
env,
|
|
42
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
43
|
-
detached: false,
|
|
44
|
-
windowsHide: true,
|
|
45
|
-
shell: true,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// Use normal spawn without shell
|
|
50
|
-
proc = nodeSpawn(resolvedCommand, args, {
|
|
51
|
-
cwd,
|
|
52
|
-
env,
|
|
53
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
54
|
-
detached: false,
|
|
55
|
-
windowsHide: isWindows,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
59
|
-
throw new Error(`Failed to spawn LSP server: ${command}`);
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
process: proc,
|
|
63
|
-
stdin: proc.stdin,
|
|
64
|
-
stdout: proc.stdout,
|
|
65
|
-
stderr: proc.stderr,
|
|
66
|
-
pid: proc.pid ?? 0,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Spawn via package manager (npx/bun)
|
|
71
|
-
*/
|
|
72
|
-
export function launchViaPackageManager(packageName, args = [], options = {}) {
|
|
73
|
-
// Prefer bun if available, fall back to npx (use .cmd on Windows)
|
|
74
|
-
const isWin = process.platform === "win32";
|
|
75
|
-
const manager = process.env.BUN_INSTALL
|
|
76
|
-
? { cmd: isWin ? "bun.exe" : "bun", args: ["x", packageName, ...args] }
|
|
77
|
-
: { cmd: isWin ? "npx.cmd" : "npx", args: ["-y", packageName, ...args] };
|
|
78
|
-
return launchLSP(manager.cmd, manager.args, options);
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Spawn via Node.js directly
|
|
82
|
-
*/
|
|
83
|
-
export function launchViaNode(scriptPath, args = [], options = {}) {
|
|
84
|
-
return launchLSP(process.execPath, [scriptPath, ...args], options);
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Spawn via Python module
|
|
88
|
-
*/
|
|
89
|
-
export function launchViaPython(moduleName, args = [], options = {}) {
|
|
90
|
-
// On Windows, prefer 'py' launcher, fall back to 'python'
|
|
91
|
-
const pythonCmd = process.platform === "win32" ? "py" : "python3";
|
|
92
|
-
return launchLSP(pythonCmd, ["-m", moduleName, ...args], options);
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Stop an LSP process gracefully
|
|
96
|
-
*/
|
|
97
|
-
export async function stopLSP(handle) {
|
|
98
|
-
return new Promise((resolve) => {
|
|
99
|
-
// Send SIGTERM first
|
|
100
|
-
handle.process.kill("SIGTERM");
|
|
101
|
-
// Force kill after timeout
|
|
102
|
-
const timeout = setTimeout(() => {
|
|
103
|
-
if (!handle.process.killed) {
|
|
104
|
-
handle.process.kill("SIGKILL");
|
|
105
|
-
}
|
|
106
|
-
}, 5000);
|
|
107
|
-
handle.process.on("exit", () => {
|
|
108
|
-
clearTimeout(timeout);
|
|
109
|
-
resolve();
|
|
110
|
-
});
|
|
111
|
-
handle.process.on("error", () => {
|
|
112
|
-
clearTimeout(timeout);
|
|
113
|
-
resolve();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
}
|