pi-lens 4.4.2 → 4.4.3

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/{chunk-2ZGIZPDG.js → chunk-2VUQMUMT.js} +6 -6
  3. package/dist/{chunk-ARJ6PLFH.js → chunk-3W7IEVVL.js} +1 -1
  4. package/dist/{chunk-5JM2524W.js → chunk-3YN6V5TV.js} +16 -15
  5. package/dist/{chunk-CF24OIYI.js → chunk-5UCAH366.js} +1 -1
  6. package/dist/{chunk-NW7BOILN.js → chunk-6STA6Z7I.js} +2 -2
  7. package/dist/{chunk-66SXUJCA.js → chunk-77M37OKR.js} +5 -3
  8. package/dist/{chunk-EETY4LF7.js → chunk-AB3YYG6N.js} +1 -1
  9. package/dist/{chunk-66VMUL7Q.js → chunk-ACXEQZOU.js} +3 -3
  10. package/dist/{chunk-3UUPUE3O.js → chunk-CMMHNUZ2.js} +31 -29
  11. package/dist/chunk-CSHFH5IN.js +17 -0
  12. package/dist/{chunk-3WA4HP4I.js → chunk-EC47DWFA.js} +6 -5
  13. package/dist/{chunk-ESBQHFMJ.js → chunk-EU63SDCG.js} +187 -79
  14. package/dist/{chunk-34WSVGEM.js → chunk-FCSOVF55.js} +78 -0
  15. package/dist/{chunk-IBRALRBR.js → chunk-FMSO6RDZ.js} +3 -2
  16. package/dist/{chunk-ODBNXWT4.js → chunk-H6MF6EVN.js} +81 -42
  17. package/dist/{chunk-XPZPXCBV.js → chunk-KDERNTCQ.js} +2 -2
  18. package/dist/chunk-KSX3TXSZ.js +69 -0
  19. package/dist/{chunk-PV6LR5P5.js → chunk-M6HSLBWY.js} +198 -4362
  20. package/dist/{chunk-XKIZ2HNN.js → chunk-MXGY6KPT.js} +6 -4
  21. package/dist/{chunk-GHB6AYCP.js → chunk-RXCOMYPY.js} +2 -2
  22. package/dist/{chunk-GZYBXISR.js → chunk-SQ4TVJBR.js} +3 -3
  23. package/dist/{chunk-VITUCP5A.js → chunk-SS36ZX4J.js} +5 -3
  24. package/dist/{chunk-PFNSLWU5.js → chunk-T6CPIZNT.js} +5 -4
  25. package/dist/{chunk-JWA5I3SR.js → chunk-VCO24T4L.js} +3 -5
  26. package/dist/{chunk-Q6ZWTCLY.js → chunk-XAGLWMJ4.js} +2 -3
  27. package/dist/{chunk-WOKKRCJ5.js → chunk-XIJZVPD5.js} +3 -2
  28. package/dist/{chunk-7ULNCDCO.js → chunk-YIUAVF7E.js} +5 -5
  29. package/dist/{chunk-GOYRYZ2R.js → chunk-YSZNHOBY.js} +63 -11
  30. package/dist/chunk-YYOIQFRS.js +4139 -0
  31. package/dist/{chunk-QZVW3AAK.js → chunk-ZWFS3OEF.js} +5 -4
  32. package/dist/index.js +1628 -1482
  33. package/dist/mcp/analyze-cli.js +1 -1
  34. package/dist/mcp/cli.js +6 -6
  35. package/dist/mcp/server.js +62 -61
  36. package/dist/mcp/worker.js +16 -15
  37. package/dist/probes/installer.js +1 -1
  38. package/docs/pi-lens-merge-policy.md +12 -4
  39. package/docs/pi-lens-reviewer.md +3 -0
  40. package/docs/pi-lens-subagent.md +5 -0
  41. package/package.json +1 -1
  42. package/dist/chunk-CO2G5PHH.js +0 -84
  43. package/dist/{chunk-IXXDFY73.js → chunk-3EFKIGZN.js} +0 -0
  44. package/dist/{chunk-OG5UUPN7.js → chunk-OCAGUNBC.js} +3 -3
@@ -1,13 +1,17 @@
1
1
  import { createRequire as __pilensCreateRequire } from "node:module"; const require = __pilensCreateRequire(import.meta.url);
2
+ import {
3
+ resolveOpengrepConfig
4
+ } from "./chunk-VWCXW2E7.js";
2
5
  import {
3
6
  augmentPythonEnvironment,
4
7
  detectPythonEnvironment,
5
8
  detectPythonVenv,
6
9
  pythonEnvironmentToolCandidates
7
- } from "./chunk-34WSVGEM.js";
10
+ } from "./chunk-FCSOVF55.js";
8
11
  import {
9
- resolveOpengrepConfig
10
- } from "./chunk-VWCXW2E7.js";
12
+ resolveGitCheckout,
13
+ resolveLinkedWorktreeOwner
14
+ } from "./chunk-PNQDPDRC.js";
11
15
  import {
12
16
  extensionsForLanguage,
13
17
  getUserRuleRoot,
@@ -36,7 +40,7 @@ import {
36
40
  isZizmorAuditTarget,
37
41
  logSessionStart,
38
42
  resolveZizmorGitHubToken
39
- } from "./chunk-66VMUL7Q.js";
43
+ } from "./chunk-ACXEQZOU.js";
40
44
  import {
41
45
  resolveToolCwd
42
46
  } from "./chunk-Q7DUK4LX.js";
