pi-lens 4.4.3 → 4.4.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.
Files changed (143) hide show
  1. package/CHANGELOG.md +281 -0
  2. package/README.md +13 -1
  3. package/dist/{chunk-SS36ZX4J.js → chunk-24AKHFGP.js} +6 -6
  4. package/dist/{chunk-JSQFTSC6.js → chunk-2FN63LPV.js} +11 -11
  5. package/dist/{chunk-5UCAH366.js → chunk-2KXTHF3M.js} +20 -20
  6. package/dist/{chunk-EU63SDCG.js → chunk-3DA2JDOL.js} +367 -281
  7. package/dist/{chunk-RWWYJ623.js → chunk-3KAZU3VR.js} +1 -1
  8. package/dist/chunk-3PTHXJXR.js +28 -0
  9. package/dist/chunk-3QED2P4V.js +31 -0
  10. package/dist/{chunk-N2H3ZPZY.js → chunk-3RKP3FMS.js} +1 -0
  11. package/dist/{chunk-XVF2VVXP.js → chunk-5HSRT26B.js} +2 -2
  12. package/dist/{chunk-MXGY6KPT.js → chunk-5IUSNGOC.js} +15 -15
  13. package/dist/{chunk-EJIUXPBX.js → chunk-5OFV52AM.js} +1 -1
  14. package/dist/{chunk-AW7R2GWG.js → chunk-5VSF4UUQ.js} +12 -7
  15. package/dist/{chunk-6STA6Z7I.js → chunk-5WRPDP2A.js} +18 -18
  16. package/dist/{chunk-YIUAVF7E.js → chunk-6DLWKFEX.js} +35 -34
  17. package/dist/{chunk-WOA4LN2R.js → chunk-7D6L4MTX.js} +2 -2
  18. package/dist/{chunk-GAEGEPOC.js → chunk-7HXE67BN.js} +2 -2
  19. package/dist/chunk-AGSS7277.js +84 -0
  20. package/dist/{chunk-R3PCY3YS.js → chunk-AMERCH6V.js} +13 -13
  21. package/dist/{chunk-WU567RSC.js → chunk-ATKJFDQN.js} +14 -10
  22. package/dist/{chunk-VSSBEUFT.js → chunk-AWSCPCN2.js} +16 -16
  23. package/dist/{chunk-VCHXCQFG.js → chunk-BWD5EPKO.js} +3 -3
  24. package/dist/{chunk-H6MF6EVN.js → chunk-CT4MN5IU.js} +1200 -230
  25. package/dist/{chunk-FCSOVF55.js → chunk-CUHSHSB6.js} +6 -6
  26. package/dist/{chunk-CHOW74WE.js → chunk-CYRKQRPM.js} +7 -10
  27. package/dist/{chunk-Q7DUK4LX.js → chunk-DEL2U6CM.js} +5 -5
  28. package/dist/{chunk-6C7JWPCP.js → chunk-DGUKIYSI.js} +26 -23
  29. package/dist/{chunk-PHDMFAKM.js → chunk-DUO2TU77.js} +2 -2
  30. package/dist/{chunk-MRXKYPCS.js → chunk-EBC36LNN.js} +2 -2
  31. package/dist/{chunk-CSHFH5IN.js → chunk-ED36RF6Y.js} +1 -1
  32. package/dist/{chunk-76MWC2K6.js → chunk-EUXZEFTV.js} +90 -97
  33. package/dist/{chunk-QOZXJ4NA.js → chunk-FM4RDMKT.js} +11 -8
  34. package/dist/{chunk-ACXEQZOU.js → chunk-GAQ7OQG6.js} +31 -28
  35. package/dist/{chunk-XAGLWMJ4.js → chunk-GL5LUMZE.js} +23 -23
  36. package/dist/{chunk-BKE7E7TC.js → chunk-GMX5OS7B.js} +9 -9
  37. package/dist/{chunk-ZHFZWTZV.js → chunk-GSLNCYGG.js} +11 -11
  38. package/dist/{chunk-3W7IEVVL.js → chunk-GSM5UU7A.js} +26 -34
  39. package/dist/{chunk-724UL2TJ.js → chunk-GXFV6MYU.js} +3 -3
  40. package/dist/chunk-HAD7QRQI.js +30 -0
  41. package/dist/{chunk-QOBUHWHX.js → chunk-HRNHZA3N.js} +6 -6
  42. package/dist/{chunk-VWCXW2E7.js → chunk-HWCCCQNX.js} +1 -1
  43. package/dist/{chunk-7DYBLXYA.js → chunk-HYGZEMX6.js} +3 -3
  44. package/dist/chunk-IJYGIDF4.js +186 -0
  45. package/dist/{chunk-4W4VLAPJ.js → chunk-IQWN5JCP.js} +11 -11
  46. package/dist/{chunk-SQ4TVJBR.js → chunk-IUE7SSKV.js} +7 -7
  47. package/dist/{chunk-IBGIOBEE.js → chunk-IWDLU6K3.js} +68 -5
  48. package/dist/{chunk-XCJN5IJU.js → chunk-IYNJ6YPZ.js} +4 -4
  49. package/dist/{chunk-JAU72XNY.js → chunk-J64T55EI.js} +3 -3
  50. package/dist/{chunk-2BBLFX75.js → chunk-J6MPGQTS.js} +5 -5
  51. package/dist/chunk-JORED7EX.js +44 -0
  52. package/dist/{chunk-6SDEP3AJ.js → chunk-JUKMK5Y4.js} +8 -8
  53. package/dist/{chunk-FMSO6RDZ.js → chunk-JW3YWBVB.js} +15 -15
  54. package/dist/{chunk-L3BLXZG7.js → chunk-KAPJINKN.js} +30 -69
  55. package/dist/{chunk-2B73ZPOK.js → chunk-KN35K52N.js} +3 -3
  56. package/dist/{chunk-C34ZXZ7O.js → chunk-KUA4OJ5Y.js} +24 -11
  57. package/dist/chunk-KYUB6QDC.js +72 -0
  58. package/dist/{chunk-67WMNWEE.js → chunk-LLJNQKQW.js} +12 -10
  59. package/dist/chunk-LZSEQW6A.js +57 -0
  60. package/dist/{chunk-ZANLILYD.js → chunk-M2IFVFWU.js} +2 -2
  61. package/dist/chunk-M2UD3LPU.js +88 -0
  62. package/dist/{chunk-XIJZVPD5.js → chunk-MBKQHGA7.js} +15 -15
  63. package/dist/{chunk-P7266HLM.js → chunk-MPNJLASA.js} +2 -2
  64. package/dist/{chunk-6GFRNVYR.js → chunk-MZGQNL3Y.js} +10 -10
  65. package/dist/{chunk-ZWFS3OEF.js → chunk-N5FLEO7W.js} +33 -32
  66. package/dist/{chunk-3JNKMP3B.js → chunk-O4NWQT6I.js} +4 -4
  67. package/dist/{chunk-T6CPIZNT.js → chunk-OHKJ7PQF.js} +33 -32
  68. package/dist/{chunk-VRZP76YM.js → chunk-P63GXC37.js} +4 -1
  69. package/dist/{chunk-XTMJ7XDT.js → chunk-POMLXPMY.js} +1 -1
  70. package/dist/{chunk-QQNQ7SJW.js → chunk-QBFBRV2B.js} +10 -4
  71. package/dist/{chunk-CMMHNUZ2.js → chunk-R3T7CLQ2.js} +60 -38
  72. package/dist/{chunk-23WOO7TX.js → chunk-R7YOCSNV.js} +10 -10
  73. package/dist/{chunk-2CD5RS6M.js → chunk-RKBXZN3A.js} +23 -2
  74. package/dist/{chunk-OCAGUNBC.js → chunk-RKKOYPRA.js} +12 -12
  75. package/dist/{chunk-52FUZI6K.js → chunk-RMLC67LF.js} +1 -1
  76. package/dist/{chunk-XMSXXAHW.js → chunk-ROYSX2S5.js} +2 -2
  77. package/dist/{chunk-M6HSLBWY.js → chunk-RVK72CZX.js} +6507 -7514
  78. package/dist/{chunk-FLKWCIZH.js → chunk-S2HEXIWI.js} +5 -5
  79. package/dist/{chunk-UZ3TUTRV.js → chunk-S67KYG37.js} +1 -1
  80. package/dist/{chunk-VCO24T4L.js → chunk-SD4I7ZO4.js} +14 -14
  81. package/dist/{chunk-Z527N6YQ.js → chunk-SKAMFC7A.js} +12 -12
  82. package/dist/{chunk-MQLUAEOC.js → chunk-SRYEJNES.js} +2 -2
  83. package/dist/{chunk-BRGDSBJE.js → chunk-SYE6T2EB.js} +12 -12
  84. package/dist/{chunk-GXW6K4YJ.js → chunk-T57LYLZT.js} +1 -1
  85. package/dist/{chunk-ZXYDQ3TZ.js → chunk-T7FEBKXN.js} +48 -15
  86. package/dist/{chunk-3EFKIGZN.js → chunk-TIQ2PKDW.js} +3 -3
  87. package/dist/{chunk-QILIYSJF.js → chunk-TLX72JTG.js} +1 -1
  88. package/dist/{chunk-TYM6OUIT.js → chunk-TOY6QKOH.js} +12 -12
  89. package/dist/{chunk-IZSHAIJ7.js → chunk-TRETHTQO.js} +12 -12
  90. package/dist/{chunk-3VPVG5SU.js → chunk-U44DJXQP.js} +10 -6
  91. package/dist/{chunk-PNQDPDRC.js → chunk-UA7ZXYDR.js} +1 -1
  92. package/dist/{chunk-OXXKQCSV.js → chunk-UBOQLVT2.js} +4 -4
  93. package/dist/{chunk-QGQ5CCCG.js → chunk-UMS2MFPZ.js} +2 -2
  94. package/dist/{chunk-QHJ6DQ2R.js → chunk-US7ECLD7.js} +55 -13
  95. package/dist/{chunk-AB3YYG6N.js → chunk-UZ2XCLYS.js} +8 -8
  96. package/dist/chunk-V35JG4JB.js +2667 -0
  97. package/dist/{chunk-N3X6Q4YT.js → chunk-VOOAPROD.js} +3 -3
  98. package/dist/{chunk-SAEFPSB6.js → chunk-W66O5E25.js} +21 -11
  99. package/dist/{chunk-KBG47GHP.js → chunk-WMYE35PX.js} +15 -11
  100. package/dist/{chunk-5NGR67U5.js → chunk-XBJVAEEO.js} +32 -5
  101. package/dist/{chunk-YYOIQFRS.js → chunk-XHJBS436.js} +122 -44
  102. package/dist/{chunk-GBPP5P7X.js → chunk-XTBDCR27.js} +4 -4
  103. package/dist/{chunk-4UNXBNE2.js → chunk-XTFDJI3T.js} +11 -11
  104. package/dist/{chunk-UXGETRP4.js → chunk-XYURS6EN.js} +13 -12
  105. package/dist/{chunk-RPLINGVB.js → chunk-Y6GZHWSJ.js} +6 -6
  106. package/dist/{chunk-2VUQMUMT.js → chunk-YCWYO6TQ.js} +41 -38
  107. package/dist/{chunk-77M37OKR.js → chunk-YH5MVY2U.js} +7 -7
  108. package/dist/{chunk-AOHZU2BM.js → chunk-YNE3RP52.js} +1 -1
  109. package/dist/{chunk-YSZNHOBY.js → chunk-ZHH37KZL.js} +12 -12
  110. package/dist/{chunk-ZGDGW2V3.js → chunk-ZIVJBOO3.js} +2 -2
  111. package/dist/{chunk-RXCOMYPY.js → chunk-ZVUL7QYY.js} +29 -28
  112. package/dist/index.js +11052 -5852
  113. package/dist/mcp/analyze-cli.js +10 -9
  114. package/dist/mcp/cli.js +41 -38
  115. package/dist/mcp/server.js +1120 -474
  116. package/dist/mcp/worker.js +61 -58
  117. package/dist/probes/installer.js +19 -19
  118. package/dist/workers/project-snapshot-persist-worker.js +28 -9
  119. package/dist/workers/review-graph-persist-worker.js +1 -1
  120. package/docs/configuration.md +11 -0
  121. package/docs/engineering-principles.md +32 -0
  122. package/docs/lsp-capability-matrix.md +1 -1
  123. package/docs/lsp-idle-eviction.md +15 -26
  124. package/docs/pi-lens-fixer.md +117 -13
  125. package/docs/pi-lens-merge-policy.md +97 -7
  126. package/docs/pi-lens-monitor.md +8 -2
  127. package/docs/pi-lens-retro.md +4 -1
  128. package/docs/pi-lens-reviewer.md +112 -4
  129. package/docs/pi-lens-subagent.md +22 -14
  130. package/docs/release-qa-baseline.md +3 -1
  131. package/docs/servercapabilities.md +9 -19
  132. package/package.json +7 -5
  133. package/scripts/download-grammars.js +40 -7
  134. package/scripts/lib/latency-log-phases.mjs +95 -0
  135. package/scripts/rpc-load-check.mjs +570 -81
  136. package/dist/chunk-3YN6V5TV.js +0 -85
  137. package/dist/chunk-466Z26MG.js +0 -30
  138. package/dist/chunk-EC47DWFA.js +0 -56
  139. package/dist/chunk-KDERNTCQ.js +0 -28
  140. package/dist/chunk-KSX3TXSZ.js +0 -69
  141. package/dist/chunk-LOP6GRPH.js +0 -31
  142. package/dist/chunk-UOPVJQ4N.js +0 -103
  143. /package/dist/{chunk-FC4RP4I2.js → chunk-6HWVI6MI.js} +0 -0
@@ -1,36 +1,36 @@
1
1
  import { createRequire as __pilensCreateRequire } from "node:module"; const require = __pilensCreateRequire(import.meta.url);
