pi-lens 3.3.0 → 3.3.1

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 CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to pi-lens will be documented in this file.
4
4
 
5
+ ## [3.3.1] - 2026-04-02
6
+
7
+ ### Fixed
8
+ - **LSP spawn `EINVAL` on Windows** — `.cmd` files (e.g. `vscode-json-language-server.cmd`) found via npm global lookup were spawned without `shell: true`, causing `EINVAL` from `CreateProcess`. The `needsShell` recomputation for npm global paths incorrectly treated `.cmd` the same as `.exe`. Fixed in both primary and fallback spawn paths.
9
+ - **Unhandled `EINVAL` rejection** — LSP error handlers only caught `ENOENT` (binary not found). `EINVAL` (binary found but can't execute directly) now caught alongside `ENOENT` in both `launchLSP` and `launchViaPackageManager`.
10
+
11
+ ---
12
+
5
13
  ## [3.3.0] - 2026-04-02
6
14
 
7
15
  ### Removed
@@ -149,8 +149,11 @@ export async function launchLSP(command, args = [], options = {}) {
149
149
  if (npmGlobalPath) {
150
150
  spawnCommand = npmGlobalPath;
151
151
  // Recompute needsShell for npm global path
152
- const globalHasExt = /\.(exe|cmd|bat)$/i.test(spawnCommand);
153
- needsShell = isWindows && (spawnCommand.includes(" ") || !globalHasExt);
152
+ needsShell =
153
+ isWindows &&
154
+ (spawnCommand.includes(" ") ||
155
+ /\.(cmd|bat)$/i.test(spawnCommand) ||
156
+ !/\.(exe|cmd|bat)$/i.test(spawnCommand));
154
157
  }
155
158
  }
156
159
  let proc;
@@ -166,8 +169,10 @@ export async function launchLSP(command, args = [], options = {}) {
166
169
  if (npmGlobalPath && npmGlobalPath !== spawnCommand) {
167
170
  console.error(`[lsp] Trying npm global: ${npmGlobalPath}`);
168
171
  // Recompute needsShell for npm global path
169
- const globalHasExt = /\.(exe|cmd|bat)$/i.test(npmGlobalPath);
170
- const needsShellGlobal = isWindows && (npmGlobalPath.includes(" ") || !globalHasExt);
172
+ const needsShellGlobal = isWindows &&
173
+ (npmGlobalPath.includes(" ") ||
174
+ /\.(cmd|bat)$/i.test(npmGlobalPath) ||
175
+ !/\.(exe|cmd|bat)$/i.test(npmGlobalPath));
171
176
  proc = trySpawn(npmGlobalPath, args, cwd, env, needsShellGlobal);
172
177
  }
173
178
  else {
@@ -192,7 +197,7 @@ export async function launchLSP(command, args = [], options = {}) {
192
197
  let settled = false;
193
198
  // Attach error handler that can reject for immediate errors
194
199
  proc.on("error", (err) => {
195
- if (!settled && err.code === "ENOENT") {
200
+ if (!settled && (err.code === "ENOENT" || err.code === "EINVAL")) {
196
201
  settled = true;
197
202
  reject(new Error(`LSP server binary not found: ${command}. ` +
198
203
  `Install it or check your PATH.`));
@@ -254,7 +259,7 @@ export async function launchViaPackageManager(packageName, args = [], options =
254
259
  await new Promise((resolve, reject) => {
255
260
  let settled = false;
256
261
  proc.on("error", (err) => {
257
- if (!settled && err.code === "ENOENT") {
262
+ if (!settled && (err.code === "ENOENT" || err.code === "EINVAL")) {
258
263
  settled = true;
259
264
  reject(new Error(`Package manager not found for: ${packageName}. ` +
260
265
  `Install Node.js or check your PATH.`));
@@ -205,8 +205,11 @@ export async function launchLSP(
205
205
  if (npmGlobalPath) {
206
206
  spawnCommand = npmGlobalPath;
207
207
  // Recompute needsShell for npm global path
208
- const globalHasExt = /\.(exe|cmd|bat)$/i.test(spawnCommand);
209
- needsShell = isWindows && (spawnCommand.includes(" ") || !globalHasExt);
208
+ needsShell =
209
+ isWindows &&
210
+ (spawnCommand.includes(" ") ||
211
+ /\.(cmd|bat)$/i.test(spawnCommand) ||
212
+ !/\.(exe|cmd|bat)$/i.test(spawnCommand));
210
213
  }
211
214
  }
212
215
 
@@ -225,9 +228,11 @@ export async function launchLSP(
225
228
  if (npmGlobalPath && npmGlobalPath !== spawnCommand) {
226
229
  console.error(`[lsp] Trying npm global: ${npmGlobalPath}`);
227
230
  // Recompute needsShell for npm global path
228
- const globalHasExt = /\.(exe|cmd|bat)$/i.test(npmGlobalPath);
229
231
  const needsShellGlobal =
230
- isWindows && (npmGlobalPath.includes(" ") || !globalHasExt);
232
+ isWindows &&
233
+ (npmGlobalPath.includes(" ") ||
234
+ /\.(cmd|bat)$/i.test(npmGlobalPath) ||
235
+ !/\.(exe|cmd|bat)$/i.test(npmGlobalPath));
231
236
  proc = trySpawn(npmGlobalPath, args, cwd, env, needsShellGlobal);
232
237
  } else {
233
238
  throw err;
@@ -256,7 +261,7 @@ export async function launchLSP(
256
261
 
257
262
  // Attach error handler that can reject for immediate errors
258
263
  proc.on("error", (err: Error & { code?: string }) => {
259
- if (!settled && err.code === "ENOENT") {
264
+ if (!settled && (err.code === "ENOENT" || err.code === "EINVAL")) {
260
265
  settled = true;
261
266
  reject(
262
267
  new Error(
@@ -346,7 +351,7 @@ export async function launchViaPackageManager(
346
351
  let settled = false;
347
352
 
348
353
  proc.on("error", (err: Error & { code?: string }) => {
349
- if (!settled && err.code === "ENOENT") {
354
+ if (!settled && (err.code === "ENOENT" || err.code === "EINVAL")) {
350
355
  settled = true;
351
356
  reject(
352
357
  new Error(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lens",
3
- "version": "3.3.0",
3
+ "version": "3.3.1",
4
4
  "type": "module",
5
5
  "description": "pi extension for real-time code quality — 31 LSP servers, tree-sitter structural analysis, AST pattern matching, auto-install for TypeScript/Python tooling, duplicate detection, complexity metrics, and inline blockers with comprehensive /lens-booboo reports",
6
6
  "repository": {