@@ -63,6 +67,7 @@ import {
63
67
  holdOwnChildPid,
64
68
  isCommandAvailableAsync,
65
69
  isPathIgnoredByProject,
70
+ isPiLensInternalPath,
66
71
  ownerTagForChildren,
67
72
  resolveWindowsCommandForEnvironment,
68
73
  safeSpawnAsync
@@ -128,6 +133,7 @@ import {
128
133
  isAtOrAboveHomeDir,
129
134
  isFullyQualified,
130
135
  isUnderDir,
136
+ isVendorPath,
131
137
  isWindowsPath,
132
138
  matchesWorkspaceMemberPattern,
133
139
  normalizeEphemeralMapKey,
@@ -140,16 +146,115 @@ import {
140
146
  __require
141
147
  } from "./chunk-NXL4FFQQ.js";
142
148
 
149
+ // dist/clients/analysis-root.js
150
+ import * as fs from "node:fs";
151
+ import * as os from "node:os";
152
+ import * as nodePath from "node:path";
153
+ var PROJECT_MARKERS = [
154
+ ".git",
155
+ "package.json",
156
+ "pyproject.toml",
157
+ "Cargo.toml",
158
+ "go.mod",
159
+ "pom.xml",
160
+ "build.gradle",
161
+ "Gemfile",
162
+ "mix.exs",
163
+ "composer.json"
164
+ ];
165
+ function hasProjectMarker(dir) {
166
+ return PROJECT_MARKERS.some((marker) => {
167
+ try {
168
+ const stat2 = fs.statSync(nodePath.join(dir, marker));
169
+ return stat2.isFile() || marker === ".git";
170
+ } catch {
171
+ return false;
172
+ }
173
+ });
174
+ }
175
+ function nearestProjectRoot(filePath) {
176
+ let dir = nodePath.dirname(nodePath.resolve(filePath));
177
+ const filesystemRoot = nodePath.parse(dir).root;
178
+ while (dir !== filesystemRoot) {
179
+ if (hasProjectMarker(dir))
180
+ return dir;
181
+ dir = nodePath.dirname(dir);
182
+ }
183
+ return hasProjectMarker(filesystemRoot) ? filesystemRoot : void 0;
184
+ }
185
+ function realPathOrResolved(filePath) {
186
+ const resolved = nodePath.resolve(filePath);
187
+ let current = resolved;
188
+ const missing = [];
189
+ while (true) {
190
+ try {
191
+ const real = fs.realpathSync.native(current);
192
+ return nodePath.join(real, ...missing.reverse());
193
+ } catch {
194
+ const parent = nodePath.dirname(current);
195
+ if (parent === current)
196
+ return resolved;
197
+ missing.push(nodePath.basename(current));
198
+ current = parent;
199
+ }
200
+ }
201
+ }
202
+ function resolveAnalysisRootPath(filePath, sessionRoot, homeDirOverride) {
203
+ const resolved = realPathOrResolved(filePath);
204
+ const session = realPathOrResolved(sessionRoot);
205
+ const tmp = realPathOrResolved(os.tmpdir());
206
+ const data = process.env.PI_LENS_HOME ? realPathOrResolved(process.env.PI_LENS_HOME) : void 0;
207
+ if (isVendorPath(resolved))
208
+ return void 0;
209
+ if (resolved === tmp || resolved === session || isUnderDir(session, resolved) || !isUnderDir(resolved, session) && (isPiLensInternalPath(resolved, session) || data !== void 0 && (resolved === data || isUnderDir(resolved, data))))
210
+ return void 0;
211
+ if (isUnderDir(resolved, session))
212
+ return session;
213
+ const checkout = resolveGitCheckout(session);
214
+ const linked = checkout && resolveLinkedWorktreeOwner(checkout, resolved);
215
+ if (linked && !isVendorPath(resolved))
216
+ return linked.root;
217
+ const candidate = nearestProjectRoot(resolved);
218
+ if (!candidate || candidate === nodePath.parse(candidate).root)
219
+ return void 0;
220
+ const home = realPathOrResolved(homeDirOverride ?? os.homedir());
221
+ if (isAtOrAboveHomeDir(candidate, home))
222
+ return void 0;
223
+ if (candidate === tmp || isUnderDir(session, candidate))
224
+ return void 0;
225
+ if (isVendorPath(candidate))
226
+ return void 0;
227
+ return candidate;
228
+ }
229
+ function resolveAnalysisRoot(filePath, sessionRoot, homeDirOverride) {
230
+ const resolved = realPathOrResolved(filePath);
231
+ if (isVendorPath(resolved))
232
+ return "none";
233
+ const checkout = resolveGitCheckout(sessionRoot);
234
+ if (checkout && resolveLinkedWorktreeOwner(checkout, resolved)) {
235
+ return "linked-worktree";
236
+ }
237
+ const root = resolveAnalysisRootPath(filePath, sessionRoot, homeDirOverride);
238
+ if (!root)
239
+ return "none";
240
+ if (root === nodePath.resolve(sessionRoot))
241
+ return "session";
242
+ return "adopted";
243
+ }
244
+ function canWriteAnalysisRoot(mode) {
245
+ return mode === "session" || mode === "linked-worktree";
246
+ }
247
+
143
248
  // dist/clients/lsp/server.js
144
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, statSync as statSync3 } from "node:fs";
249
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, statSync as statSync4 } from "node:fs";
145
250
  import { access, readFile, readdir, stat } from "node:fs/promises";