2
2
  import {
3
3
  resolveOpengrepConfig
4
- } from "./chunk-VWCXW2E7.js";
4
+ } from "./chunk-HWCCCQNX.js";
5
5
  import {
6
6
  augmentPythonEnvironment,
7
7
  detectPythonEnvironment,
8
8
  detectPythonVenv,
9
9
  pythonEnvironmentToolCandidates
10
- } from "./chunk-FCSOVF55.js";
10
+ } from "./chunk-CUHSHSB6.js";
11
11
  import {
12
12
  resolveGitCheckout,
13
13
  resolveLinkedWorktreeOwner
14
- } from "./chunk-PNQDPDRC.js";
14
+ } from "./chunk-UA7ZXYDR.js";
15
+ import {
16
+ hasCargoWorkspaceTable,
17
+ readCargoWorkspaceExclude,
18
+ readCargoWorkspaceMembers,
19
+ readTextFileOrUndefined
20
+ } from "./chunk-MPNJLASA.js";
15
21
  import {
16
22
  extensionsForLanguage,
17
23
  getUserRuleRoot,
18
24
  ruleCorpusFingerprintForCycle
19
- } from "./chunk-724UL2TJ.js";
25
+ } from "./chunk-GXFV6MYU.js";
20
26
  import {
21
27
  load,
22
28
  resolvePackagePath
23
- } from "./chunk-QOZXJ4NA.js";
24
- import {
25
- hasCargoWorkspaceTable,
26
- readCargoWorkspaceExclude,
27
- readCargoWorkspaceMembers,
28
- readTextFileOrUndefined
29
- } from "./chunk-P7266HLM.js";
29
+ } from "./chunk-FM4RDMKT.js";
30
30
  import {
31
31
  HOOK_WALL_BUDGET_MS,
32
32
  bounded
33
- } from "./chunk-52FUZI6K.js";
33
+ } from "./chunk-RMLC67LF.js";
34
34
  import {
35
35
  ensureTool,
36
36
  findManagedToolBinary,
@@ -40,27 +40,29 @@ import {
40
40
  isZizmorAuditTarget,
41
41
  logSessionStart,
42
42
  resolveZizmorGitHubToken
43
- } from "./chunk-ACXEQZOU.js";
43
+ } from "./chunk-GAQ7OQG6.js";
44
44
  import {
45
45
  resolveToolCwd
46
- } from "./chunk-Q7DUK4LX.js";
46
+ } from "./chunk-DEL2U6CM.js";
47
47
  import {
48
+ commandSearchReachesProject,
48
49
  findGlobalBinary,
49
50
  isProjectLocalBinPath
50
- } from "./chunk-AW7R2GWG.js";
51
+ } from "./chunk-5VSF4UUQ.js";
51
52
  import {
52
53
  classifyProbeFailure,
53
54
  createAvailabilityLatch,
54
55
  describeInstallAttempt,
55
56
  logAvailabilityDecision,
56
57
  startHostStallSampler
57
- } from "./chunk-VRZP76YM.js";
58
+ } from "./chunk-P63GXC37.js";
58
59
  import {
59
60
  OWNER_TAG_ENV,
60
61
  SpawnFailureError,
61
62
  classifySpawnFailure,
62
63
  createGenerationSource,
63
64
  ephemeralStagingRoot,
65
+ findCommandAsync,
64
66
  getGlobalPiLensDir,
65
67
  getProjectIgnoreGlobs,
66
68
  hasSpawnFailureKind,
@@ -71,13 +73,13 @@ import {
71
73
  ownerTagForChildren,
72
74
  resolveWindowsCommandForEnvironment,
73
75
  safeSpawnAsync
74
- } from "./chunk-C34ZXZ7O.js";
76
+ } from "./chunk-KUA4OJ5Y.js";
75
77
  import {
76
78
  DOTNET_CSHARP_ROOT_MARKERS,
77
79
  DOTNET_FSHARP_ROOT_MARKERS,
78
80
  KIND_EXTENSIONS,
79
81
  LEAN_ROOT_MARKERS
80
- } from "./chunk-PHDMFAKM.js";
82
+ } from "./chunk-DUO2TU77.js";
81
83
  import {
82
84
  isRepoTier,
83
85
  lspSectionOf,
@@ -87,7 +89,7 @@ import {
87
89
  reportPiLensConfigRecords,
88
90
  resolvePiLensConfig,
89
91
  summarizeConfigResolution
90
- } from "./chunk-2BBLFX75.js";
92
+ } from "./chunk-J6MPGQTS.js";
91
93
  import {
92
94
  FRESHNESS_CADENCE_MS,
93
95
  LSP_NAMESPACE_KEY,
@@ -95,30 +97,30 @@ import {
95
97
  dirMtimesStillFreshAsync,
96
98
  getPiLensGlobalConfigPath,
97
99
  unknownDirMtimeRecords
98
- } from "./chunk-XVF2VVXP.js";
100
+ } from "./chunk-5HSRT26B.js";
99
101
  import {
100
102
  getProjectTrustState
101
- } from "./chunk-ZANLILYD.js";
103
+ } from "./chunk-M2IFVFWU.js";
102
104
  import {
103
105
  getDegradationLedgerGeneration,
104
106
  incrementDegradationCount,
105
107
  recordDegradationOnce
106
- } from "./chunk-JAU72XNY.js";
108
+ } from "./chunk-J64T55EI.js";
107
109
  import {
108
110
  logExtension
109
- } from "./chunk-XTMJ7XDT.js";
111
+ } from "./chunk-POMLXPMY.js";
110
112
  import {
111
113
  claimPhaseOncePerSession,
112
114
  currentSessionRecordId,
113
115
  logLatency,
114
116
  releasePhaseClaim
115
- } from "./chunk-QQNQ7SJW.js";
117
+ } from "./chunk-QBFBRV2B.js";
116
118
  import {
117
119
  getGlobalPiLensLogDir,
118
120
  getProcessSingleton,
119
121
  isTestMode,
120
122
  redactSecrets
121
- } from "./chunk-AOHZU2BM.js";
123
+ } from "./chunk-YNE3RP52.js";
122
124
  import {
123
125
  STAGE_TMP_PATTERN
124
126
  } from "./chunk-LJDODBBZ.js";
@@ -141,7 +143,7 @@ import {
141
143
  normalizeMapKey,
142
144
  pathsEqual,
143
145
  toPosix
144
- } from "./chunk-N2H3ZPZY.js";
146
+ } from "./chunk-3RKP3FMS.js";
145
147
  import {
146
148
  __require
147
149
  } from "./chunk-NXL4FFQQ.js";
@@ -245,17 +247,45 @@ function canWriteAnalysisRoot(mode) {
245
247
  return mode === "session" || mode === "linked-worktree";
246
248
  }
247
249
 
250
+ // dist/clients/lsp/file-server-match.js
251
+ import path from "node:path";
252
+ function fileMatchKeys(filePath) {
253
+ return {
254
+ ext: path.extname(filePath).toLowerCase(),
255
+ base: path.basename(filePath).toLowerCase()
256
+ };
257
+ }
258
+ function fileMatchReason(server, filePath, ext, base) {
259
+ let matched = false;
260
+ for (const value of server.extensions) {
261
+ const lower = value.toLowerCase();
262
+ if (lower === ext || lower === base) {
263
+ matched = true;
264
+ break;
265
+ }
266
+ }
267
+ if (!matched)
268
+ return "extension-mismatch";
269
+ if (server.pathFilter && !server.pathFilter(filePath))
270
+ return "path-filter";
271
+ return "selected";
272
+ }
273
+ function registeredServers(config, catalog) {
274
+ const builtins = config.registeredServers.length ? config.registeredServers : catalog;
275
+ return [...builtins, ...config.customServers];
276
+ }
277
+
248
278
  // dist/clients/lsp/server.js
249
279
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, statSync as statSync4 } from "node:fs";
250
- import { access, readFile, readdir, stat } from "node:fs/promises";
280
+ import { access, readFile, readdir, realpath, stat } from "node:fs/promises";
251
281
  import os7 from "node:os";
252
- import path6 from "node:path";
282
+ import path7 from "node:path";
253
283
 
254
284
  // dist/clients/sgconfig.js
255
285
  import { createHash } from "node:crypto";
256
286
  import * as fs2 from "node:fs";
257
287
  import * as os2 from "node:os";
258
- import * as path from "node:path";
288
+ import * as path2 from "node:path";
259
289
  var SGCONFIG_NAMES = ["sgconfig.yml", "sgconfig.yaml"];