146
- import os6 from "node:os";
251
+ import os7 from "node:os";
147
252
  import path6 from "node:path";
148
253
 
149
254
  // dist/clients/sgconfig.js
150
255
  import { createHash } from "node:crypto";
151
- import * as fs from "node:fs";
152
- import * as os from "node:os";
256
+ import * as fs2 from "node:fs";
257
+ import * as os2 from "node:os";
153
258
  import * as path from "node:path";
154
259
  var SGCONFIG_NAMES = ["sgconfig.yml", "sgconfig.yaml"];
155
260
  function findLocalSgconfig(startDir) {
@@ -157,7 +262,7 @@ function findLocalSgconfig(startDir) {
157
262
  }
158
263
  function canonicalDir(dir) {
159
264
  try {
160
- return fs.realpathSync.native(dir);
265
+ return fs2.realpathSync.native(dir);
161
266
  } catch {
162
267
  return path.resolve(dir);
163
268
  }
@@ -200,7 +305,7 @@ function getAstGrepRuleSources(projectRoot = process.cwd()) {
200
305
  });
201
306
  const seen = /* @__PURE__ */ new Set();
202
307
  return candidates.filter((source) => {
203
- if (!fs.existsSync(source.dir))
308
+ if (!fs2.existsSync(source.dir))
204
309
  return false;
205
310
  const key = canonicalDir(source.dir);
206
311
  if (seen.has(key))
@@ -213,7 +318,7 @@ function findYamlFiles(dir) {
213
318
  const files = [];
214
319
  let entries;
215
320
  try {
216
- entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
321
+ entries = fs2.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
217
322
  } catch {
218
323
  return files;
219
324
  }
@@ -265,7 +370,7 @@ function snapshotRuleSource(source) {
265
370
  hash.update("\0");
266
371
  let content;
267
372
  try {
268
- content = fs.readFileSync(file, "utf8");
373
+ content = fs2.readFileSync(file, "utf8");
269
374
  } catch {
270
375
  hash.update("missing");
271
376
  hash.update("\0");
@@ -307,8 +412,8 @@ function getAstGrepRuleFingerprint(projectRoot = process.cwd(), options = {}) {
307
412
  return ruleCorpusFingerprintForCycle("ast-grep", root, (fingerprintRoot) => sourceFingerprint(getAstGrepRuleSources(fingerprintRoot).map(snapshotRuleSource)), options.force);
308
413
  }
309
414
  function materializeMergedRuleDir(sources, mergedDir) {
310
- fs.rmSync(mergedDir, { recursive: true, force: true });
311
- fs.mkdirSync(mergedDir, { recursive: true });
415
+ fs2.rmSync(mergedDir, { recursive: true, force: true });
416
+ fs2.mkdirSync(mergedDir, { recursive: true });
312
417
  const claimedByEarlierSource = /* @__PURE__ */ new Set();
313
418
  for (const [sourceIndex, source] of sources.entries()) {
314
419
  const claimedThisSource = /* @__PURE__ */ new Set();
@@ -325,9 +430,9 @@ function materializeMergedRuleDir(sources, mergedDir) {
325
430
  continue;
326
431
  const destination = path.join(mergedDir, `source${sourceIndex}-${String(fileIndex).padStart(5, "0")}.yml`);
327
432
  if (survivingDocuments.length === file.documents.length) {
328
- fs.copyFileSync(file.file, destination);
433
+ fs2.copyFileSync(file.file, destination);
329
434
  } else {
330
- fs.writeFileSync(destination, `${survivingDocuments.map((document) => document.raw.trim()).join("\n---\n")}
435
+ fs2.writeFileSync(destination, `${survivingDocuments.map((document) => document.raw.trim()).join("\n---\n")}
331
436
  `);
332
437
  }
333
438
  }
@@ -343,14 +448,14 @@ function resolveBaselineSgconfig(projectRoot = process.cwd()) {
343
448
  const root = canonicalDir(path.resolve(projectRoot || process.cwd()));
344
449
  const fingerprint = getAstGrepRuleFingerprint(root, { force: true });
345
450
  const cached = cachedBaselines.get(root);
346
- if (cached?.fingerprint === fingerprint && fs.existsSync(cached.path) && fs.existsSync(cached.mergedDir)) {
451
+ if (cached?.fingerprint === fingerprint && fs2.existsSync(cached.path) && fs2.existsSync(cached.mergedDir)) {
347
452
  return cached.path;
348
453
  }
349
454
  const sources = getAstGrepRuleSources(root).map(snapshotRuleSource);
350
455
  if (sources.length === 0)
351
456
  return void 0;
352
- const dir = path.join(os.tmpdir(), "pi-lens-ast-grep");
353
- fs.mkdirSync(dir, { recursive: true });
457
+ const dir = path.join(os2.tmpdir(), "pi-lens-ast-grep");
458
+ fs2.mkdirSync(dir, { recursive: true });
354
459
  const artifactKey = rootArtifactKey(root);
355
460
  const file = path.join(dir, `baseline-${process.pid}-${artifactKey}.sgconfig.yml`);
356
461
  const mergedDir = path.join(dir, `baseline-${process.pid}-${artifactKey}.rules`);
@@ -362,7 +467,7 @@ function resolveBaselineSgconfig(projectRoot = process.cwd()) {
362
467
  cleanupStaleBaselines(dir, protectedArtifacts);
363
468
  materializeMergedRuleDir(sources, mergedDir);
364
469
  const ruleDirForYaml = mergedDir.split(path.sep).join("/");
365
- fs.writeFileSync(file, `ruleDirs:
470
+ fs2.writeFileSync(file, `ruleDirs:
366
471
  - ${JSON.stringify(ruleDirForYaml)}
367
472
  `);
368
473
  cachedBaselines.set(root, { fingerprint, path: file, mergedDir });
@@ -373,7 +478,7 @@ var SG_BASELINE_RETAINED_ENTRIES = 24;
373
478
  function enforceBaselineEntryCap(dir, keep) {
374
479
  let names;
375
480
  try {
376
- names = fs.readdirSync(dir);
481
+ names = fs2.readdirSync(dir);
377
482
  } catch {
378
483
  return;
379
484
  }
@@ -389,7 +494,7 @@ function enforceBaselineEntryCap(dir, keep) {
389
494
  try {
390
495
  candidates.push({
391
496
  full,
392
- mtimeMs: fs.statSync(full).mtimeMs,
497
+ mtimeMs: fs2.statSync(full).mtimeMs,
393
498
  recursive: isMergedDir
394
499
  });
395
500
  } catch {
@@ -402,7 +507,7 @@ function enforceBaselineEntryCap(dir, keep) {
402
507
  let evicted = 0;
403
508
  for (const candidate of candidates.slice(0, over)) {
404
509
  try {
405
- fs.rmSync(candidate.full, {
510
+ fs2.rmSync(candidate.full, {
406
511
  recursive: candidate.recursive,
407
512
  force: true
408
513
  });
@@ -426,7 +531,7 @@ function enforceBaselineEntryCap(dir, keep) {
426
531
  function cleanupStaleBaselines(dir, keep) {
427
532
  try {
428
533
  const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
429
- for (const name of fs.readdirSync(dir)) {
534
+ for (const name of fs2.readdirSync(dir)) {
430
535
  const isConfig = /^baseline(?:-\d+(?:-[a-f0-9]+)?)?\.sgconfig\.yml$/.test(name);
431
536
  const isMergedDir = /^baseline-\d+(?:-[a-f0-9]+)?\.rules$/.test(name);
432
537
  if (!isConfig && !isMergedDir)
@@ -435,9 +540,9 @@ function cleanupStaleBaselines(dir, keep) {
435
540
  if (keep.has(full))
436
541
  continue;
437
542
  try {
438
- const stat2 = fs.statSync(full);
543
+ const stat2 = fs2.statSync(full);
439
544
  if (stat2.mtimeMs < cutoff) {
440
- fs.rmSync(full, { recursive: stat2.isDirectory(), force: true });
545
+ fs2.rmSync(full, { recursive: stat2.isDirectory(), force: true });
441
546
  }
442
547
  } catch {
443
548
  }
@@ -492,7 +597,7 @@ function serverTraits(declaration) {
492
597
  }
493
598
 
494
599
  // dist/clients/lsp/config.js
495
- import * as os3 from "node:os";
600
+ import * as os4 from "node:os";
496
601
  import path3 from "node:path";
497
602
 
498
603
  // dist/clients/dispatch/known-runner-ids.js
@@ -510,12 +615,12 @@ function isKnownRunnerId(id) {
510
615
  // dist/clients/lsp/launch.js
511
616
  import { AsyncLocalStorage } from "node:async_hooks";
512
617
  import { execFileSync, spawn as nodeSpawn } from "node:child_process";
513
- import fs3 from "node:fs";
514
- import os2 from "node:os";
618
+ import fs4 from "node:fs";
619
+ import os3 from "node:os";
515
620
  import path2 from "node:path";
516
621
 
517
622
  // dist/clients/lsp/ruby-drive-dirs.js
518
- import * as fs2 from "node:fs";
623
+ import * as fs3 from "node:fs";
519
624
  var RUBY_VERSION_DIR = /^ruby\d/i;
520
625
  var rubyDirNamesCache = new BoundedLruCache(16);
521
626
  function rubyDriveKey(driveRoot) {
@@ -531,7 +636,7 @@ function getRubyVersionDirNamesSync(driveRoot) {
531
636
  return cached;
532
637
  let names;
533
638
  try {
534
- names = filterRubyDirNames(fs2.readdirSync(driveRoot));
639
+ names = filterRubyDirNames(fs3.readdirSync(driveRoot));
535
640
  } catch {
536
641
  names = [];
537
642
  }
@@ -545,7 +650,7 @@ async function getRubyVersionDirNamesAsync(driveRoot) {
545
650
  return cached;
546
651
  let names;
547
652
  try {
548
- names = filterRubyDirNames(await fs2.promises.readdir(driveRoot));
653
+ names = filterRubyDirNames(await fs3.promises.readdir(driveRoot));
549
654
  } catch {
550
655
  names = [];
551
656
  }
@@ -572,8 +677,8 @@ function logSessionStart2(msg) {
572
677
  const line = redactSecrets(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
573
678
  `);
574
679
  try {
575
- fs3.mkdirSync(SESSIONSTART_LOG_DIR, { recursive: true });
576
- fs3.appendFileSync(SESSIONSTART_LOG, line);
680
+ fs4.mkdirSync(SESSIONSTART_LOG_DIR, { recursive: true });
681
+ fs4.appendFileSync(SESSIONSTART_LOG, line);
577
682
  } catch {
578
683
  }
579
684
  }
@@ -654,7 +759,7 @@ async function buildAugmentedPath(basePath) {
654
759
  candidates.push(nodeDir);
655
760
  }
656
761
  if (isWindows) {
657
- const home = os2.homedir();
762
+ const home = os3.homedir();
658
763
  const driveRoot = path2.parse(home).root;
659
764
  candidates.push(path2.join(home, ".cargo", "bin"));
660
765
  candidates.push(path2.join(home, "go", "bin"));
@@ -676,7 +781,7 @@ async function buildAugmentedPath(basePath) {
676
781
  }
677
782
  const toAppend = [];
678
783
  for (const candidate of candidates) {
679
- if (!candidate || !fs3.existsSync(candidate))
784
+ if (!candidate || !fs4.existsSync(candidate))
680
785
  continue;
681
786
  const normalized = normalizePathEntry(candidate, process.platform);
682
787
  if (existing.has(normalized))
@@ -692,13 +797,13 @@ async function buildAugmentedPath(basePath) {
692
797
  }
693
798
  function isCmdShimValid(cmdPath) {
694
799
  try {
695
- const content = fs3.readFileSync(cmdPath, "utf-8");
800
+ const content = fs4.readFileSync(cmdPath, "utf-8");
696
801
  const match = content.match(/"%~dp0[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
697
802
  if (!match)
698
803
  return true;
699
804
  const relPath = match[1].replace(/[/\\]/g, path2.sep);
700
805
  const target = path2.resolve(path2.dirname(cmdPath), "..", relPath);
701
- return fs3.existsSync(target);
806
+ return fs4.existsSync(target);
702
807
  } catch {
703
808
  return true;
704
809
  }
@@ -715,16 +820,16 @@ function isMissingWindowsStartupCommand(command, spawnCommand, cwd, env) {
715
820
  }
716
821
  function bypassPs1OnWindows(ps1Path, args) {
717
822
  const cmdPath = `${ps1Path.slice(0, -4)}.cmd`;
718
- if (fs3.existsSync(cmdPath)) {
823
+ if (fs4.existsSync(cmdPath)) {
719
824
  return { command: cmdPath, args, needsShell: true };
720
825
  }
721
826
  try {
722
- const content = fs3.readFileSync(ps1Path, "utf-8");
827
+ const content = fs4.readFileSync(ps1Path, "utf-8");
723
828
  const match = content.match(/"\$basedir[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
724
829
  if (match) {
725
830
  const relPath = match[1].replace(/[/\\]/g, path2.sep);
726
831
  const jsPath = path2.resolve(path2.dirname(ps1Path), "..", relPath);
727
- if (fs3.existsSync(jsPath)) {
832
+ if (fs4.existsSync(jsPath)) {
728
833
  return {
729
834
  command: process.execPath,
730
835
  args: [jsPath, ...args],
@@ -752,7 +857,7 @@ function findBinaryOnPath(command, env) {
752
857
  timeout: 5e3
753
858
  }).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
754
859
  for (const candidate of result) {
755
- if (fs3.existsSync(candidate)) {
860
+ if (fs4.existsSync(candidate)) {
756
861
  return candidate;
757
862
  }
758
863
  }
@@ -988,7 +1093,7 @@ async function launchLSP(command, args = [], options = {}) {
988
1093
  };
989
1094
  proc.stderr?.on("data", onStartupStderr);
990
1095
  try {
991
- await new Promise((resolve3, reject) => {
1096
+ await new Promise((resolve4, reject) => {
992
1097
  let settled = false;
993
1098
  proc.on("error", (err) => {
994
1099
  if (!settled) {
@@ -1025,7 +1130,7 @@ async function launchLSP(command, args = [], options = {}) {
1025
1130
  setTimeout(() => {
1026
1131
  if (!settled) {
1027
1132
  settled = true;
1028
- resolve3();
1133
+ resolve4();
1029
1134
  }
1030
1135
  }, startupFailureWindowMs);
1031
1136
  });
@@ -1086,7 +1191,7 @@ function recordConfigResolved(cwd, resolution, lspConfig, homeDir, resolveMs) {
1086
1191
  });
1087
1192
  logSessionStart(`config resolved documents=${summary.documents.length} legacy=${legacyDocuments} records=${summary.recordCount} deniedServers=${deniedServers} resolveMs=${resolveMs} session=${sessionId} root=${root}`);
1088
1193
  }
1089
- async function loadLSPConfig(cwd, homeDir = os3.homedir(), options = {}) {
1194
+ async function loadLSPConfig(cwd, homeDir = os4.homedir(), options = {}) {
1090
1195
  const reporting = options.report !== false;
1091
1196
  publishConfigResolutionPending(cwd);
1092
1197
  const resolveStartedAt = Date.now();
@@ -1447,7 +1552,7 @@ async function initLSPConfig(cwd) {
1447
1552
  if (existing)
1448
1553
  return existing;
1449
1554
  const promise = (async () => {
1450
- const config = registerLSPConfig(await loadLSPConfig(cwd, os3.homedir()));
1555
+ const config = registerLSPConfig(await loadLSPConfig(cwd, os4.homedir()));
1451
1556
  forgetConfigResolvedClaims(setSessionRootConfig(normalizedCwd, config));
1452
1557
  })();
1453
1558
  configInFlight.set(normalizedCwd, promise);
@@ -1960,8 +2065,8 @@ function classifyCascadeWaitTier(lspService, filePath, snapshots) {
1960
2065
  }
1961
2066
 
1962
2067
  // dist/clients/lsp/lombok.js
1963
- import * as fs4 from "node:fs";
1964
- import * as os4 from "node:os";
2068
+ import * as fs5 from "node:fs";
2069
+ import * as os5 from "node:os";
1965
2070
  import * as path4 from "node:path";
1966
2071
  var LOMBOK_ENV_KEYS = ["PI_LENS_LOMBOK_JAR", "LOMBOK_JAR"];
1967
2072
  var LOMBOK_PROJECT_FILES = [
@@ -1975,17 +2080,17 @@ function fileExists(filePath) {
1975
2080
  if (!filePath)
1976
2081
  return false;
1977
2082
  try {
1978
- return fs4.statSync(filePath).isFile();
2083
+ return fs5.statSync(filePath).isFile();
1979
2084
  } catch {
1980
2085
  return false;
1981
2086
  }
1982
2087
  }
1983
2088
  function readTextIfSmall(filePath, maxBytes = 512 * 1024) {
1984
2089
  try {
1985
- const stat2 = fs4.statSync(filePath);
2090
+ const stat2 = fs5.statSync(filePath);
1986
2091
  if (!stat2.isFile() || stat2.size > maxBytes)
1987
2092
  return "";
1988
- return fs4.readFileSync(filePath, "utf-8");
2093
+ return fs5.readFileSync(filePath, "utf-8");
1989
2094
  } catch {
1990
2095
  return "";
1991
2096
  }
@@ -2026,7 +2131,7 @@ function newestExistingJar(candidates) {
2026
2131
  let best;
2027
2132
  for (const candidate of candidates) {
2028
2133
  try {
2029
- const stat2 = fs4.statSync(candidate);
2134
+ const stat2 = fs5.statSync(candidate);
2030
2135
  if (!stat2.isFile())
2031
2136
  continue;
2032
2137
  if (!best || stat2.mtimeMs > best.mtimeMs) {
@@ -2037,22 +2142,22 @@ function newestExistingJar(candidates) {
2037
2142
  }
2038
2143
  return best?.filePath;
2039
2144
  }
2040
- function mavenLocalLombokJar(home = os4.homedir()) {
2145
+ function mavenLocalLombokJar(home = os5.homedir()) {
2041
2146
  const base = path4.join(home, ".m2", "repository", "org", "projectlombok", "lombok");
2042
2147
  let versions = [];
2043
2148
  try {
2044
- versions = fs4.readdirSync(base);
2149
+ versions = fs5.readdirSync(base);
2045
2150
  } catch {
2046
2151
  return void 0;
2047
2152
  }
2048
2153
  return newestExistingJar(versions.map((version) => path4.join(base, version, `lombok-${version}.jar`)));
2049
2154
  }
2050
- function gradleCacheLombokJar(home = os4.homedir()) {
2155
+ function gradleCacheLombokJar(home = os5.homedir()) {
2051
2156
  const base = path4.join(home, ".gradle", "caches", "modules-2", "files-2.1", "org.projectlombok", "lombok");
2052
2157
  const candidates = [];
2053
2158
  let versions = [];
2054
2159
  try {
2055
- versions = fs4.readdirSync(base);
2160
+ versions = fs5.readdirSync(base);
2056
2161
  } catch {
2057
2162
  return void 0;
2058
2163
  }
@@ -2060,7 +2165,7 @@ function gradleCacheLombokJar(home = os4.homedir()) {
2060
2165
  const versionDir = path4.join(base, version);
2061
2166
  let hashes = [];
2062
2167
  try {
2063
- hashes = fs4.readdirSync(versionDir);
2168
+ hashes = fs5.readdirSync(versionDir);
2064
2169
  } catch {
2065
2170
  continue;
2066
2171
  }
@@ -2097,7 +2202,7 @@ function createLombokJdtlsArgs(root, baseEnv = process.env) {
2097
2202
 
2098
2203
  // dist/clients/lsp/jvm-runtime.js
2099
2204
  import { existsSync as existsSync2, readdirSync as readdirSync4 } from "node:fs";
2100
- import os5 from "node:os";
2205
+ import os6 from "node:os";
2101
2206
  import path5 from "node:path";
2102
2207
  var JAVA_EXE = process.platform === "win32" ? "java.exe" : "java";
2103
2208
  var JAVA_PROBE_TIMEOUT_MS = 5e3;
@@ -2125,7 +2230,7 @@ function childDirs(base) {
2125
2230
  }
2126
2231
  }
2127
2232
  function candidateRoots() {
2128
- const home = os5.homedir();
2233
+ const home = os6.homedir();
2129
2234
  const roots = [];
2130
2235
  roots.push(path5.join(home, ".jdks"));
2131
2236
  roots.push(path5.join(getGlobalPiLensDir(), "tools"));
@@ -2422,8 +2527,8 @@ function posixFilesystemIsCaseInsensitive(root) {
2422
2527
  const alternatePath = path6.join(path6.dirname(resolved), alternate);
2423
2528
  if (alternate !== name && existsSync3(alternatePath)) {
2424
2529
  try {
2425
- const actual = statSync3(resolved);
2426
- const alternateStat = statSync3(alternatePath);
2530
+ const actual = statSync4(resolved);
2531
+ const alternateStat = statSync4(alternatePath);
2427
2532
  insensitive = actual.dev === alternateStat.dev && actual.ino === alternateStat.ino;
2428
2533
  } catch {
2429
2534
  insensitive = false;
@@ -3017,7 +3122,7 @@ function piAgentExtensionsRootKey(file) {
3017
3122
  return dirKey.slice(0, index + marker.length);
3018
3123
  }
3019
3124
  function IgnoreHomeRoot(primary) {
3020
- const homeKey = normalizeEphemeralMapKey(path6.resolve(os6.homedir()));
3125
+ const homeKey = normalizeEphemeralMapKey(path6.resolve(os7.homedir()));
3021
3126
  return withRootMarkers(async (file) => {
3022
3127
  const root = await primary(file);
3023
3128
  if (!root)
@@ -3027,7 +3132,7 @@ function IgnoreHomeRoot(primary) {
3027
3132
  }
3028
3133
  function rubyBinCandidates(baseName) {
3029
3134
  const candidates = [];
3030
- const home = os6.homedir();
3135
+ const home = os7.homedir();
3031
3136
  const isWin = process.platform === "win32";
3032
3137
  const ext = isWin ? ".bat" : "";
3033
3138
  candidates.push(path6.join(home, ".local", "share", "mise", "installs", "ruby", "bin", `${baseName}${ext}`));
@@ -3084,8 +3189,8 @@ function createInteractiveServer(spec) {
3084
3189
  function PriorityRoot(markerGroups, excludePatterns, stopDir) {
3085
3190
  const resolvers = markerGroups.map((markers) => NearestRoot(markers, excludePatterns, stopDir));
3086
3191
  return withRootMarkers(async (file) => {
3087
- for (const resolve3 of resolvers) {
3088
- const root = await resolve3(file);
3192
+ for (const resolve4 of resolvers) {
3193
+ const root = await resolve4(file);
3089
3194
  if (root)
3090
3195
  return root;
3091
3196
  }
@@ -3198,7 +3303,7 @@ function NearestRoot(includePatterns, excludePatterns, stopDir) {
3198
3303
  }
3199
3304
  }
3200
3305
  for (const pattern of includePatterns) {
3201
- if (await markerExists(currentDir, pattern) && (pattern !== ".git" || currentDir !== os6.tmpdir()) && !await isExcludedLspRoot(currentDir)) {
3306
+ if (await markerExists(currentDir, pattern) && (pattern !== ".git" || currentDir !== os7.tmpdir()) && !await isExcludedLspRoot(currentDir)) {
3202
3307
  return enforceLspRootCeiling(currentDir, process.cwd(), file);
3203
3308
  }
3204
3309
  }
@@ -3246,13 +3351,13 @@ async function findAncestorFile(startDir, ...relativeSegments) {
3246
3351
  return findAncestorFileAmong(startDir, [relativeSegments]);
3247
3352
  }
3248
3353
  async function findAncestorFileAmong(startDir, candidateSegmentLists) {
3249
- const fs5 = await import("node:fs/promises");
3354
+ const fs6 = await import("node:fs/promises");
3250
3355
  let currentDir = path6.resolve(startDir);
3251
3356
  while (!isAtOrAboveHomeDir(currentDir)) {
3252
3357
  for (const segments of candidateSegmentLists) {
3253
3358
  const candidate = path6.join(currentDir, ...segments);
3254
3359
  try {
3255
- await fs5.access(candidate);
3360
+ await fs6.access(candidate);
3256
3361
  return candidate;
3257
3362
  } catch {
3258
3363
  }
@@ -3308,14 +3413,14 @@ async function typescriptVersionForTsc(tscPath) {
3308
3413
  return void 0;
3309
3414
  }
3310
3415
  async function findTsserverPath(root, allowInstall, options) {
3311
- const fs5 = await import("node:fs/promises");
3312
- const projectRoots = await Promise.all([root, options?.sessionRoot ?? process.cwd(), process.cwd()].map((dir) => fs5.realpath(dir).catch(() => path6.resolve(dir))));
3416
+ const fs6 = await import("node:fs/promises");
3417
+ const projectRoots = await Promise.all([root, options?.sessionRoot ?? process.cwd(), process.cwd()].map((dir) => fs6.realpath(dir).catch(() => path6.resolve(dir))));
3313
3418
  const admitCandidate = async (candidate, projectSupplied) => {
3314
3419
  try {
3315
- const real = await fs5.realpath(candidate);
3316
- if (path6.basename(real) !== "tsserver.js" || !(await fs5.stat(real)).isFile())
3420
+ const real = await fs6.realpath(candidate);
3421
+ if (path6.basename(real) !== "tsserver.js" || !(await fs6.stat(real)).isFile())
3317
3422
  return void 0;
3318
- const manifest = JSON.parse(await fs5.readFile(path6.join(path6.dirname(real), "..", "package.json"), "utf8"));
3423
+ const manifest = JSON.parse(await fs6.readFile(path6.join(path6.dirname(real), "..", "package.json"), "utf8"));
3319
3424
  if (typeof manifest?.version !== "string" || !manifest.version)
3320
3425
  return void 0;
3321
3426
  return admitProjectSuppliedTsserver(real, options?.sessionRoot ?? process.cwd(), projectSupplied || projectRoots.some((dir) => isUnderDir(real, dir)), options?.projectCodeAllowed);
@@ -3331,7 +3436,7 @@ async function findTsserverPath(root, allowInstall, options) {
3331
3436
  }
3332
3437
  const cwdCandidate = path6.join(process.cwd(), "node_modules", "typescript", "lib", "tsserver.js");
3333
3438
  try {
3334
- await fs5.access(cwdCandidate);
3439
+ await fs6.access(cwdCandidate);
3335
3440
  const admittedCwd = await admitCandidate(cwdCandidate, false);
3336
3441
  if (admittedCwd)
3337
3442
  return admittedCwd;
@@ -3422,7 +3527,7 @@ async function findNativeTypeScriptLsp(root) {
3422
3527
  return void 0;
3423
3528
  }
3424
3529
  function dotnetToolCandidates(tool) {
3425
- const home = os6.homedir();
3530
+ const home = os7.homedir();
3426
3531
  return [
3427
3532
  path6.join(PI_LENS_BIN_DIR2, `${tool}.exe`),
3428
3533
  path6.join(PI_LENS_BIN_DIR2, tool),
@@ -3435,16 +3540,16 @@ function binExeVariants(dir, tool) {
3435
3540
  return process.platform === "win32" ? [path6.join(dir, `${tool}.exe`), path6.join(dir, tool)] : [path6.join(dir, tool)];
3436
3541
  }
3437
3542
  function goBinCandidates(tool) {
3438
- const gopath = process.env.GOPATH?.split(path6.delimiter)[0] || path6.join(os6.homedir(), "go");
3543
+ const gopath = process.env.GOPATH?.split(path6.delimiter)[0] || path6.join(os7.homedir(), "go");
3439
3544
  return [tool, ...binExeVariants(path6.join(gopath, "bin"), tool)];
3440
3545
  }
3441
3546
  function cargoBinCandidates(tool) {
3442
- const cargoHome = process.env.CARGO_HOME || path6.join(os6.homedir(), ".cargo");
3547
+ const cargoHome = process.env.CARGO_HOME || path6.join(os7.homedir(), ".cargo");
3443
3548
  return [tool, ...binExeVariants(path6.join(cargoHome, "bin"), tool)];
3444
3549
  }
3445
3550
  async function tryGemInstall(gem) {
3446
- const { join: join3 } = await import("node:path");
3447
- const binDir = join3(getGlobalPiLensDir(), "bin");
3551
+ const { join: join4 } = await import("node:path");
3552
+ const binDir = join4(getGlobalPiLensDir(), "bin");
3448
3553
  const { mkdir } = await import("node:fs/promises");
3449
3554
  await mkdir(binDir, { recursive: true });
3450
3555
  const result = await safeSpawnAsync("gem", ["install", gem, "--bindir", binDir, "--no-document"], { timeout: 18e4, ignoreAmbientSignal: true });
@@ -5062,6 +5167,9 @@ export {
5062
5167
  registerRunnerId,
5063
5168
  withLspProjectCodePermission,
5064
5169
  refuseUntrustedLspExecution,
5170
+ resolveAnalysisRootPath,
5171
+ resolveAnalysisRoot,
5172
+ canWriteAnalysisRoot,
5065
5173
  BUILTIN_SERVER_RUNNER_COVERS,
5066
5174
  describeRootFallback,
5067
5175
  resolveLspServerCwd,