260
290
  function findLocalSgconfig(startDir) {
261
291
  return findLocalToolConfig(startDir, SGCONFIG_NAMES);
@@ -264,20 +294,20 @@ function canonicalDir(dir) {
264
294
  try {
265
295
  return fs2.realpathSync.native(dir);
266
296
  } catch {
267
- return path.resolve(dir);
297
+ return path2.resolve(dir);
268
298
  }
269
299
  }
270
300
  function getAstGrepRuleSources(projectRoot = process.cwd()) {
271
- const root = path.resolve(projectRoot || process.cwd());
301
+ const root = path2.resolve(projectRoot || process.cwd());
272
302
  const packageRoot = resolvePackagePath(import.meta.url);
273
303
  const candidates = [];
274
304
  if (canonicalDir(root) !== canonicalDir(packageRoot)) {
275
305
  candidates.push({
276
- dir: path.join(root, "rules", "ast-grep-rules", "rules"),
306
+ dir: path2.join(root, "rules", "ast-grep-rules", "rules"),
277
307
  origin: "project",
278
308
  tier: "primary"
279
309
  }, {
280
- dir: path.join(root, "rules", "ast-grep-rules", "coderabbit", "rules"),
310
+ dir: path2.join(root, "rules", "ast-grep-rules", "coderabbit", "rules"),
281
311
  origin: "project",
282
312
  tier: "secondary"
283
313
  });
@@ -285,21 +315,21 @@ function getAstGrepRuleSources(projectRoot = process.cwd()) {
285
315
  const userRoot = getUserRuleRoot();
286
316
  if (canonicalDir(userRoot) !== canonicalDir(root)) {
287
317
  candidates.push({
288
- dir: path.join(userRoot, "ast-grep-rules", "rules"),
318
+ dir: path2.join(userRoot, "ast-grep-rules", "rules"),
289
319
  origin: "user",
290
320
  tier: "primary"
291
321
  }, {
292
- dir: path.join(userRoot, "ast-grep-rules", "coderabbit", "rules"),
322
+ dir: path2.join(userRoot, "ast-grep-rules", "coderabbit", "rules"),
293
323
  origin: "user",
294
324
  tier: "secondary"
295
325
  });
296
326
  }
297
327
  candidates.push({
298
- dir: path.join(packageRoot, "rules", "ast-grep-rules", "rules"),
328
+ dir: path2.join(packageRoot, "rules", "ast-grep-rules", "rules"),
299
329
  origin: "bundled",
300
330
  tier: "primary"
301
331
  }, {
302
- dir: path.join(packageRoot, "rules", "ast-grep-rules", "coderabbit", "rules"),
332
+ dir: path2.join(packageRoot, "rules", "ast-grep-rules", "coderabbit", "rules"),
303
333
  origin: "bundled",
304
334
  tier: "secondary"
305
335
  });
@@ -323,7 +353,7 @@ function findYamlFiles(dir) {
323
353
  return files;
324
354
  }
325
355
  for (const entry of entries) {
326
- const full = path.join(dir, entry.name);
356
+ const full = path2.join(dir, entry.name);
327
357
  if (entry.isDirectory()) {
328
358
  files.push(...findYamlFiles(full));
329
359
  } else if (entry.isFile() && /\.ya?ml$/i.test(entry.name)) {
@@ -365,7 +395,7 @@ function snapshotRuleSource(source) {
365
395
  const hash = createHash("sha256");
366
396
  const files = [];
367
397
  for (const file of findYamlFiles(source.dir)) {
368
- const relativePath = path.relative(source.dir, file);
398
+ const relativePath = path2.relative(source.dir, file);
369
399
  hash.update(relativePath);
370
400
  hash.update("\0");
371
401
  let content;
@@ -408,7 +438,7 @@ function sourceFingerprint(sources) {
408
438
  return hash.digest("hex");
409
439
  }
410
440
  function getAstGrepRuleFingerprint(projectRoot = process.cwd(), options = {}) {
411
- const root = path.resolve(projectRoot || process.cwd());
441
+ const root = path2.resolve(projectRoot || process.cwd());
412
442
  return ruleCorpusFingerprintForCycle("ast-grep", root, (fingerprintRoot) => sourceFingerprint(getAstGrepRuleSources(fingerprintRoot).map(snapshotRuleSource)), options.force);
413
443
  }
414
444
  function materializeMergedRuleDir(sources, mergedDir) {
@@ -428,7 +458,7 @@ function materializeMergedRuleDir(sources, mergedDir) {
428
458
  });
429
459
  if (survivingDocuments.length === 0)
430
460
  continue;
431
- const destination = path.join(mergedDir, `source${sourceIndex}-${String(fileIndex).padStart(5, "0")}.yml`);
461
+ const destination = path2.join(mergedDir, `source${sourceIndex}-${String(fileIndex).padStart(5, "0")}.yml`);
432
462
  if (survivingDocuments.length === file.documents.length) {
433
463
  fs2.copyFileSync(file.file, destination);
434
464
  } else {
@@ -445,7 +475,7 @@ function rootArtifactKey(root) {
445
475
  return createHash("sha256").update(root).digest("hex").slice(0, 12);
446
476
  }
447
477
  function resolveBaselineSgconfig(projectRoot = process.cwd()) {
448
- const root = canonicalDir(path.resolve(projectRoot || process.cwd()));
478
+ const root = canonicalDir(path2.resolve(projectRoot || process.cwd()));
449
479
  const fingerprint = getAstGrepRuleFingerprint(root, { force: true });
450
480
  const cached = cachedBaselines.get(root);
451
481
  if (cached?.fingerprint === fingerprint && fs2.existsSync(cached.path) && fs2.existsSync(cached.mergedDir)) {
@@ -454,11 +484,11 @@ function resolveBaselineSgconfig(projectRoot = process.cwd()) {
454
484
  const sources = getAstGrepRuleSources(root).map(snapshotRuleSource);
455
485
  if (sources.length === 0)
456
486
  return void 0;
457
- const dir = path.join(os2.tmpdir(), "pi-lens-ast-grep");
487
+ const dir = path2.join(os2.tmpdir(), "pi-lens-ast-grep");
458
488
  fs2.mkdirSync(dir, { recursive: true });
459
489
  const artifactKey = rootArtifactKey(root);
460
- const file = path.join(dir, `baseline-${process.pid}-${artifactKey}.sgconfig.yml`);
461
- const mergedDir = path.join(dir, `baseline-${process.pid}-${artifactKey}.rules`);
490
+ const file = path2.join(dir, `baseline-${process.pid}-${artifactKey}.sgconfig.yml`);
491
+ const mergedDir = path2.join(dir, `baseline-${process.pid}-${artifactKey}.rules`);
462
492
  const protectedArtifacts = /* @__PURE__ */ new Set([file, mergedDir]);
463
493
  for (const baseline of cachedBaselines.values()) {
464
494
  protectedArtifacts.add(baseline.path);
@@ -466,7 +496,7 @@ function resolveBaselineSgconfig(projectRoot = process.cwd()) {
466
496
  }
467
497
  cleanupStaleBaselines(dir, protectedArtifacts);
468
498
  materializeMergedRuleDir(sources, mergedDir);
469
- const ruleDirForYaml = mergedDir.split(path.sep).join("/");
499
+ const ruleDirForYaml = mergedDir.split(path2.sep).join("/");
470
500
  fs2.writeFileSync(file, `ruleDirs:
471
501
  - ${JSON.stringify(ruleDirForYaml)}
472
502
  `);
@@ -488,7 +518,7 @@ function enforceBaselineEntryCap(dir, keep) {
488
518
  const isMergedDir = /^baseline-\d+(?:-[a-f0-9]+)?\.rules$/.test(name);
489
519
  if (!isConfig && !isMergedDir)
490
520
  continue;
491
- const full = path.join(dir, name);
521
+ const full = path2.join(dir, name);
492
522
  if (keep.has(full))
493
523
  continue;
494
524
  try {
@@ -536,7 +566,7 @@ function cleanupStaleBaselines(dir, keep) {
536
566
  const isMergedDir = /^baseline-\d+(?:-[a-f0-9]+)?\.rules$/.test(name);
537
567
  if (!isConfig && !isMergedDir)
538
568
  continue;
539
- const full = path.join(dir, name);
569
+ const full = path2.join(dir, name);
540
570
  if (keep.has(full))
541
571
  continue;
542
572
  try {
@@ -598,7 +628,7 @@ function serverTraits(declaration) {
598
628
 
599
629
  // dist/clients/lsp/config.js
600
630
  import * as os4 from "node:os";
601
- import path3 from "node:path";
631
+ import path4 from "node:path";
602
632
 
603
633
  // dist/clients/dispatch/known-runner-ids.js
604
634
  var knownRunnerIds = /* @__PURE__ */ new Set();
@@ -617,7 +647,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
617
647
  import { execFileSync, spawn as nodeSpawn } from "node:child_process";
618
648
  import fs4 from "node:fs";
619
649
  import os3 from "node:os";
620
- import path2 from "node:path";
650
+ import path3 from "node:path";
621
651
 
622
652
  // dist/clients/lsp/ruby-drive-dirs.js
623
653
  import * as fs3 from "node:fs";
@@ -667,9 +697,9 @@ function computeNeedsShell(resolvedCommand) {
667
697
  var DEFAULT_STARTUP_FAILURE_WINDOW_MS = 50;
668
698
  var WINDOWS_NAV_STARTUP_FAILURE_WINDOW_MS = 500;
669
699
  var SESSIONSTART_LOG_DIR = getGlobalPiLensLogDir();
670
- var SESSIONSTART_LOG = path2.join(SESSIONSTART_LOG_DIR, "sessionstart.log");
671
- var PI_LENS_BIN_DIR = path2.join(getGlobalPiLensDir(), "bin");
672
- var PI_LENS_TOOLS_BIN_DIR = path2.join(getGlobalPiLensDir(), "tools", "node_modules", ".bin");
700
+ var SESSIONSTART_LOG = path3.join(SESSIONSTART_LOG_DIR, "sessionstart.log");
701
+ var PI_LENS_BIN_DIR = path3.join(getGlobalPiLensDir(), "bin");
702
+ var PI_LENS_TOOLS_BIN_DIR = path3.join(getGlobalPiLensDir(), "tools", "node_modules", ".bin");
673
703
  function logSessionStart2(msg) {
674
704
  if (isTestMode()) {
675
705
  return;
@@ -698,8 +728,8 @@ function splitPathEntries(value, delimiter) {
698
728
  }
699
729
  function normalizePathEntry(entry, platform) {
700
730
  if (platform !== "win32")
701
- return path2.posix.normalize(entry);
702
- return path2.win32.normalize(entry).toLowerCase();
731
+ return path3.posix.normalize(entry);
732
+ return path3.win32.normalize(entry).toLowerCase();
703
733
  }
704
734
  function combinePathValuesForPlatform(values, platform = process.platform) {
705
735
  const unique = [];
@@ -754,27 +784,27 @@ function getLiveWindowsPath() {
754
784
  }
755
785
  async function buildAugmentedPath(basePath) {
756
786
  const candidates = [];
757
- const nodeDir = path2.dirname(process.execPath);
787
+ const nodeDir = path3.dirname(process.execPath);
758
788
  if (nodeDir) {
759
789
  candidates.push(nodeDir);
760
790
  }
761
791
  if (isWindows) {
762
792
  const home = os3.homedir();
763
- const driveRoot = path2.parse(home).root;
764
- candidates.push(path2.join(home, ".cargo", "bin"));
765
- candidates.push(path2.join(home, "go", "bin"));
766
- candidates.push(path2.join(home, ".dotnet", "tools"));
793
+ const driveRoot = path3.parse(home).root;
794
+ candidates.push(path3.join(home, ".cargo", "bin"));
795
+ candidates.push(path3.join(home, "go", "bin"));
796
+ candidates.push(path3.join(home, ".dotnet", "tools"));
767
797
  candidates.push(PI_LENS_BIN_DIR);
768
798
  candidates.push(PI_LENS_TOOLS_BIN_DIR);
769
- candidates.push(path2.join(driveRoot, "Program Files", "Go", "bin"));
770
- candidates.push(path2.join(driveRoot, "Go", "bin"));
799
+ candidates.push(path3.join(driveRoot, "Program Files", "Go", "bin"));
800
+ candidates.push(path3.join(driveRoot, "Go", "bin"));
771
801
  for (const entry of await getRubyVersionDirNamesAsync(driveRoot)) {
772
- candidates.push(path2.join(driveRoot, entry, "bin"));
802
+ candidates.push(path3.join(driveRoot, entry, "bin"));
773
803
  }
774
804
  }
775
805
  const effectiveBase = isWindows ? combinePathValuesForPlatform([basePath, getLiveWindowsPath()]) : basePath;
776
806
  const existing = /* @__PURE__ */ new Set();
777
- for (const entry of splitPathEntries(effectiveBase, path2.delimiter)) {
807
+ for (const entry of splitPathEntries(effectiveBase, path3.delimiter)) {
778
808
  if (!entry)
779
809
  continue;
780
810
  existing.add(normalizePathEntry(entry, process.platform));
@@ -792,8 +822,8 @@ async function buildAugmentedPath(basePath) {
792
822
  if (toAppend.length === 0)
793
823
  return basePath ?? "";
794
824
  if (!basePath)
795
- return toAppend.join(path2.delimiter);
796
- return `${basePath}${path2.delimiter}${toAppend.join(path2.delimiter)}`;
825
+ return toAppend.join(path3.delimiter);
826
+ return `${basePath}${path3.delimiter}${toAppend.join(path3.delimiter)}`;
797
827
  }
798
828
  function isCmdShimValid(cmdPath) {
799
829
  try {
@@ -801,8 +831,8 @@ function isCmdShimValid(cmdPath) {
801
831
  const match = content.match(/"%~dp0[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
802
832
  if (!match)
803
833
  return true;
804
- const relPath = match[1].replace(/[/\\]/g, path2.sep);
805
- const target = path2.resolve(path2.dirname(cmdPath), "..", relPath);
834
+ const relPath = match[1].replace(/[/\\]/g, path3.sep);
835
+ const target = path3.resolve(path3.dirname(cmdPath), "..", relPath);
806
836
  return fs4.existsSync(target);
807
837
  } catch {
808
838
  return true;
@@ -827,8 +857,8 @@ function bypassPs1OnWindows(ps1Path, args) {
827
857
  const content = fs4.readFileSync(ps1Path, "utf-8");
828
858
  const match = content.match(/"\$basedir[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
829
859
  if (match) {
830
- const relPath = match[1].replace(/[/\\]/g, path2.sep);
831
- const jsPath = path2.resolve(path2.dirname(ps1Path), "..", relPath);
860
+ const relPath = match[1].replace(/[/\\]/g, path3.sep);
861
+ const jsPath = path3.resolve(path3.dirname(ps1Path), "..", relPath);
832
862
  if (fs4.existsSync(jsPath)) {
833
863
  return {
834
864
  command: process.execPath,
@@ -872,7 +902,7 @@ function withLspProjectCodePermission(allowed, spawn) {
872
902
  var unknownProjectLocalNoticeGeneration = -1;
873
903
  function recordUntrustedLspExecution(request, trust) {
874
904
  const generation = getDegradationLedgerGeneration();
875
- const subject = request.kind === "project-code-server" ? `project-code-server:g${generation}:${request.serverId}:${request.root}` : `project-local-binary:g${generation}:${path2.basename(request.command)}`;
905
+ const subject = request.kind === "project-code-server" ? `project-code-server:g${generation}:${request.serverId}:${request.root}` : `project-local-binary:g${generation}:${path3.basename(request.command)}`;
876
906
  const metadata = request.kind === "project-code-server" ? {
877
907
  field: request.kind,
878
908
  serverId: request.serverId,
@@ -906,21 +936,43 @@ function refuseUntrustedLspExecution(request) {
906
936
  return;
907
937
  if (request.kind === "project-code-server")
908
938
  recordUntrustedLspExecution(request, trust);
909
- throw new SpawnFailureError("spawn-failed", `LSP ${request.kind === "project-code-server" ? "project-code server" : "project-local binary"} refused: project trust is ${trust}`, new Error(`project trust is ${trust}`));
939
+ throw new SpawnFailureError(request.kind === "project-local-binary" ? "trust-refused" : "spawn-failed", `LSP ${request.kind === "project-code-server" ? "project-code server" : "project-local binary"} refused: project trust is ${trust}`, new Error(`project trust is ${trust}`));
910
940
  }
911
941
  function admitProjectSuppliedTsserver(tsserverPath, cwd, projectSupplied, projectCodeAllowed = lspProjectCodePermission.getStore() ?? false) {
912
942
  const trust = getProjectTrustState();
913
943
  if (tsserverPath && (!projectSupplied || projectCodeAllowed && trust === "trusted"))
914
944
  return tsserverPath;
945
+ if (!tsserverPath) {
946
+ recordUnresolvedTypeScriptCompiler(cwd, trust);
947
+ return void 0;
948
+ }
915
949
  recordUntrustedLspExecution({
916
950
  kind: "project-local-binary",
917
- command: tsserverPath ?? "tsserver.js",
918
- resolvedCommand: tsserverPath ?? "tsserver.js",
951
+ command: tsserverPath,
952
+ resolvedCommand: tsserverPath,
919
953
  cwd,
920
- reason: tsserverPath ? "LSP execution refused: project compiler requires trusted session ownership" : "LSP execution refused: no admitted absolute TypeScript compiler"
954
+ reason: "LSP execution refused: project compiler requires trusted session ownership"
921
955
  }, trust);
922
956
  return void 0;
923
957
  }
958
+ function recordUnresolvedTypeScriptCompiler(cwd, trust) {
959
+ const generation = getDegradationLedgerGeneration();
960
+ recordDegradationOnce({
961
+ kind: "lsp-registry-decision",
962
+ subject: `typescript-compiler:g${generation}:${cwd}`,
963
+ reason: "LSP not started: no absolute TypeScript compiler (tsserver.js) was resolved",
964
+ metadata: { field: "typescript-compiler", trust }
965
+ });
966
+ if (unknownProjectLocalNoticeGeneration === generation)
967
+ return;
968
+ unknownProjectLocalNoticeGeneration = generation;
969
+ logExtension({
970
+ subsystem: "lsp-registry",
971
+ level: "warn",
972
+ message: "TypeScript language server not started: no absolute TypeScript compiler (tsserver.js) could be resolved; install typescript in the project or let pi-lens install it",
973
+ metadata: { field: "typescript-compiler" }
974
+ });
975
+ }
924
976
  function isProjectLocalLspBinary(resolvedCommand, cwd) {
925
977
  return isProjectLocalBinPath(resolvedCommand, cwd);
926
978
  }
@@ -1015,12 +1067,12 @@ async function launchLSP(command, args = [], options = {}) {
1015
1067
  delete env[OWNER_TAG_ENV];
1016
1068
  else
1017
1069
  env[OWNER_TAG_ENV] = ownerTag;
1018
- const isRelativePath = !isFullyQualified(command) && (command.includes(path2.sep) || command.includes("/"));
1019
- const explicitCommand = isRelativePath ? path2.resolve(cwd, command) : command;
1020
- const resolvedCommand = !isFullyQualified(command) && !command.includes(path2.sep) && !command.includes("/") ? findBinaryOnPath(command, env) ?? explicitCommand : explicitCommand;
1070
+ const isRelativePath = !isFullyQualified(command) && (command.includes(path3.sep) || command.includes("/"));
1071
+ const explicitCommand = isRelativePath ? path3.resolve(cwd, command) : command;
1072
+ const resolvedCommand = !isFullyQualified(command) && !command.includes(path3.sep) && !command.includes("/") ? findBinaryOnPath(command, env) ?? explicitCommand : explicitCommand;
1021
1073
  let needsShell = computeNeedsShell(resolvedCommand);
1022
1074
  let spawnCommand = resolvedCommand;
1023
- if (!isFullyQualified(command) && !command.includes(path2.sep) && !command.includes("/")) {
1075
+ if (!isFullyQualified(command) && !command.includes(path3.sep) && !command.includes("/")) {
1024
1076
  const globalBinPath = await findGlobalBinary(command);
1025
1077
  if (globalBinPath) {
1026
1078
  spawnCommand = globalBinPath;
@@ -1055,7 +1107,7 @@ async function launchLSP(command, args = [], options = {}) {
1055
1107
  try {
1056
1108
  proc = trySpawn(spawnCommand, args, cwd, env, needsShell);
1057
1109
  } catch (err) {
1058
- if (!isFullyQualified(command) && !command.includes(path2.sep) && !command.includes("/")) {
1110
+ if (!isFullyQualified(command) && !command.includes(path3.sep) && !command.includes("/")) {
1059
1111
  const globalBinPath = await findGlobalBinary(command);
1060
1112
  if (globalBinPath && globalBinPath !== spawnCommand) {
1061
1113
  const needsShellGlobal = computeNeedsShell(globalBinPath);
@@ -1161,7 +1213,7 @@ function asRecord(value) {
1161
1213
  }
1162
1214
  var CONFIG_RESOLVED_PHASE = "config_resolved";
1163
1215
  function configResolutionKey(cwd) {
1164
- return normalizeFilePath(path3.resolve(normalizeFilePath(cwd)));
1216
+ return normalizeFilePath(path4.resolve(normalizeFilePath(cwd)));
1165
1217
  }
1166
1218
  function publishConfigResolutionPending(cwd) {
1167
1219
  logSessionStart(`session_start config_resolution_pending session=${currentSessionRecordId()} root=${configResolutionKey(cwd)}`);
@@ -1392,7 +1444,7 @@ var EMPTY_CONFIG = {
1392
1444
  };
1393
1445
  var configInFlight = /* @__PURE__ */ new Map();
1394
1446
  function normalizeWorkspacePath(cwd) {
1395
- return path3.resolve(cwd);
1447
+ return path4.resolve(cwd);
1396
1448
  }
1397
1449
  var unknownTrustNoticeGeneration = -1;
1398
1450
  function sourceFor(provenance, key) {
@@ -1436,24 +1488,8 @@ function registryDecision(id, field, provenance, trust, allowed) {
1436
1488
  }
1437
1489
  }
1438
1490
  }
1439
- function isSameOrChildPath(filePath, candidateRoot) {
1440
- if (filePath === candidateRoot)
1441
- return true;
1442
- return filePath.startsWith(`${candidateRoot}${path3.sep}`);
1443
- }
1444
1491
  function getConfigForFile(filePath) {
1445
- const resolvedFilePath = path3.resolve(filePath);
1446
- let bestMatch;
1447
- for (const [root, config] of sessionRootConfigEntries()) {
1448
- if (config === void 0)
1449
- continue;
1450
- if (!isSameOrChildPath(resolvedFilePath, root))
1451
- continue;
1452
- if (!bestMatch || root.length > bestMatch.root.length) {
1453
- bestMatch = { root, config };
1454
- }
1455
- }
1456
- return bestMatch?.config ?? EMPTY_CONFIG;
1492
+ return sessionRootConfigForFile(filePath) ?? EMPTY_CONFIG;
1457
1493
  }
1458
1494
  function registerLSPConfig(config) {
1459
1495
  return compileLspRegistry(config, config.__provenance);
@@ -1564,40 +1600,22 @@ async function initLSPConfig(cwd) {
1564
1600
  }
1565
1601
  }
1566
1602
  }
1567
- function registeredServers(config) {
1568
- const builtins = config.registeredServers.length ? config.registeredServers : LSP_SERVERS;
1569
- return [...builtins, ...config.customServers];
1570
- }
1571
1603
  function selectionReason(server, config, filePath, ext, base) {
1572
1604
  if (config.disabledServerIds.has(server.id))
1573
1605
  return "disabled-by-config";
1574
- let matched = false;
1575
- for (const value of server.extensions) {
1576
- const lower = value.toLowerCase();
1577
- if (lower === ext || lower === base) {
1578
- matched = true;
1579
- break;
1580
- }
1581
- }
1582
- if (!matched)
1583
- return "extension-mismatch";
1584
- if (server.pathFilter && !server.pathFilter(filePath))
1585
- return "path-filter";
1586
- return "selected";
1606
+ return fileMatchReason(server, filePath, ext, base);
1587
1607
  }
1588
1608
  function explainServersForFile(filePath, config = getConfigForFile(filePath)) {
1589
- const ext = path3.extname(filePath).toLowerCase();
1590
- const base = path3.basename(filePath).toLowerCase();
1591
- return registeredServers(config).map((server) => {
1609
+ const { ext, base } = fileMatchKeys(filePath);
1610
+ return registeredServers(config, LSP_SERVERS).map((server) => {
1592
1611
  const reason = selectionReason(server, config, filePath, ext, base);
1593
1612
  return { server, selected: reason === "selected", reason };
1594
1613
  });
1595
1614
  }
1596
1615
  function getServersForFileWithConfig(filePath) {
1597
1616
  const config = getConfigForFile(filePath);
1598
- const ext = path3.extname(filePath).toLowerCase();
1599
- const base = path3.basename(filePath).toLowerCase();
1600
- return registeredServers(config).filter((server) => selectionReason(server, config, filePath, ext, base) === "selected");
1617
+ const { ext, base } = fileMatchKeys(filePath);
1618
+ return registeredServers(config, LSP_SERVERS).filter((server) => selectionReason(server, config, filePath, ext, base) === "selected");
1601
1619
  }
1602
1620
  function primaryServerEntry(filePath) {
1603
1621
  return getServersForFileWithConfig(filePath).find((s) => !isAuxiliary(s));
@@ -2067,14 +2085,14 @@ function classifyCascadeWaitTier(lspService, filePath, snapshots) {
2067
2085
  // dist/clients/lsp/lombok.js
2068
2086
  import * as fs5 from "node:fs";
2069
2087
  import * as os5 from "node:os";
2070
- import * as path4 from "node:path";
2088
+ import * as path5 from "node:path";
2071
2089
  var LOMBOK_ENV_KEYS = ["PI_LENS_LOMBOK_JAR", "LOMBOK_JAR"];
2072
2090
  var LOMBOK_PROJECT_FILES = [
2073
2091
  "lombok.config",
2074
2092
  "pom.xml",
2075
2093
  "build.gradle",
2076
2094
  "build.gradle.kts",
2077
- path4.join("gradle", "libs.versions.toml")
2095
+ path5.join("gradle", "libs.versions.toml")
2078
2096
  ];
2079
2097
  function fileExists(filePath) {
2080
2098
  if (!filePath)
@@ -2099,13 +2117,13 @@ function containsLombokDependency(text) {
2099
2117
  return /\borg\.projectlombok\b/i.test(text) || /<artifactId>\s*lombok\s*<\/artifactId>/i.test(text) || /\b(annotationProcessor|compileOnly|testCompileOnly|testAnnotationProcessor)\b[^\n]*\blombok\b/i.test(text);
2100
2118
  }
2101
2119
  function hasLombokProject(root) {
2102
- const lombokConfig = path4.join(root, "lombok.config");
2120
+ const lombokConfig = path5.join(root, "lombok.config");
2103
2121
  if (fileExists(lombokConfig))
2104
2122
  return true;
2105
2123
  for (const name of LOMBOK_PROJECT_FILES) {
2106
2124
  if (name === "lombok.config")
2107
2125
  continue;
2108
- const text = readTextIfSmall(path4.join(root, name));
2126
+ const text = readTextIfSmall(path5.join(root, name));
2109
2127
  if (text && containsLombokDependency(text))
2110
2128
  return true;
2111
2129
  }
@@ -2115,16 +2133,16 @@ function envJarCandidate(env) {
2115
2133
  for (const key of LOMBOK_ENV_KEYS) {
2116
2134
  const value = env[key]?.trim();
2117
2135
  if (fileExists(value))
2118
- return path4.resolve(value);
2136
+ return path5.resolve(value);
2119
2137
  }
2120
2138
  return void 0;
2121
2139
  }
2122
2140
  function localJarCandidates(root) {
2123
2141
  return [
2124
- path4.join(root, "lombok.jar"),
2125
- path4.join(root, ".lombok", "lombok.jar"),
2126
- path4.join(root, "lib", "lombok.jar"),
2127
- path4.join(root, "libs", "lombok.jar")
2142
+ path5.join(root, "lombok.jar"),
2143
+ path5.join(root, ".lombok", "lombok.jar"),
2144
+ path5.join(root, "lib", "lombok.jar"),
2145
+ path5.join(root, "libs", "lombok.jar")
2128
2146
  ];
2129
2147
  }
2130
2148
  function newestExistingJar(candidates) {
@@ -2143,17 +2161,17 @@ function newestExistingJar(candidates) {
2143
2161
  return best?.filePath;
2144
2162
  }
2145
2163
  function mavenLocalLombokJar(home = os5.homedir()) {
2146
- const base = path4.join(home, ".m2", "repository", "org", "projectlombok", "lombok");
2164
+ const base = path5.join(home, ".m2", "repository", "org", "projectlombok", "lombok");
2147
2165
  let versions = [];
2148
2166
  try {
2149
2167
  versions = fs5.readdirSync(base);
2150
2168
  } catch {
2151
2169
  return void 0;
2152
2170
  }
2153
- return newestExistingJar(versions.map((version) => path4.join(base, version, `lombok-${version}.jar`)));
2171
+ return newestExistingJar(versions.map((version) => path5.join(base, version, `lombok-${version}.jar`)));
2154
2172
  }
2155
2173
  function gradleCacheLombokJar(home = os5.homedir()) {
2156
- const base = path4.join(home, ".gradle", "caches", "modules-2", "files-2.1", "org.projectlombok", "lombok");
2174
+ const base = path5.join(home, ".gradle", "caches", "modules-2", "files-2.1", "org.projectlombok", "lombok");
2157
2175
  const candidates = [];
2158
2176
  let versions = [];
2159
2177
  try {
@@ -2162,7 +2180,7 @@ function gradleCacheLombokJar(home = os5.homedir()) {
2162
2180
  return void 0;
2163
2181
  }
2164
2182
  for (const version of versions) {
2165
- const versionDir = path4.join(base, version);
2183
+ const versionDir = path5.join(base, version);
2166
2184
  let hashes = [];
2167
2185
  try {
2168
2186
  hashes = fs5.readdirSync(versionDir);
@@ -2170,7 +2188,7 @@ function gradleCacheLombokJar(home = os5.homedir()) {
2170
2188
  continue;
2171
2189
  }
2172
2190
  for (const hash of hashes) {
2173
- candidates.push(path4.join(versionDir, hash, `lombok-${version}.jar`));
2191
+ candidates.push(path5.join(versionDir, hash, `lombok-${version}.jar`));
2174
2192
  }
2175
2193
  }
2176
2194
  return newestExistingJar(candidates);
@@ -2203,15 +2221,15 @@ function createLombokJdtlsArgs(root, baseEnv = process.env) {
2203
2221
  // dist/clients/lsp/jvm-runtime.js
2204
2222
  import { existsSync as existsSync2, readdirSync as readdirSync4 } from "node:fs";
2205
2223
  import os6 from "node:os";
2206
- import path5 from "node:path";
2224
+ import path6 from "node:path";
2207
2225
  var JAVA_EXE = process.platform === "win32" ? "java.exe" : "java";
2208
2226
  var JAVA_PROBE_TIMEOUT_MS = 5e3;
2209
2227
  var MIN_JAVA_MAJOR = 17;
2210
2228
  function jdkHomeFrom(dir) {
2211
- if (existsSync2(path5.join(dir, "bin", JAVA_EXE)))
2229
+ if (existsSync2(path6.join(dir, "bin", JAVA_EXE)))
2212
2230
  return dir;
2213
- const macHome = path5.join(dir, "Contents", "Home");
2214
- if (existsSync2(path5.join(macHome, "bin", JAVA_EXE)))
2231
+ const macHome = path6.join(dir, "Contents", "Home");
2232
+ if (existsSync2(path6.join(macHome, "bin", JAVA_EXE)))
2215
2233
  return macHome;
2216
2234
  return void 0;
2217
2235
  }
@@ -2224,7 +2242,7 @@ function parseMajorVersion(name) {
2224
2242
  }
2225
2243
  function childDirs(base) {
2226
2244
  try {
2227
- return readdirSync4(base, { withFileTypes: true }).filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => path5.join(base, e.name));
2245
+ return readdirSync4(base, { withFileTypes: true }).filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => path6.join(base, e.name));
2228
2246
  } catch {
2229
2247
  return [];
2230
2248
  }
@@ -2232,26 +2250,26 @@ function childDirs(base) {
2232
2250
  function candidateRoots() {
2233
2251
  const home = os6.homedir();
2234
2252
  const roots = [];
2235
- roots.push(path5.join(home, ".jdks"));
2236
- roots.push(path5.join(getGlobalPiLensDir(), "tools"));
2253
+ roots.push(path6.join(home, ".jdks"));
2254
+ roots.push(path6.join(getGlobalPiLensDir(), "tools"));
2237
2255
  if (process.platform === "win32") {
2238
2256
  const progFiles = [
2239
2257
  process.env.ProgramFiles,
2240
2258
  process.env["ProgramFiles(x86)"],
2241
2259
  process.env.ProgramW6432,
2242
- path5.join(process.env.LOCALAPPDATA ?? path5.join(home, "AppData", "Local"), "Programs")
2260
+ path6.join(process.env.LOCALAPPDATA ?? path6.join(home, "AppData", "Local"), "Programs")
2243
2261
  ].filter((p) => Boolean(p));
2244
2262
  for (const base of progFiles) {
2245
- roots.push(path5.join(base, "Eclipse Adoptium"));
2246
- roots.push(path5.join(base, "Java"));
2247
- roots.push(path5.join(base, "Microsoft"));
2248
- roots.push(path5.join(base, "Zulu"));
2249
- roots.push(path5.join(base, "Amazon Corretto"));
2250
- roots.push(path5.join(base, "BellSoft"));
2263
+ roots.push(path6.join(base, "Eclipse Adoptium"));
2264
+ roots.push(path6.join(base, "Java"));
2265
+ roots.push(path6.join(base, "Microsoft"));
2266
+ roots.push(path6.join(base, "Zulu"));
2267
+ roots.push(path6.join(base, "Amazon Corretto"));
2268
+ roots.push(path6.join(base, "BellSoft"));
2251
2269
  }
2252
2270
  } else if (process.platform === "darwin") {
2253
2271
  roots.push("/Library/Java/JavaVirtualMachines");
2254
- roots.push(path5.join(home, "Library", "Java", "JavaVirtualMachines"));
2272
+ roots.push(path6.join(home, "Library", "Java", "JavaVirtualMachines"));
2255
2273
  roots.push("/opt/homebrew/opt");
2256
2274
  roots.push("/usr/local/opt");
2257
2275
  } else {
@@ -2275,7 +2293,7 @@ function discoverJdkHome(roots = candidateRoots(), javaHome = process.env.JAVA_H
2275
2293
  continue;
2276
2294
  found.push({
2277
2295
  home: resolved,
2278
- major: parseMajorVersion(path5.basename(dir))
2296
+ major: parseMajorVersion(path6.basename(dir))
2279
2297
  });
2280
2298
  }
2281
2299
  }
@@ -2374,12 +2392,12 @@ async function resolveJavaRuntimeEnv() {
2374
2392
  }
2375
2393
  const home = discoverJdkHome();
2376
2394
  if (home) {
2377
- const binDir = path5.join(home, "bin");
2395
+ const binDir = path6.join(home, "bin");
2378
2396
  const currentPath = process.env.PATH ?? process.env.Path ?? "";
2379
2397
  _cachedEnv = {
2380
2398
  value: {
2381
2399
  JAVA_HOME: home,
2382
- PATH: binDir + path5.delimiter + currentPath
2400
+ PATH: binDir + path6.delimiter + currentPath
2383
2401
  }
2384
2402
  };
2385
2403
  return _cachedEnv.value;
@@ -2435,7 +2453,7 @@ async function resolveLspServerCwd(server, filePath, sessionCwd, onRootFailure,
2435
2453
  rootFailed = true;
2436
2454
  onRootFailure?.(reason);
2437
2455
  }
2438
- const isFileDirFallback = serverRoot !== void 0 && rootMarkers?.length && path6.resolve(serverRoot) === path6.resolve(path6.dirname(filePath));
2456
+ const isFileDirFallback = serverRoot !== void 0 && rootMarkers?.length && path7.resolve(serverRoot) === path7.resolve(path7.dirname(filePath));
2439
2457
  if (!serverRoot || isFileDirFallback) {
2440
2458
  const probedMarker = onRootFallback && !rootFailed && rootMarkers?.length ? resolveToolCwd("lsp", server.id, filePath, {
2441
2459
  cwd: sessionCwd,
@@ -2444,7 +2462,7 @@ async function resolveLspServerCwd(server, filePath, sessionCwd, onRootFailure,
2444
2462
  }).marker : void 0;
2445
2463
  const refusedMarker = probedMarker !== void 0 && rootMarkers?.includes(probedMarker) ? probedMarker : void 0;
2446
2464
  const fallbackCwd = rootMarkers?.length ? resolveToolCwd("lsp", server.id, filePath, {
2447
- cwd: path6.dirname(path6.resolve(filePath)),
2465
+ cwd: path7.dirname(path7.resolve(filePath)),
2448
2466
  rootMarkers
2449
2467
  }) : void 0;
2450
2468
  if (!serverRoot) {
@@ -2498,6 +2516,9 @@ var PROJECT_BOUNDARY_MARKERS = [
2498
2516
  "Cargo.toml",
2499
2517
  "Cargo.lock",
2500
2518
  "pyproject.toml",
2519
+ "setup.py",
2520
+ "setup.cfg",
2521
+ "requirements.txt",
2501
2522
  "uv.lock",
2502
2523
  "poetry.lock",
2503
2524
  "Pipfile",
@@ -2511,20 +2532,26 @@ var PROJECT_BOUNDARY_MARKERS = [
2511
2532
  "pubspec.yaml",
2512
2533
  "Package.swift"
2513
2534
  ];
2535
+ var PYTHON_BOUNDARY_MARKERS = /* @__PURE__ */ new Set([
2536
+ "setup.py",
2537
+ "setup.cfg",
2538
+ "requirements.txt"
2539
+ ]);
2540
+ var PYTHON_EXTENSIONS = new Set(extensionsForLanguage("python"));
2514
2541
  var loggedRootCeilingClamps = /* @__PURE__ */ new Set();
2515
2542
  var posixCaseInsensitiveByPath = /* @__PURE__ */ new Map();
2516
2543
  function posixFilesystemIsCaseInsensitive(root) {
2517
- const resolved = path6.resolve(root);
2544
+ const resolved = path7.resolve(root);
2518
2545
  const cached = posixCaseInsensitiveByPath.get(resolved);
2519
2546
  if (cached !== void 0)
2520
2547
  return cached;
2521
2548
  if (!existsSync3(resolved)) {
2522
2549
  return false;
2523
2550
  }
2524
- const name = path6.basename(resolved);
2551
+ const name = path7.basename(resolved);
2525
2552
  const alternate = name.toLowerCase() === name ? name.toUpperCase() : name.toLowerCase();
2526
2553
  let insensitive = false;
2527
- const alternatePath = path6.join(path6.dirname(resolved), alternate);
2554
+ const alternatePath = path7.join(path7.dirname(resolved), alternate);
2528
2555
  if (alternate !== name && existsSync3(alternatePath)) {
2529
2556
  try {
2530
2557
  const actual = statSync4(resolved);
@@ -2542,7 +2569,7 @@ function resetLSPCaseSensitivityState() {
2542
2569
  }
2543
2570
  function isSameOrWithin(ancestor, candidate, deps = {}) {
2544
2571
  const windowsShaped = isWindowsPath(ancestor) || isWindowsPath(candidate);
2545
- const pathApi = windowsShaped ? path6.win32 : path6;
2572
+ const pathApi = windowsShaped ? path7.win32 : path7;
2546
2573
  const resolvedAncestor = pathApi.resolve(ancestor);
2547
2574
  const resolvedCandidate = pathApi.resolve(candidate);
2548
2575
  let caseInsensitive = false;
@@ -2562,7 +2589,7 @@ function isSameOrWithin(ancestor, candidate, deps = {}) {
2562
2589
  }
2563
2590
  function enforceLspRootCeiling(root, sessionCwd, filePath) {
2564
2591
  const windowsShaped = isWindowsPath(root) || isWindowsPath(sessionCwd);
2565
- const pathApi = windowsShaped ? path6.win32 : path6;
2592
+ const pathApi = windowsShaped ? path7.win32 : path7;
2566
2593
  const resolvedRoot = pathApi.resolve(root);
2567
2594
  const resolvedCwd = pathApi.resolve(sessionCwd);
2568
2595
  if (filePath && !isSameOrWithin(resolvedCwd, pathApi.resolve(filePath))) {
@@ -2577,18 +2604,20 @@ function enforceLspRootCeiling(root, sessionCwd, filePath) {
2577
2604
  }
2578
2605
  return resolvedCwd;
2579
2606
  }
2580
- async function hasProjectBoundaryMarker(dir) {
2607
+ async function hasProjectBoundaryMarker(dir, server) {
2581
2608
  if (await markerExists(dir, ".git"))
2582
2609
  return true;
2583
2610
  for (const marker of PROJECT_BOUNDARY_MARKERS) {
2611
+ if (PYTHON_BOUNDARY_MARKERS.has(marker) && !server.extensions.some((extension) => PYTHON_EXTENSIONS.has(extension)))
2612
+ continue;
2584
2613
  if (await markerExists(dir, marker))
2585
2614
  return true;
2586
2615
  }
2587
2616
  return false;
2588
2617
  }
2589
2618
  function pathSegments(dir) {
2590
- const parsed = path6.parse(path6.resolve(dir));
2591
- return path6.relative(parsed.root, path6.resolve(dir)).split(path6.sep).filter(Boolean).map((segment) => segment.toLowerCase());
2619
+ const parsed = path7.parse(path7.resolve(dir));
2620
+ return path7.relative(parsed.root, path7.resolve(dir)).split(path7.sep).filter(Boolean).map((segment) => segment.toLowerCase());
2592
2621
  }
2593
2622
  function hasFixtureConvention(dir) {
2594
2623
  const segments = pathSegments(dir);
@@ -2600,18 +2629,18 @@ function hasAtomicStageSegment(dir) {
2600
2629
  return pathSegments(dir).some((segment) => STAGE_TMP_PATTERN.test(segment));
2601
2630
  }
2602
2631
  async function findGitBoundary(dir) {
2603
- let current = path6.resolve(dir);
2604
- const fsRoot = path6.parse(current).root;
2632
+ let current = path7.resolve(dir);
2633
+ const fsRoot = path7.parse(current).root;
2605
2634
  while (true) {
2606
2635
  if (await markerExists(current, ".git"))
2607
2636
  return current;
2608
2637
  if (current === fsRoot)
2609
2638
  return void 0;
2610
- current = path6.dirname(current);
2639
+ current = path7.dirname(current);
2611
2640
  }
2612
2641
  }
2613
2642
  async function isExcludedLspRoot(dir) {
2614
- const candidate = path6.resolve(dir);
2643
+ const candidate = path7.resolve(dir);
2615
2644
  if (hasFixtureConvention(candidate) || hasAtomicStageSegment(candidate))
2616
2645
  return true;
2617
2646
  const gitRoot = await findGitBoundary(candidate);
@@ -2623,9 +2652,9 @@ async function isExcludedLspRoot(dir) {
2623
2652
  }
2624
2653
  async function nearestNonExcludedFallbackRoot(candidate) {
2625
2654
  if (!await isExcludedLspRoot(candidate))
2626
- return path6.resolve(candidate);
2627
- let current = path6.dirname(path6.resolve(candidate));
2628
- const fsRoot = path6.parse(current).root;
2655
+ return path7.resolve(candidate);
2656
+ let current = path7.dirname(path7.resolve(candidate));
2657
+ const fsRoot = path7.parse(current).root;
2629
2658
  let nearestAllowed;
2630
2659
  while (true) {
2631
2660
  if (!await isExcludedLspRoot(current)) {
@@ -2637,7 +2666,7 @@ async function nearestNonExcludedFallbackRoot(candidate) {
2637
2666
  }
2638
2667
  if (current === fsRoot)
2639
2668
  break;
2640
- current = path6.dirname(current);
2669
+ current = path7.dirname(current);
2641
2670
  }
2642
2671
  return nearestAllowed ?? fsRoot;
2643
2672
  }
@@ -2678,7 +2707,7 @@ async function installEvidenceForLaunch(toolId, installed, attempt) {
2678
2707
  const confirmedManagedPath = await findManagedToolBinary(toolId);
2679
2708
  return {
2680
2709
  ...evidence,
2681
- binary: path6.basename(installed),
2710
+ binary: path7.basename(installed),
2682
2711
  ...confirmedManagedPath !== void 0 && pathsEqual(confirmedManagedPath, installed) && {
2683
2712
  source: "managed-dir"
2684
2713
  }
@@ -2731,7 +2760,7 @@ function markDirectLspCommandUnavailable(command) {
2731
2760
  directLspCommandUnavailableUntil.set(command, Date.now() + DIRECT_LSP_NEGATIVE_TTL_MS);
2732
2761
  directLspCommandSkipLoggedUntil.delete(command);
2733
2762
  }
2734
- var PI_LENS_BIN_DIR2 = path6.join(getGlobalPiLensDir(), "bin");
2763
+ var PI_LENS_BIN_DIR2 = path7.join(getGlobalPiLensDir(), "bin");
2735
2764
  async function resolveAndLaunch(spec, allowInstall) {
2736
2765
  const generation = lspLaunchAvailabilityGeneration.capture();
2737
2766
  const toolLabel = spec.managedToolId ?? spec.candidates[spec.candidates.length - 1] ?? "unknown";
@@ -2796,7 +2825,7 @@ async function resolveAndLaunch(spec, allowInstall) {
2796
2825
  producer: "lsp-launch",
2797
2826
  classifiedBy: "probe",
2798
2827
  evidence: {
2799
- binary: path6.basename(managedCandidate),
2828
+ binary: path7.basename(managedCandidate),
2800
2829
  source: "managed-dir",
2801
2830
  correctsLatchedRow: false
2802
2831
  }
@@ -2827,7 +2856,7 @@ async function resolveAndLaunch(spec, allowInstall) {
2827
2856
  logSessionStart(`lsp launch candidate failed tool=${toolLabel} idx=${failure.index} command=${failure.command} error=${failure.message}`);
2828
2857
  trackRuntimeFailure(failure.err);
2829
2858
  }
2830
- const hasOnlyRepairableCandidateFailures = candidateFailures.every((failure) => hasSpawnFailureKind(failure.err, "tool-not-found"));
2859
+ const hasOnlyRepairableCandidateFailures = candidateFailures.every((failure) => hasSpawnFailureKind(failure.err, "tool-not-found") || hasSpawnFailureKind(failure.err, "trust-refused"));
2831
2860
  if (!hasOnlyRepairableCandidateFailures) {
2832
2861
  if (lastRuntimeFailure)
2833
2862
  throw lastRuntimeFailure;
@@ -2846,14 +2875,19 @@ async function resolveAndLaunch(spec, allowInstall) {
2846
2875
  globalInstallDisabled: isLspInstallDisabled()
2847
2876
  }
2848
2877
  });
2878
+ if (lastRuntimeFailure)
2879
+ throw lastRuntimeFailure;
2849
2880
  return void 0;
2850
2881
  }
2882
+ const isRefusal = (failure) => hasSpawnFailureKind(failure.err, "trust-refused");
2883
+ const trustRefused = candidateFailures.some(isRefusal);
2884
+ const storeOnly = trustRefused && (candidateFailures.some((failure) => isRefusal(failure) && isSimpleCommand(failure.command)) || commandSearchReachesProject(spec.cwd));
2851
2885
  if (spec.managedToolId) {
2852
2886
  const failedCandidate = candidateFailures.at(-1);
2853
2887
  const classifiedFailure = classifyProbeFailure({
2854
2888
  error: failedCandidate?.err instanceof Error ? failedCandidate.err : void 0,
2855
2889
  spawnFailure: {
2856
- kind: hasSpawnFailureKind(failedCandidate?.err, "tool-not-found") ? "tool-not-found" : void 0
2890
+ kind: ["tool-not-found", "trust-refused"].find((kind) => hasSpawnFailureKind(failedCandidate?.err, kind))
2857
2891
  }
2858
2892
  }, { command: failedCandidate?.command });
2859
2893
  logAvailabilityDecision({
@@ -2867,10 +2901,18 @@ async function resolveAndLaunch(spec, allowInstall) {
2867
2901
  producer: "lsp-launch",
2868
2902
  evidence: classifiedFailure.evidence
2869
2903
  });
2870
- logSessionStart(`lsp launch ensure-tool start tool=${spec.managedToolId} cwd=${spec.cwd}`);
2904
+ if (storeOnly) {
2905
+ recordDegradationOnce({
2906
+ kind: "lsp-registry-decision",
2907
+ subject: `store-only-repair:${spec.managedToolId}`,
2908
+ reason: "LSP repair read only the pi-lens tool store: after a trust refusal a bare-name lookup reaches the project, so nothing was probed on PATH or installed",
2909
+ metadata: { field: "store-only-repair", tool: spec.managedToolId }
2910
+ });
2911
+ }
2912
+ logSessionStart(`lsp launch ensure-tool start tool=${spec.managedToolId} cwd=${spec.cwd} storeOnly=${storeOnly}`);
2871
2913
  const installStartedAt = Date.now();
2872
- const installed = await ensureTool(spec.managedToolId);
2873
- const installAttempt = captureInstallAttempt(spec.managedToolId);
2914
+ const installed = await (storeOnly ? getToolPath(spec.managedToolId, { storeOnly: true }) : ensureTool(spec.managedToolId));
2915
+ const installAttempt = storeOnly ? void 0 : captureInstallAttempt(spec.managedToolId);
2874
2916
  if (staleLaunch(generation, `${toolLabel}:ensureTool`)) {
2875
2917
  return void 0;
2876
2918
  }
@@ -3000,7 +3042,7 @@ async function resolveAndLaunch(spec, allowInstall) {
3000
3042
  }
3001
3043
  }
3002
3044
  }
3003
- const runtimeInstall = spec.runtimeInstall;
3045
+ const runtimeInstall = trustRefused ? void 0 : spec.runtimeInstall;
3004
3046
  const runtimeAvailable = runtimeInstall ? await isOnPath(runtimeInstall.runtimeCommand) : false;
3005
3047
  if (staleLaunch(generation, `${toolLabel}:runtimeAvailability`)) {
3006
3048
  return void 0;
@@ -3089,7 +3131,7 @@ async function resolveAndLaunchTreeBinary(spec, allowInstall) {
3089
3131
  return void 0;
3090
3132
  }
3091
3133
  const suffix = process.platform === "win32" ? ".exe" : "";
3092
- const binPath = path6.join(bundleDir, ...spec.binRelPath.split("/")) + suffix;
3134
+ const binPath = path7.join(bundleDir, ...spec.binRelPath.split("/")) + suffix;
3093
3135
  try {
3094
3136
  const proc = await launchLSP(binPath, spec.args, {
3095
3137
  cwd: spec.cwd,
@@ -3104,7 +3146,7 @@ async function resolveAndLaunchTreeBinary(spec, allowInstall) {
3104
3146
  }
3105
3147
  }
3106
3148
  function nodeBinLocalCandidates(root, baseName) {
3107
- const localBase = path6.join(root, "node_modules", ".bin", baseName);
3149
+ const localBase = path7.join(root, "node_modules", ".bin", baseName);
3108
3150
  if (process.platform === "win32") {
3109
3151
  return [`${localBase}.cmd`, `${localBase}.exe`];
3110
3152
  }
@@ -3114,7 +3156,7 @@ function nodeBinCandidates(root, baseName) {
3114
3156
  return [...nodeBinLocalCandidates(root, baseName), baseName];
3115
3157
  }
3116
3158
  function piAgentExtensionsRootKey(file) {
3117
- const dirKey = normalizeEphemeralMapKey(path6.dirname(path6.resolve(file)));
3159
+ const dirKey = normalizeEphemeralMapKey(path7.dirname(path7.resolve(file)));
3118
3160
  const marker = "/.pi/agent/extensions";
3119
3161
  const index = dirKey.indexOf(marker);
3120
3162
  if (index === -1)
@@ -3122,12 +3164,12 @@ function piAgentExtensionsRootKey(file) {
3122
3164
  return dirKey.slice(0, index + marker.length);
3123
3165
  }
3124
3166
  function IgnoreHomeRoot(primary) {
3125
- const homeKey = normalizeEphemeralMapKey(path6.resolve(os7.homedir()));
3167
+ const homeKey = normalizeEphemeralMapKey(path7.resolve(os7.homedir()));
3126
3168
  return withRootMarkers(async (file) => {
3127
3169
  const root = await primary(file);
3128
3170
  if (!root)
3129
3171
  return void 0;
3130
- return normalizeEphemeralMapKey(path6.resolve(root)) === homeKey ? void 0 : root;
3172
+ return normalizeEphemeralMapKey(path7.resolve(root)) === homeKey ? void 0 : root;
3131
3173
  }, primary.rootMarkers ?? []);
3132
3174
  }
3133
3175
  function rubyBinCandidates(baseName) {
@@ -3135,13 +3177,13 @@ function rubyBinCandidates(baseName) {
3135
3177
  const home = os7.homedir();
3136
3178
  const isWin = process.platform === "win32";
3137
3179
  const ext = isWin ? ".bat" : "";
3138
- candidates.push(path6.join(home, ".local", "share", "mise", "installs", "ruby", "bin", `${baseName}${ext}`));
3139
- candidates.push(path6.join(home, ".asdf", "installs", "ruby", "bin", `${baseName}${ext}`));
3180
+ candidates.push(path7.join(home, ".local", "share", "mise", "installs", "ruby", "bin", `${baseName}${ext}`));
3181
+ candidates.push(path7.join(home, ".asdf", "installs", "ruby", "bin", `${baseName}${ext}`));
3140
3182
  if (isWin) {
3141
- const driveRoot = path6.parse(home).root;
3183
+ const driveRoot = path7.parse(home).root;
3142
3184
  for (const entry of getRubyVersionDirNamesSync(driveRoot)) {
3143
- candidates.push(path6.join(driveRoot, entry, "bin", `${baseName}.bat`));
3144
- candidates.push(path6.join(driveRoot, entry, "bin", baseName));
3185
+ candidates.push(path7.join(driveRoot, entry, "bin", `${baseName}.bat`));
3186
+ candidates.push(path7.join(driveRoot, entry, "bin", baseName));
3145
3187
  }
3146
3188
  }
3147
3189
  return candidates;
@@ -3198,7 +3240,7 @@ function PriorityRoot(markerGroups, excludePatterns, stopDir) {
3198
3240
  }, markerGroups.flat());
3199
3241
  }
3200
3242
  var FileDirRoot = async (file) => {
3201
- const candidate = path6.resolve(path6.dirname(file));
3243
+ const candidate = path7.resolve(path7.dirname(file));
3202
3244
  return nearestNonExcludedFallbackRoot(candidate);
3203
3245
  };
3204
3246
  function RootWithFallback(primary, fallback = FileDirRoot) {
@@ -3220,16 +3262,16 @@ function markerProbeDir(dir, pattern) {
3220
3262
  const normalized = toPosix(pattern);
3221
3263
  const slash = normalized.lastIndexOf("/");
3222
3264
  const parentPattern = slash >= 0 ? normalized.slice(0, slash) : "";
3223
- return parentPattern ? path6.join(dir, ...parentPattern.split("/").filter(Boolean)) : dir;
3265
+ return parentPattern ? path7.join(dir, ...parentPattern.split("/").filter(Boolean)) : dir;
3224
3266
  }
3225
3267
  async function markerExists(dir, pattern) {
3226
3268
  if (!pattern.includes("*")) {
3227
3269
  try {
3228
- await stat(path6.join(dir, pattern));
3270
+ await stat(path7.join(dir, pattern));
3229
3271
  return true;
3230
3272
  } catch (err) {
3231
3273
  if (isPermissionFsError(err)) {
3232
- logSessionStart(`lsp root marker skipped: permission error stat ${path6.join(dir, pattern)}`);
3274
+ logSessionStart(`lsp root marker skipped: permission error stat ${path7.join(dir, pattern)}`);
3233
3275
  }
3234
3276
  return false;
3235
3277
  }
@@ -3265,7 +3307,7 @@ function NearestRoot(includePatterns, excludePatterns, stopDir) {
3265
3307
  subdirPatterns.push(pattern);
3266
3308
  }
3267
3309
  return withRootMarkers(async (file) => {
3268
- const startDir = path6.resolve(path6.dirname(file));
3310
+ const startDir = path7.resolve(path7.dirname(file));
3269
3311
  const dirKey = normalizeMapKey(startDir);
3270
3312
  const cached = cache.get(dirKey);
3271
3313
  if (cached !== void 0 && Date.now() - cached.walkedAt < FRESHNESS_CADENCE_MS && await bounded(dirMtimesStillFreshAsync(cached.probedDirs), rootMtimeBound("lsp-root-memo-freshness")) === true)
@@ -3277,10 +3319,10 @@ function NearestRoot(includePatterns, excludePatterns, stopDir) {
3277
3319
  const walkedAt = Date.now();
3278
3320
  const promise = (async () => {
3279
3321
  let currentDir = startDir;
3280
- const fsRoot = path6.parse(currentDir).root;
3281
- const stop = stopDir ? path6.resolve(stopDir) : fsRoot;
3322
+ const fsRoot = path7.parse(currentDir).root;
3323
+ const stop = stopDir ? path7.resolve(stopDir) : fsRoot;
3282
3324
  while (true) {
3283
- if (stop !== fsRoot && currentDir.startsWith(stop + path6.sep) === false && currentDir !== stop) {
3325
+ if (stop !== fsRoot && currentDir.startsWith(stop + path7.sep) === false && currentDir !== stop) {
3284
3326
  break;
3285
3327
  }
3286
3328
  const stepDirs = [
@@ -3298,7 +3340,7 @@ function NearestRoot(includePatterns, excludePatterns, stopDir) {
3298
3340
  }
3299
3341
  }
3300
3342
  if (excluded) {
3301
- currentDir = path6.dirname(currentDir);
3343
+ currentDir = path7.dirname(currentDir);
3302
3344
  continue;
3303
3345
  }
3304
3346
  }
@@ -3310,7 +3352,7 @@ function NearestRoot(includePatterns, excludePatterns, stopDir) {
3310
3352
  if (currentDir === stop || currentDir === fsRoot) {
3311
3353
  break;
3312
3354
  }
3313
- currentDir = path6.dirname(currentDir);
3355
+ currentDir = path7.dirname(currentDir);
3314
3356
  }
3315
3357
  return void 0;
3316
3358
  })();
@@ -3352,17 +3394,17 @@ async function findAncestorFile(startDir, ...relativeSegments) {
3352
3394
  }
3353
3395
  async function findAncestorFileAmong(startDir, candidateSegmentLists) {
3354
3396
  const fs6 = await import("node:fs/promises");
3355
- let currentDir = path6.resolve(startDir);
3397
+ let currentDir = path7.resolve(startDir);
3356
3398
  while (!isAtOrAboveHomeDir(currentDir)) {
3357
3399
  for (const segments of candidateSegmentLists) {
3358
- const candidate = path6.join(currentDir, ...segments);
3400
+ const candidate = path7.join(currentDir, ...segments);
3359
3401
  try {
3360
3402
  await fs6.access(candidate);
3361
3403
  return candidate;
3362
3404
  } catch {
3363
3405
  }
3364
3406
  }
3365
- const parent = path6.dirname(currentDir);
3407
+ const parent = path7.dirname(currentDir);
3366
3408
  if (parent === currentDir)
3367
3409
  break;
3368
3410
  currentDir = parent;
@@ -3378,19 +3420,21 @@ function resetClassicTsRepairGuard() {
3378
3420
  classicTsRepairState().attempted = false;
3379
3421
  }
3380
3422
  function typescriptDirsForTsc(tscPath) {
3381
- const binDir = path6.dirname(tscPath);
3423
+ const binDir = path7.dirname(tscPath);
3382
3424
  return [
3383
- path6.join(binDir, "..", "typescript"),
3384
- path6.join(binDir, "..", "..", "typescript")
3425
+ path7.join(binDir, "..", "typescript"),
3426
+ path7.join(binDir, "..", "..", "typescript"),
3427
+ // Windows npm-global: `<prefix>/tsc.cmd` beside `<prefix>/node_modules`.
3428
+ path7.join(binDir, "node_modules", "typescript")
3385
3429
  ];
3386
3430
  }
3387
3431
  async function typescriptVersionForTsc(tscPath) {
3388
- if (!path6.isAbsolute(tscPath))
3432
+ if (!path7.isAbsolute(tscPath))
3389
3433
  return void 0;
3390
3434
  for (const dir of typescriptDirsForTsc(tscPath)) {
3391
3435
  let manifest;
3392
3436
  try {
3393
- manifest = await readFile(path6.join(dir, "package.json"), "utf8");
3437
+ manifest = await readFile(path7.join(dir, "package.json"), "utf8");
3394
3438
  } catch {
3395
3439
  continue;
3396
3440
  }
@@ -3412,15 +3456,28 @@ async function typescriptVersionForTsc(tscPath) {
3412
3456
  }
3413
3457
  return void 0;
3414
3458
  }
3459
+ async function hasTypescriptPackageDir(tscPath) {
3460
+ for (const dir of typescriptDirsForTsc(tscPath)) {
3461
+ if ((await stat(dir).catch(() => void 0))?.isDirectory())
3462
+ return true;
3463
+ }
3464
+ return false;
3465
+ }
3466
+ async function absoluteCommandPath(command) {
3467
+ if (!command || path7.isAbsolute(command))
3468
+ return command;
3469
+ const found = await findCommandAsync(command);
3470
+ return found ? realpath(found).catch(() => void 0) : void 0;
3471
+ }
3415
3472
  async function findTsserverPath(root, allowInstall, options) {
3416
3473
  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))));
3474
+ const projectRoots = await Promise.all([root, options?.sessionRoot ?? process.cwd(), process.cwd()].map((dir) => fs6.realpath(dir).catch(() => path7.resolve(dir))));
3418
3475
  const admitCandidate = async (candidate, projectSupplied) => {
3419
3476
  try {
3420
3477
  const real = await fs6.realpath(candidate);
3421
- if (path6.basename(real) !== "tsserver.js" || !(await fs6.stat(real)).isFile())
3478
+ if (path7.basename(real) !== "tsserver.js" || !(await fs6.stat(real)).isFile())
3422
3479
  return void 0;
3423
- const manifest = JSON.parse(await fs6.readFile(path6.join(path6.dirname(real), "..", "package.json"), "utf8"));
3480
+ const manifest = JSON.parse(await fs6.readFile(path7.join(path7.dirname(real), "..", "package.json"), "utf8"));
3424
3481
  if (typeof manifest?.version !== "string" || !manifest.version)
3425
3482
  return void 0;
3426
3483
  return admitProjectSuppliedTsserver(real, options?.sessionRoot ?? process.cwd(), projectSupplied || projectRoots.some((dir) => isUnderDir(real, dir)), options?.projectCodeAllowed);
@@ -3434,7 +3491,7 @@ async function findTsserverPath(root, allowInstall, options) {
3434
3491
  if (admittedAncestor)
3435
3492
  return admittedAncestor;
3436
3493
  }
3437
- const cwdCandidate = path6.join(process.cwd(), "node_modules", "typescript", "lib", "tsserver.js");
3494
+ const cwdCandidate = path7.join(process.cwd(), "node_modules", "typescript", "lib", "tsserver.js");
3438
3495
  try {
3439
3496
  await fs6.access(cwdCandidate);
3440
3497
  const admittedCwd = await admitCandidate(cwdCandidate, false);
@@ -3443,10 +3500,10 @@ async function findTsserverPath(root, allowInstall, options) {
3443
3500
  } catch {
3444
3501
  }
3445
3502
  const tsserverForTsc = async (tscPath) => {
3446
- if (!tscPath || !path6.isAbsolute(tscPath))
3503
+ if (!tscPath)
3447
3504
  return void 0;
3448
3505
  for (const dir of typescriptDirsForTsc(tscPath)) {
3449
- const candidate = path6.join(dir, "lib", "tsserver.js");
3506
+ const candidate = path7.join(dir, "lib", "tsserver.js");
3450
3507
  try {
3451
3508
  const admitted = await admitCandidate(candidate, false);
3452
3509
  if (admitted)
@@ -3457,29 +3514,28 @@ async function findTsserverPath(root, allowInstall, options) {
3457
3514
  return void 0;
3458
3515
  };
3459
3516
  const installAllowed = canInstall(allowInstall);
3460
- const discoveredTsc = await ensureTool("typescript", {
3461
- allowInstall: installAllowed
3462
- });
3517
+ const discoveredTsc = await absoluteCommandPath(await ensureTool("typescript", { allowInstall: installAllowed }));
3463
3518
  const discoveredTsserver = await tsserverForTsc(discoveredTsc);
3464
3519
  if (discoveredTsserver || !discoveredTsc || !installAllowed || classicTsRepairState().attempted) {
3465
3520
  return discoveredTsserver;
3466
3521
  }
3467
3522
  const discoveredVersion = await typescriptVersionForTsc(discoveredTsc);
3468
- if (!discoveredVersion || discoveredVersion.major < 7)
3523
+ const shim = !await hasTypescriptPackageDir(discoveredTsc);
3524
+ if (!shim && (!discoveredVersion || discoveredVersion.major < 7))
3469
3525
  return void 0;
3470
3526
  classicTsRepairState().attempted = true;
3471
- logSessionStart(`lsp typescript: managed compiler resolved to TypeScript ${discoveredVersion.version}, which ships no tsserver.js; reinstalling pinned classic fallback`);
3472
- const repairedTsc = await ensureTool("typescript", {
3527
+ logSessionStart(shim ? `lsp typescript: ${discoveredTsc} has no TypeScript package beside it; installing pinned classic fallback` : `lsp typescript: managed compiler resolved to TypeScript ${discoveredVersion?.version}, which ships no tsserver.js; reinstalling pinned classic fallback`);
3528
+ const repairedTsc = await absoluteCommandPath(await ensureTool("typescript", {
3473
3529
  allowInstall: true,
3474
3530
  forceReinstall: true
3475
- });
3531
+ }));
3476
3532
  return tsserverForTsc(repairedTsc);
3477
3533
  }
3478
3534
  async function findNativeTypeScriptLsp(root) {
3479
- let currentDir = path6.resolve(root);
3535
+ let currentDir = path7.resolve(root);
3480
3536
  while (!isAtOrAboveHomeDir(currentDir)) {
3481
- const typescriptDir = path6.join(currentDir, "node_modules", "typescript");
3482
- const packageJsonPath = path6.join(typescriptDir, "package.json");
3537
+ const typescriptDir = path7.join(currentDir, "node_modules", "typescript");
3538
+ const packageJsonPath = path7.join(typescriptDir, "package.json");
3483
3539
  let packageJsonText;
3484
3540
  try {
3485
3541
  packageJsonText = await readFile(packageJsonPath, "utf8");
@@ -3493,7 +3549,7 @@ async function findNativeTypeScriptLsp(root) {
3493
3549
  return void 0;
3494
3550
  } catch {
3495
3551
  }
3496
- const parent = path6.dirname(currentDir);
3552
+ const parent = path7.dirname(currentDir);
3497
3553
  if (parent === currentDir)
3498
3554
  return void 0;
3499
3555
  currentDir = parent;
@@ -3513,7 +3569,7 @@ async function findNativeTypeScriptLsp(root) {
3513
3569
  const major = /^\d+$/.test(majorText) ? Number(majorText) : Number.NaN;
3514
3570
  if (!Number.isFinite(major) || major < 7)
3515
3571
  return void 0;
3516
- const localTsc = path6.join(currentDir, "node_modules", ".bin", "tsc");
3572
+ const localTsc = path7.join(currentDir, "node_modules", ".bin", "tsc");
3517
3573
  const candidates = process.platform === "win32" ? [`${localTsc}.cmd`, `${localTsc}.exe`, localTsc] : [localTsc];
3518
3574
  for (const command of candidates) {
3519
3575
  try {
@@ -3529,23 +3585,23 @@ async function findNativeTypeScriptLsp(root) {
3529
3585
  function dotnetToolCandidates(tool) {
3530
3586
  const home = os7.homedir();
3531
3587
  return [
3532
- path6.join(PI_LENS_BIN_DIR2, `${tool}.exe`),
3533
- path6.join(PI_LENS_BIN_DIR2, tool),
3534
- path6.join(home, ".dotnet", "tools", `${tool}.exe`),
3535
- path6.join(home, ".dotnet", "tools", tool),
3588
+ path7.join(PI_LENS_BIN_DIR2, `${tool}.exe`),
3589
+ path7.join(PI_LENS_BIN_DIR2, tool),
3590
+ path7.join(home, ".dotnet", "tools", `${tool}.exe`),
3591
+ path7.join(home, ".dotnet", "tools", tool),
3536
3592
  tool
3537
3593
  ].filter(Boolean);
3538
3594
  }
3539
3595
  function binExeVariants(dir, tool) {
3540
- return process.platform === "win32" ? [path6.join(dir, `${tool}.exe`), path6.join(dir, tool)] : [path6.join(dir, tool)];
3596
+ return process.platform === "win32" ? [path7.join(dir, `${tool}.exe`), path7.join(dir, tool)] : [path7.join(dir, tool)];
3541
3597
  }
3542
3598
  function goBinCandidates(tool) {
3543
- const gopath = process.env.GOPATH?.split(path6.delimiter)[0] || path6.join(os7.homedir(), "go");
3544
- return [tool, ...binExeVariants(path6.join(gopath, "bin"), tool)];
3599
+ const gopath = process.env.GOPATH?.split(path7.delimiter)[0] || path7.join(os7.homedir(), "go");
3600
+ return [tool, ...binExeVariants(path7.join(gopath, "bin"), tool)];
3545
3601
  }
3546
3602
  function cargoBinCandidates(tool) {
3547
- const cargoHome = process.env.CARGO_HOME || path6.join(os7.homedir(), ".cargo");
3548
- return [tool, ...binExeVariants(path6.join(cargoHome, "bin"), tool)];
3603
+ const cargoHome = process.env.CARGO_HOME || path7.join(os7.homedir(), ".cargo");
3604
+ return [tool, ...binExeVariants(path7.join(cargoHome, "bin"), tool)];
3549
3605
  }
3550
3606
  async function tryGemInstall(gem) {
3551
3607
  const { join: join4 } = await import("node:path");
@@ -3583,7 +3639,7 @@ var TS_TOOLING_MARKERS = [
3583
3639
  ];
3584
3640
  var TS_FAMILY_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
3585
3641
  function isTsFamilyFile(file) {
3586
- return TS_FAMILY_EXTENSIONS.has(path6.extname(file).toLowerCase());
3642
+ return TS_FAMILY_EXTENSIONS.has(path7.extname(file).toLowerCase());
3587
3643
  }
3588
3644
  function tsConfigMarkersForFile(file) {
3589
3645
  return isTsFamilyFile(file) ? ["tsconfig.json"] : TS_CONFIG_MARKERS;
@@ -3604,40 +3660,40 @@ async function findTypeScriptProjectRoot(file) {
3604
3660
  return isSameOrWithin(toolingRoot, configRoot) ? configRoot : toolingRoot;
3605
3661
  }
3606
3662
  async function findExtensionBoundedRoot(file, extensionRootKey) {
3607
- const startDir = path6.resolve(path6.dirname(file));
3663
+ const startDir = path7.resolve(path7.dirname(file));
3608
3664
  let currentDir = startDir;
3609
3665
  const configMarkers = tsConfigMarkersForFile(file);
3610
3666
  while (true) {
3611
3667
  for (const pattern of configMarkers) {
3612
3668
  try {
3613
- await stat(path6.join(currentDir, pattern));
3669
+ await stat(path7.join(currentDir, pattern));
3614
3670
  return currentDir;
3615
3671
  } catch {
3616
3672
  }
3617
3673
  }
3618
3674
  for (const pattern of TS_TOOLING_MARKERS) {
3619
3675
  try {
3620
- await stat(path6.join(currentDir, pattern));
3676
+ await stat(path7.join(currentDir, pattern));
3621
3677
  return currentDir;
3622
3678
  } catch {
3623
3679
  }
3624
3680
  }
3625
- const currentKey = normalizeEphemeralMapKey(path6.resolve(currentDir));
3681
+ const currentKey = normalizeEphemeralMapKey(path7.resolve(currentDir));
3626
3682
  if (currentKey === extensionRootKey)
3627
3683
  return void 0;
3628
- const parent = path6.dirname(currentDir);
3684
+ const parent = path7.dirname(currentDir);
3629
3685
  if (parent === currentDir)
3630
3686
  return void 0;
3631
3687
  currentDir = parent;
3632
3688
  }
3633
3689
  }
3634
3690
  async function hasAgentLevelProjectMarker(extensionRootKey) {
3635
- const agentDir = path6.dirname(extensionRootKey);
3691
+ const agentDir = path7.dirname(extensionRootKey);
3636
3692
  if (!agentDir || agentDir === extensionRootKey)
3637
3693
  return false;
3638
3694
  for (const pattern of [...TS_CONFIG_MARKERS, ...TS_TOOLING_MARKERS]) {
3639
3695
  try {
3640
- await stat(path6.join(agentDir, pattern));
3696
+ await stat(path7.join(agentDir, pattern));
3641
3697
  return true;
3642
3698
  } catch {
3643
3699
  }
@@ -3815,13 +3871,13 @@ var PythonServer = {
3815
3871
  if (!pyrightPath)
3816
3872
  return void 0;
3817
3873
  source = "managed";
3818
- const binDir = path6.dirname(pyrightPath);
3874
+ const binDir = path7.dirname(pyrightPath);
3819
3875
  const isWindows2 = process.platform === "win32";
3820
3876
  const managedCandidates = isWindows2 ? [
3821
- path6.join(binDir, "pyright-langserver.cmd"),
3822
- path6.join(binDir, "pyright-langserver"),
3877
+ path7.join(binDir, "pyright-langserver.cmd"),
3878
+ path7.join(binDir, "pyright-langserver"),
3823
3879
  "pyright-langserver"
3824
- ] : [path6.join(binDir, "pyright-langserver"), "pyright-langserver"];
3880
+ ] : [path7.join(binDir, "pyright-langserver"), "pyright-langserver"];
3825
3881
  const resolved = await resolveAndLaunch({ candidates: managedCandidates, args: ["--stdio"], cwd: root, env }, false);
3826
3882
  if (!resolved)
3827
3883
  return void 0;
@@ -3890,7 +3946,7 @@ var GoServer = {
3890
3946
  }
3891
3947
  };
3892
3948
  function cargoWorkspaceDeclaresMember(workspaceContent, parentDir, childDir) {
3893
- const relativePath = path6.relative(parentDir, childDir).split(path6.sep).join("/");
3949
+ const relativePath = path7.relative(parentDir, childDir).split(path7.sep).join("/");
3894
3950
  if (relativePath === "" || relativePath.startsWith(".."))
3895
3951
  return false;
3896
3952
  const matches = (pattern) => matchesWorkspaceMemberPattern(pattern, relativePath, CARGO_WORKSPACE_MEMBER_DIALECT, () => recordDegradationOnce({
@@ -3904,7 +3960,7 @@ function cargoWorkspaceDeclaresMember(workspaceContent, parentDir, childDir) {
3904
3960
  return readCargoWorkspaceMembers(workspaceContent).some(matches);
3905
3961
  }
3906
3962
  function sessionHoistCeiling(sessionCwd, file) {
3907
- return isSameOrWithin(path6.resolve(sessionCwd), path6.resolve(file)) ? path6.resolve(sessionCwd) : void 0;
3963
+ return isSameOrWithin(path7.resolve(sessionCwd), path7.resolve(file)) ? path7.resolve(sessionCwd) : void 0;
3908
3964
  }
3909
3965
  function RustWorkspaceRoot() {
3910
3966
  const crateRoot = createRootDetector(["Cargo.toml", "Cargo.lock"]);
@@ -3915,14 +3971,14 @@ function RustWorkspaceRoot() {
3915
3971
  const sessionCwd = process.cwd();
3916
3972
  const stop = sessionHoistCeiling(sessionCwd, file);
3917
3973
  let current = root;
3918
- const fsRoot = path6.parse(current).root;
3974
+ const fsRoot = path7.parse(current).root;
3919
3975
  while (true) {
3920
3976
  if (stop !== void 0 && current === stop)
3921
3977
  break;
3922
- const parent = path6.dirname(current);
3978
+ const parent = path7.dirname(current);
3923
3979
  if (parent === current || parent === fsRoot)
3924
3980
  break;
3925
- const parentCargoPath = path6.join(parent, "Cargo.toml");
3981
+ const parentCargoPath = path7.join(parent, "Cargo.toml");
3926
3982
  const parentCargoContent = await readTextFileOrUndefined(parentCargoPath);
3927
3983
  if (parentCargoContent !== void 0 && hasCargoWorkspaceTable(parentCargoContent)) {
3928
3984
  if (cargoWorkspaceDeclaresMember(parentCargoContent, parent, root)) {
@@ -3950,9 +4006,9 @@ async function declaresMavenModule(parentDir, parentPomPath, childDir) {
3950
4006
  const modulesBlock = content.match(/<modules>([\s\S]*?)<\/modules>/);
3951
4007
  if (!modulesBlock)
3952
4008
  return false;
3953
- const resolvedChild = path6.resolve(childDir);
4009
+ const resolvedChild = path7.resolve(childDir);
3954
4010
  for (const match of modulesBlock[1].matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
3955
- if (pathsEqual(path6.resolve(parentDir, match[1]), resolvedChild))
4011
+ if (pathsEqual(path7.resolve(parentDir, match[1]), resolvedChild))
3956
4012
  return true;
3957
4013
  }
3958
4014
  return false;
@@ -3976,15 +4032,15 @@ function JavaWorkspaceRoot() {
3976
4032
  const stop = sessionHoistCeiling(sessionCwd, file);
3977
4033
  let current = root;
3978
4034
  let lastHop = root;
3979
- const fsRoot = path6.parse(current).root;
4035
+ const fsRoot = path7.parse(current).root;
3980
4036
  while (true) {
3981
4037
  if (stop !== void 0 && current === stop)
3982
4038
  break;
3983
- const parent = path6.dirname(current);
4039
+ const parent = path7.dirname(current);
3984
4040
  if (parent === current || parent === fsRoot)
3985
4041
  break;
3986
4042
  if (await markerExists(parent, "pom.xml")) {
3987
- const parentPom = path6.join(parent, "pom.xml");
4043
+ const parentPom = path7.join(parent, "pom.xml");
3988
4044
  if (!await declaresMavenModule(parent, parentPom, lastHop))
3989
4045
  break;
3990
4046
  current = parent;
@@ -4090,17 +4146,17 @@ var PHPServer = {
4090
4146
  return {
4091
4147
  ...result,
4092
4148
  initialization: {
4093
- storagePath: path6.join(getGlobalPiLensDir(), "intelephense")
4149
+ storagePath: path7.join(getGlobalPiLensDir(), "intelephense")
4094
4150
  }
4095
4151
  };
4096
4152
  }
4097
4153
  };
4098
4154
  function buildPsesArgs(bundleDir) {
4099
- const script = path6.join(bundleDir, "PowerShellEditorServices", "Start-EditorServices.ps1");
4100
- const sessionDir = path6.join(getGlobalPiLensDir(), "pses", `${process.pid}-${Date.now()}`);
4155
+ const script = path7.join(bundleDir, "PowerShellEditorServices", "Start-EditorServices.ps1");
4156
+ const sessionDir = path7.join(getGlobalPiLensDir(), "pses", `${process.pid}-${Date.now()}`);
4101
4157
  mkdirSync2(sessionDir, { recursive: true });
4102
- const logPath = path6.join(sessionDir, "pses.log");
4103
- const sessionDetailsPath = path6.join(sessionDir, "session.json");
4158
+ const logPath = path7.join(sessionDir, "pses.log");
4159
+ const sessionDetailsPath = path7.join(sessionDir, "session.json");
4104
4160
  return [
4105
4161
  "-NoLogo",
4106
4162
  "-NoProfile",
@@ -4758,8 +4814,8 @@ var VueServer = {
4758
4814
  initializeTimeoutMs: 3e4,
4759
4815
  async spawn(root, options) {
4760
4816
  const tsserverPath = await findTsserverPath(root, options?.allowInstall, options);
4761
- const hasPackageJson = existsSync3(path6.join(root, "package.json"));
4762
- const hasNodeModules = existsSync3(path6.join(root, "node_modules"));
4817
+ const hasPackageJson = existsSync3(path7.join(root, "package.json"));
4818
+ const hasNodeModules = existsSync3(path7.join(root, "node_modules"));
4763
4819
  if (hasPackageJson && !hasNodeModules) {
4764
4820
  logSessionStart(`lsp vue: node_modules missing in ${root} \u2014 Vue navigation may be limited. Run: npm install (or pnpm/yarn install) in this project.`);
4765
4821
  }
@@ -4774,7 +4830,7 @@ var VueServer = {
4774
4830
  return {
4775
4831
  process: proc.process,
4776
4832
  source: proc.source,
4777
- initialization: tsserverPath ? { typescript: { tsdk: path6.dirname(tsserverPath) } } : void 0
4833
+ initialization: tsserverPath ? { typescript: { tsdk: path7.dirname(tsserverPath) } } : void 0
4778
4834
  };
4779
4835
  }
4780
4836
  };
@@ -4816,7 +4872,7 @@ var SvelteServer = {
4816
4872
  return {
4817
4873
  process: proc.process,
4818
4874
  source: proc.source,
4819
- initialization: tsserverPath ? { typescript: { tsdk: path6.dirname(tsserverPath) } } : void 0
4875
+ initialization: tsserverPath ? { typescript: { tsdk: path7.dirname(tsserverPath) } } : void 0
4820
4876
  };
4821
4877
  }
4822
4878
  };
@@ -5111,7 +5167,7 @@ function getServerById(id) {
5111
5167
  }
5112
5168
 
5113
5169
  // dist/clients/lsp/session-roots.js
5114
- import path7 from "node:path";
5170
+ import path8 from "node:path";
5115
5171
  var SESSION_ROOT_CAP = 128;
5116
5172
  var sessionRoots = new BoundedFifoMap(SESSION_ROOT_CAP);
5117
5173
  function noteEvictedRoots(evicted) {
@@ -5126,28 +5182,57 @@ function noteEvictedRoots(evicted) {
5126
5182
  return roots;
5127
5183
  }
5128
5184
  function registerSessionRoot(cwd) {
5129
- const root = path7.resolve(cwd);
5185
+ const root = path8.resolve(cwd);
5130
5186
  if (sessionRoots.has(root))
5131
5187
  return [];
5132
5188
  return noteEvictedRoots(sessionRoots.set(root, void 0));
5133
5189
  }
5134
5190
  function setSessionRootConfig(cwd, config) {
5135
- return noteEvictedRoots(sessionRoots.set(path7.resolve(cwd), config));
5191
+ return noteEvictedRoots(sessionRoots.set(path8.resolve(cwd), config));
5192
+ }
5193
+ function isSameOrChildPath(filePath, candidateRoot) {
5194
+ if (filePath === candidateRoot)
5195
+ return true;
5196
+ return filePath.startsWith(`${candidateRoot}${path8.sep}`);
5197
+ }
5198
+ function sessionRootConfigForFile(filePath) {
5199
+ const resolvedFilePath = path8.resolve(filePath);
5200
+ let bestMatch;
5201
+ for (const [root, config] of sessionRoots) {
5202
+ if (config === void 0)
5203
+ continue;
5204
+ if (!isSameOrChildPath(resolvedFilePath, root))
5205
+ continue;
5206
+ if (!bestMatch || root.length > bestMatch.root.length) {
5207
+ bestMatch = { root, config };
5208
+ }
5209
+ }
5210
+ return bestMatch?.config;
5136
5211
  }
5137
- function sessionRootConfigEntries() {
5138
- return sessionRoots;
5212
+ function disabledPrimaries(filePath) {
5213
+ const config = sessionRootConfigForFile(filePath);
5214
+ if (!config || config.disabledServerIds.size === 0)
5215
+ return { disabledServerIds: [], fallbackServerIds: [] };
5216
+ const { ext, base } = fileMatchKeys(filePath);
5217
+ const off = config.disabledServerIds;
5218
+ const primaries = registeredServers(config, LSP_SERVERS).filter((server) => !isAuxiliary(server) && fileMatchReason(server, filePath, ext, base) === "selected");
5219
+ const ownerOff = (server) => server.fallbackFor === void 0 || off.has(server.fallbackFor);
5220
+ return {
5221
+ disabledServerIds: primaries.filter((server) => off.has(server.id) && ownerOff(server)).map((server) => server.id),
5222
+ fallbackServerIds: primaries.filter((server) => server.fallbackFor !== void 0 && off.has(server.fallbackFor)).map((server) => server.id)
5223
+ };
5139
5224
  }
5140
5225
  function isSessionRootRegistered(cwd) {
5141
- return sessionRoots.has(path7.resolve(cwd));
5226
+ return sessionRoots.has(path8.resolve(cwd));
5142
5227
  }
5143
5228
  function shouldInitializeSessionRoot(cwd, readyRoots) {
5144
- const normalized = path7.resolve(cwd);
5229
+ const normalized = path8.resolve(cwd);
5145
5230
  return !readyRoots.has(normalized) || !isSessionRootRegistered(normalized);
5146
5231
  }
5147
5232
  function isOutsideAllSessionRoots(filePath) {
5148
5233
  if (sessionRoots.size === 0)
5149
5234
  return false;
5150
- const resolved = path7.resolve(filePath);
5235
+ const resolved = path8.resolve(filePath);
5151
5236
  for (const root of sessionRoots.keys()) {
5152
5237
  if (isSameOrWithin(root, resolved))
5153
5238
  return false;
@@ -5162,8 +5247,6 @@ export {
5162
5247
  findLocalTyposConfig,
5163
5248
  getAstGrepRuleSources,
5164
5249
  getAstGrepRuleFingerprint,
5165
- isAuxiliary,
5166
- serverTraits,
5167
5250
  registerRunnerId,
5168
5251
  withLspProjectCodePermission,
5169
5252
  refuseUntrustedLspExecution,
@@ -5171,6 +5254,11 @@ export {
5171
5254
  resolveAnalysisRoot,
5172
5255
  canWriteAnalysisRoot,
5173
5256
  BUILTIN_SERVER_RUNNER_COVERS,
5257
+ isAuxiliary,
5258
+ serverTraits,
5259
+ getStrategy,
5260
+ classifyServerWaitTier,
5261
+ classifyCascadeWaitTier,
5174
5262
  describeRootFallback,
5175
5263
  resolveLspServerCwd,
5176
5264
  resetLSPCaseSensitivityState,
@@ -5183,6 +5271,7 @@ export {
5183
5271
  resetClassicTsRepairGuard,
5184
5272
  LSP_SERVERS,
5185
5273
  getServerById,
5274
+ disabledPrimaries,
5186
5275
  shouldInitializeSessionRoot,
5187
5276
  isOutsideAllSessionRoots,
5188
5277
  getSessionRootsForTelemetry,
@@ -5195,8 +5284,5 @@ export {
5195
5284
  getServersForFileWithConfig,
5196
5285
  primaryServerId,
5197
5286
  resolveLspCwdForFile,
5198
- getServerInitOverride,
5199
- getStrategy,
5200
- classifyServerWaitTier,
5201
- classifyCascadeWaitTier
5287
+ getServerInitOverride
5202
5288
  };