@herbertgao/pi-extensions 2026.10.1 → 2026.10.2

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 (707) hide show
  1. package/README.md +13 -9
  2. package/THIRD_PARTY_NOTICES.md +2 -2
  3. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +2 -2
  4. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +2 -2
  5. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +1 -1
  6. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +1 -1
  7. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +2 -2
  8. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +1 -1
  9. package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +21 -21
  10. package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +1 -1
  11. package/node_modules/@dietrichgebert/ponytail/AGENTS.md +21 -21
  12. package/node_modules/@dietrichgebert/ponytail/README.md +68 -72
  13. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +7 -0
  14. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +30 -30
  15. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-map.js +103 -0
  16. package/node_modules/@dietrichgebert/ponytail/package.json +2 -2
  17. package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +33 -101
  18. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +89 -32
  19. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +13 -12
  20. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +17 -16
  21. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +9 -10
  22. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +96 -57
  23. package/node_modules/@herbertgao/pi-agency/LICENSE +21 -0
  24. package/node_modules/@herbertgao/pi-agency/README.md +40 -0
  25. package/node_modules/@herbertgao/pi-agency/package.json +53 -0
  26. package/node_modules/@herbertgao/pi-agency/src/index.ts +441 -0
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +12 -12
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +30 -6
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +15 -9
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +27 -9
  31. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +4 -1
  32. package/node_modules/@herbertgao/pi-cc-extensions/package.json +2 -2
  33. package/node_modules/@narumitw/pi-caffeinate/package.json +3 -3
  34. package/node_modules/@tifan/pi-mermaid-open/package.json +5 -1
  35. package/node_modules/@tifan/pi-mermaid-open/src/index.ts +26 -9
  36. package/node_modules/@tifan/pi-recap/package.json +1 -1
  37. package/node_modules/@tifan/pi-recap/src/index.ts +104 -20
  38. package/node_modules/@tifan/pi-recap/src/models.ts +46 -4
  39. package/node_modules/pi-antigravity/README.md +23 -2
  40. package/node_modules/pi-antigravity/package.json +5 -3
  41. package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +3 -2
  42. package/node_modules/pi-antigravity/src/features/generate-image.ts +72 -0
  43. package/node_modules/pi-antigravity/src/features/google-search.ts +71 -0
  44. package/node_modules/pi-antigravity/src/image/image.ts +86 -47
  45. package/node_modules/pi-antigravity/src/image/native.ts +69 -0
  46. package/node_modules/pi-antigravity/src/index.ts +52 -137
  47. package/node_modules/pi-antigravity/src/search/search.ts +130 -31
  48. package/node_modules/pi-antigravity/src/stream/stream.ts +162 -113
  49. package/node_modules/pi-antigravity/src/types/enums.ts +1 -0
  50. package/node_modules/pi-antigravity/src/types/types.ts +1 -1
  51. package/node_modules/pi-antigravity/src/utils/security.ts +47 -1
  52. package/node_modules/pi-antigravity/src/utils/util.ts +38 -6
  53. package/node_modules/pi-lens/CHANGELOG.md +1064 -0
  54. package/node_modules/pi-lens/README.md +115 -25
  55. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +6 -2
  56. package/node_modules/pi-lens/dist/chunk-22AVIGXS.js +560 -0
  57. package/node_modules/pi-lens/dist/chunk-27BBHSZC.js +106 -0
  58. package/node_modules/pi-lens/dist/chunk-2BEMIWEW.js +51 -0
  59. package/node_modules/pi-lens/dist/chunk-2EECBNC5.js +89 -0
  60. package/node_modules/pi-lens/dist/chunk-34U7PLGE.js +23 -0
  61. package/node_modules/pi-lens/dist/chunk-3I5QFT3N.js +181 -0
  62. package/node_modules/pi-lens/dist/chunk-3MED75HT.js +37 -0
  63. package/node_modules/pi-lens/dist/chunk-47D2BO4S.js +87 -0
  64. package/node_modules/pi-lens/dist/chunk-4RERDEXR.js +348 -0
  65. package/node_modules/pi-lens/dist/chunk-4W2PLC4J.js +27 -0
  66. package/node_modules/pi-lens/dist/chunk-52H5B5TC.js +202 -0
  67. package/node_modules/pi-lens/dist/chunk-54B42YRX.js +27 -0
  68. package/node_modules/pi-lens/dist/chunk-5RXBNSW2.js +266 -0
  69. package/node_modules/pi-lens/dist/chunk-5THXD6X5.js +201 -0
  70. package/node_modules/pi-lens/dist/chunk-5W3R6LFT.js +24 -0
  71. package/node_modules/pi-lens/dist/chunk-5ZEJHV35.js +341 -0
  72. package/node_modules/pi-lens/dist/chunk-6P62QVEA.js +118 -0
  73. package/node_modules/pi-lens/dist/chunk-6QIUX4EP.js +459 -0
  74. package/node_modules/pi-lens/dist/chunk-6VCD4VKZ.js +78 -0
  75. package/node_modules/pi-lens/dist/chunk-7F72PXY2.js +326 -0
  76. package/node_modules/pi-lens/dist/chunk-7FBF7NPR.js +998 -0
  77. package/node_modules/pi-lens/dist/chunk-7U2IDNXN.js +37 -0
  78. package/node_modules/pi-lens/dist/chunk-ABBOA7UD.js +157 -0
  79. package/node_modules/pi-lens/dist/chunk-AHDW3GPE.js +50 -0
  80. package/node_modules/pi-lens/dist/chunk-AJ3QXTRQ.js +756 -0
  81. package/node_modules/pi-lens/dist/chunk-AJVLWNFN.js +1610 -0
  82. package/node_modules/pi-lens/dist/chunk-AJXODZY6.js +112 -0
  83. package/node_modules/pi-lens/dist/chunk-ARFCXG7S.js +84 -0
  84. package/node_modules/pi-lens/dist/chunk-AS44CFQ4.js +708 -0
  85. package/node_modules/pi-lens/dist/chunk-AWE5TMPO.js +38 -0
  86. package/node_modules/pi-lens/dist/chunk-B3I2UUT4.js +4692 -0
  87. package/node_modules/pi-lens/dist/chunk-BRJKOBZP.js +331 -0
  88. package/node_modules/pi-lens/dist/chunk-BW5KFIQC.js +59 -0
  89. package/node_modules/pi-lens/dist/chunk-C2AUYXQH.js +149 -0
  90. package/node_modules/pi-lens/dist/chunk-CGGAIP7J.js +29 -0
  91. package/node_modules/pi-lens/dist/chunk-D6QS3U6M.js +30 -0
  92. package/node_modules/pi-lens/dist/chunk-DFVMIKMQ.js +349 -0
  93. package/node_modules/pi-lens/dist/chunk-DIULIWKU.js +169 -0
  94. package/node_modules/pi-lens/dist/chunk-DQ2NZ7C4.js +2317 -0
  95. package/node_modules/pi-lens/dist/chunk-E2WFBRHM.js +213 -0
  96. package/node_modules/pi-lens/dist/chunk-E4MAEDPM.js +50 -0
  97. package/node_modules/pi-lens/dist/chunk-EOKRQ3SA.js +30 -0
  98. package/node_modules/pi-lens/dist/chunk-F3AU2TMM.js +2626 -0
  99. package/node_modules/pi-lens/dist/chunk-F3P7VQ7H.js +170 -0
  100. package/node_modules/pi-lens/dist/chunk-FC4RP4I2.js +12 -0
  101. package/node_modules/pi-lens/dist/chunk-FJNKANOS.js +32 -0
  102. package/node_modules/pi-lens/dist/chunk-GUOGVTCQ.js +146 -0
  103. package/node_modules/pi-lens/dist/chunk-GVXA6CCE.js +18 -0
  104. package/node_modules/pi-lens/dist/chunk-HHYAELLJ.js +2334 -0
  105. package/node_modules/pi-lens/dist/chunk-HMFXILPV.js +83 -0
  106. package/node_modules/pi-lens/dist/chunk-HVUZXSWK.js +421 -0
  107. package/node_modules/pi-lens/dist/chunk-HWBZIGMJ.js +62 -0
  108. package/node_modules/pi-lens/dist/chunk-I3R7GKDR.js +17 -0
  109. package/node_modules/pi-lens/dist/chunk-I7SPGOWI.js +55 -0
  110. package/node_modules/pi-lens/dist/chunk-IIXOAGHR.js +38 -0
  111. package/node_modules/pi-lens/dist/chunk-IVP5KAB7.js +2250 -0
  112. package/node_modules/pi-lens/dist/chunk-IXEBJSUE.js +22 -0
  113. package/node_modules/pi-lens/dist/chunk-JOLITGCC.js +27 -0
  114. package/node_modules/pi-lens/dist/chunk-K6VYLB2U.js +145 -0
  115. package/node_modules/pi-lens/dist/chunk-LJDODBBZ.js +78 -0
  116. package/node_modules/pi-lens/dist/chunk-LNAKEO63.js +78 -0
  117. package/node_modules/pi-lens/dist/chunk-LSMJ6KBE.js +4139 -0
  118. package/node_modules/pi-lens/dist/chunk-LW6XKDZQ.js +5565 -0
  119. package/node_modules/pi-lens/dist/chunk-N3YQJI6O.js +899 -0
  120. package/node_modules/pi-lens/dist/chunk-NABLC7W3.js +148 -0
  121. package/node_modules/pi-lens/dist/chunk-NKOUFPQF.js +659 -0
  122. package/node_modules/pi-lens/dist/chunk-NL5GLMFI.js +211 -0
  123. package/node_modules/pi-lens/dist/chunk-NMABWBZN.js +327 -0
  124. package/node_modules/pi-lens/dist/chunk-NTHH2J74.js +27 -0
  125. package/node_modules/pi-lens/dist/chunk-NTUJEGDZ.js +59 -0
  126. package/node_modules/pi-lens/dist/chunk-NXL4FFQQ.js +47 -0
  127. package/node_modules/pi-lens/dist/chunk-NXPS2L6U.js +466 -0
  128. package/node_modules/pi-lens/dist/chunk-O5WILGMI.js +42 -0
  129. package/node_modules/pi-lens/dist/chunk-O6TQT6RI.js +48 -0
  130. package/node_modules/pi-lens/dist/chunk-OAXNDZJ7.js +323 -0
  131. package/node_modules/pi-lens/dist/chunk-ODEEOXPH.js +44 -0
  132. package/node_modules/pi-lens/dist/chunk-OQGFCZJ4.js +4533 -0
  133. package/node_modules/pi-lens/dist/chunk-ORTMY4Q4.js +282 -0
  134. package/node_modules/pi-lens/dist/chunk-OS32RNR2.js +442 -0
  135. package/node_modules/pi-lens/dist/chunk-PAK6IDME.js +189 -0
  136. package/node_modules/pi-lens/dist/chunk-PWFHBTSF.js +406 -0
  137. package/node_modules/pi-lens/dist/chunk-Q5U6FMDI.js +2352 -0
  138. package/node_modules/pi-lens/dist/chunk-QOZXJ4NA.js +3364 -0
  139. package/node_modules/pi-lens/dist/chunk-QYF5S6P6.js +45 -0
  140. package/node_modules/pi-lens/dist/chunk-RIISMHKN.js +36 -0
  141. package/node_modules/pi-lens/dist/chunk-RPD4ZSB7.js +25 -0
  142. package/node_modules/pi-lens/dist/chunk-RPD5K5NC.js +79 -0
  143. package/node_modules/pi-lens/dist/chunk-RUOG5D2C.js +262 -0
  144. package/node_modules/pi-lens/dist/chunk-T4ERT73Y.js +599 -0
  145. package/node_modules/pi-lens/dist/chunk-T6D4Q4AQ.js +54 -0
  146. package/node_modules/pi-lens/dist/chunk-TGPXLY2J.js +391 -0
  147. package/node_modules/pi-lens/dist/chunk-TLGFBM3F.js +12116 -0
  148. package/node_modules/pi-lens/dist/chunk-TO6WL3GM.js +88 -0
  149. package/node_modules/pi-lens/dist/chunk-TT22N74J.js +517 -0
  150. package/node_modules/pi-lens/dist/chunk-TVN5N6GY.js +21216 -0
  151. package/node_modules/pi-lens/dist/chunk-U3VGR4VU.js +308 -0
  152. package/node_modules/pi-lens/dist/chunk-UK3CMEAL.js +1250 -0
  153. package/node_modules/pi-lens/dist/chunk-UOPVJQ4N.js +103 -0
  154. package/node_modules/pi-lens/dist/chunk-UXVNL3D7.js +23 -0
  155. package/node_modules/pi-lens/dist/chunk-UY752QSN.js +45 -0
  156. package/node_modules/pi-lens/dist/chunk-V5PXFSZK.js +188 -0
  157. package/node_modules/pi-lens/dist/chunk-V7R425XG.js +398 -0
  158. package/node_modules/pi-lens/dist/chunk-VCSRSYLF.js +81 -0
  159. package/node_modules/pi-lens/dist/chunk-VD4JQCQC.js +162 -0
  160. package/node_modules/pi-lens/dist/chunk-VDBPVIKD.js +62 -0
  161. package/node_modules/pi-lens/dist/chunk-VHQLPIRJ.js +114 -0
  162. package/node_modules/pi-lens/dist/chunk-VN2AXLEX.js +5414 -0
  163. package/node_modules/pi-lens/dist/chunk-VNMT7C64.js +478 -0
  164. package/node_modules/pi-lens/dist/chunk-WONERJTP.js +309 -0
  165. package/node_modules/pi-lens/dist/chunk-XECLWQZN.js +85 -0
  166. package/node_modules/pi-lens/dist/chunk-XIMYZ3JA.js +27 -0
  167. package/node_modules/pi-lens/dist/chunk-XK4CIILI.js +144 -0
  168. package/node_modules/pi-lens/dist/chunk-Y4T27COV.js +562 -0
  169. package/node_modules/pi-lens/dist/chunk-YGVYKNSN.js +1860 -0
  170. package/node_modules/pi-lens/dist/chunk-YLF3PPT5.js +308 -0
  171. package/node_modules/pi-lens/dist/chunk-YSNFMJKN.js +14 -0
  172. package/node_modules/pi-lens/dist/chunk-Z3CCVDUB.js +76 -0
  173. package/node_modules/pi-lens/dist/chunk-Z54ZSOBZ.js +61 -0
  174. package/node_modules/pi-lens/dist/chunk-ZAWW3AF6.js +97 -0
  175. package/node_modules/pi-lens/dist/chunk-ZMOL6RQC.js +167 -0
  176. package/node_modules/pi-lens/dist/index.js +16456 -8335
  177. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +186 -232
  178. package/node_modules/pi-lens/dist/mcp/cli.js +137 -98
  179. package/node_modules/pi-lens/dist/mcp/server.js +22589 -1573
  180. package/node_modules/pi-lens/dist/mcp/worker.js +97 -38
  181. package/node_modules/pi-lens/dist/probes/installer.js +135 -0
  182. package/node_modules/pi-lens/dist/workers/project-snapshot-persist-worker.js +22 -0
  183. package/node_modules/pi-lens/dist/workers/review-graph-persist-worker.js +15 -0
  184. package/node_modules/pi-lens/docs/agent-guide.md +13 -4
  185. package/node_modules/pi-lens/docs/agent-tools.md +42 -0
  186. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +3 -2
  187. package/node_modules/pi-lens/docs/configuration.md +20 -1
  188. package/node_modules/pi-lens/docs/environment-variables.md +52 -2
  189. package/node_modules/pi-lens/docs/features.md +8 -4
  190. package/node_modules/pi-lens/docs/globalconfig.md +1 -0
  191. package/node_modules/pi-lens/docs/io-bridge-v2-migration.md +94 -0
  192. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +36 -4
  193. package/node_modules/pi-lens/docs/lsp-idle-eviction.md +124 -0
  194. package/node_modules/pi-lens/docs/mcp.md +21 -5
  195. package/node_modules/pi-lens/docs/merge-queue-rollout.md +77 -0
  196. package/node_modules/pi-lens/docs/pi-lens-fixer.md +156 -88
  197. package/node_modules/pi-lens/docs/pi-lens-investigator.md +74 -26
  198. package/node_modules/pi-lens/docs/pi-lens-merge-policy.md +694 -0
  199. package/node_modules/pi-lens/docs/pi-lens-monitor.md +73 -7
  200. package/node_modules/pi-lens/docs/pi-lens-retro.md +6 -4
  201. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +188 -48
  202. package/node_modules/pi-lens/docs/pi-lens-subagent.md +246 -45
  203. package/node_modules/pi-lens/docs/pi-lens-warden.md +18 -7
  204. package/node_modules/pi-lens/docs/public-api-stability.md +55 -0
  205. package/node_modules/pi-lens/docs/release-qa-baseline.md +84 -17
  206. package/node_modules/pi-lens/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  207. package/node_modules/pi-lens/docs/servercapabilities.md +53 -49
  208. package/node_modules/pi-lens/docs/settings.md +1 -0
  209. package/node_modules/pi-lens/docs/usage.md +5 -1
  210. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm +0 -0
  211. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm.json +3 -3
  212. package/node_modules/pi-lens/package.json +18 -6
  213. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  214. package/node_modules/pi-lens/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  215. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +1275 -62
  216. package/node_modules/pi-lens/scripts/download-grammars.js +5 -0
  217. package/node_modules/pi-lens/scripts/grammars.lock.json +6 -1
  218. package/node_modules/pi-lens/scripts/install-selftest.mjs +33 -34
  219. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +13 -4
  220. package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +18 -0
  221. package/package.json +15 -10
  222. package/node_modules/@dietrichgebert/ponytail/README.es.md +0 -212
  223. package/node_modules/@dietrichgebert/ponytail/README.ja.md +0 -212
  224. package/node_modules/@dietrichgebert/ponytail/README.ko.md +0 -212
  225. package/node_modules/@dietrichgebert/ponytail/README.zh-CN.md +0 -212
  226. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -35
  227. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +0 -1610
  228. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +0 -593
  229. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +0 -147
  230. package/node_modules/pi-lens/dist/clients/agent-nudge.js +0 -325
  231. package/node_modules/pi-lens/dist/clients/analysed-root.js +0 -1
  232. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +0 -731
  233. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +0 -146
  234. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +0 -118
  235. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -10
  236. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +0 -154
  237. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +0 -75
  238. package/node_modules/pi-lens/dist/clients/atomic-write.js +0 -189
  239. package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +0 -12
  240. package/node_modules/pi-lens/dist/clients/bash-file-access.js +0 -1056
  241. package/node_modules/pi-lens/dist/clients/biome-client.js +0 -357
  242. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -837
  243. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +0 -129
  244. package/node_modules/pi-lens/dist/clients/bootstrap.js +0 -569
  245. package/node_modules/pi-lens/dist/clients/bounded-cache.js +0 -190
  246. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +0 -202
  247. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +0 -295
  248. package/node_modules/pi-lens/dist/clients/build-identity.js +0 -95
  249. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +0 -113
  250. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +0 -105
  251. package/node_modules/pi-lens/dist/clients/bus-publish.js +0 -171
  252. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +0 -190
  253. package/node_modules/pi-lens/dist/clients/cache-manager.js +0 -524
  254. package/node_modules/pi-lens/dist/clients/cache-observability.js +0 -1313
  255. package/node_modules/pi-lens/dist/clients/call-graph.js +0 -852
  256. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +0 -422
  257. package/node_modules/pi-lens/dist/clients/cascade-budget.js +0 -196
  258. package/node_modules/pi-lens/dist/clients/cascade-format.js +0 -315
  259. package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -31
  260. package/node_modules/pi-lens/dist/clients/cascade-types.js +0 -9
  261. package/node_modules/pi-lens/dist/clients/child-unref.js +0 -124
  262. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +0 -286
  263. package/node_modules/pi-lens/dist/clients/codebase-model.js +0 -173
  264. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +0 -40
  265. package/node_modules/pi-lens/dist/clients/complexity-client.js +0 -462
  266. package/node_modules/pi-lens/dist/clients/config-core/deny.js +0 -221
  267. package/node_modules/pi-lens/dist/clients/config-core/index.js +0 -50
  268. package/node_modules/pi-lens/dist/clients/config-core/merge.js +0 -357
  269. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +0 -340
  270. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +0 -248
  271. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +0 -164
  272. package/node_modules/pi-lens/dist/clients/config-core/records.js +0 -218
  273. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +0 -125
  274. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +0 -78
  275. package/node_modules/pi-lens/dist/clients/config-core/schema.js +0 -165
  276. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +0 -285
  277. package/node_modules/pi-lens/dist/clients/config-locations.js +0 -388
  278. package/node_modules/pi-lens/dist/clients/config-resolve.js +0 -798
  279. package/node_modules/pi-lens/dist/clients/config-schema.js +0 -251
  280. package/node_modules/pi-lens/dist/clients/config-warn.js +0 -407
  281. package/node_modules/pi-lens/dist/clients/console-guard-install.js +0 -26
  282. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +0 -42
  283. package/node_modules/pi-lens/dist/clients/dead-code-client.js +0 -510
  284. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -30
  285. package/node_modules/pi-lens/dist/clients/deadline-utils.js +0 -280
  286. package/node_modules/pi-lens/dist/clients/debug-handles.js +0 -211
  287. package/node_modules/pi-lens/dist/clients/debug-heap.js +0 -174
  288. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +0 -106
  289. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +0 -426
  290. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +0 -169
  291. package/node_modules/pi-lens/dist/clients/dependency-checker.js +0 -885
  292. package/node_modules/pi-lens/dist/clients/deps/ast-grep-napi.js +0 -22
  293. package/node_modules/pi-lens/dist/clients/deps/js-yaml.js +0 -9
  294. package/node_modules/pi-lens/dist/clients/deps/minimatch.js +0 -4
  295. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +0 -14
  296. package/node_modules/pi-lens/dist/clients/deps/typebox.js +0 -14
  297. package/node_modules/pi-lens/dist/clients/deps/vscode-jsonrpc.js +0 -1
  298. package/node_modules/pi-lens/dist/clients/deps/web-tree-sitter.js +0 -24
  299. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +0 -630
  300. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +0 -305
  301. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +0 -73
  302. package/node_modules/pi-lens/dist/clients/diagnostic-tracker.js +0 -105
  303. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +0 -230
  304. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  305. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  306. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -35
  307. package/node_modules/pi-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  308. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +0 -1269
  309. package/node_modules/pi-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
  310. package/node_modules/pi-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
  311. package/node_modules/pi-lens/dist/clients/dispatch/fact-runner.js +0 -30
  312. package/node_modules/pi-lens/dist/clients/dispatch/fact-scheduler.js +0 -68
  313. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +0 -377
  314. package/node_modules/pi-lens/dist/clients/dispatch/facts/comment-facts.js +0 -22
  315. package/node_modules/pi-lens/dist/clients/dispatch/facts/file-content.js +0 -19
  316. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +0 -348
  317. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +0 -204
  318. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  319. package/node_modules/pi-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  320. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +0 -339
  321. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +0 -417
  322. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +0 -89
  323. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +0 -2377
  324. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -11
  325. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +0 -87
  326. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -278
  327. package/node_modules/pi-lens/dist/clients/dispatch/priorities.js +0 -20
  328. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +0 -50
  329. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +0 -69
  330. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +0 -135
  331. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-noise.js +0 -40
  332. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  333. package/node_modules/pi-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  334. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  335. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  336. package/node_modules/pi-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  337. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +0 -72
  338. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  339. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  340. package/node_modules/pi-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  341. package/node_modules/pi-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  342. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  343. package/node_modules/pi-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  344. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  345. package/node_modules/pi-lens/dist/clients/dispatch/runner-context.js +0 -52
  346. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -111
  347. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  348. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -296
  349. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -219
  350. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -82
  351. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -416
  352. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -183
  353. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -176
  354. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -164
  355. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -195
  356. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -137
  357. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -29
  358. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -69
  359. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -167
  360. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +0 -104
  361. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -135
  362. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -91
  363. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -171
  364. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -940
  365. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -117
  366. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +0 -108
  367. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -99
  368. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -110
  369. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -379
  370. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -167
  371. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -102
  372. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +0 -414
  373. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -85
  374. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -120
  375. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  376. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  377. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +0 -169
  378. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -99
  379. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -88
  380. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -256
  381. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -173
  382. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -102
  383. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -128
  384. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -259
  385. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -183
  386. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -166
  387. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -163
  388. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -174
  389. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -168
  390. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -125
  391. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -643
  392. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -253
  393. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  394. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  395. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
  396. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  397. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  398. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  399. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  400. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  401. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -15
  402. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -128
  403. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  404. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -95
  405. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -79
  406. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +0 -79
  407. package/node_modules/pi-lens/dist/clients/dispatch/tool-profile.js +0 -30
  408. package/node_modules/pi-lens/dist/clients/dispatch/types.js +0 -21
  409. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
  410. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  411. package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -32
  412. package/node_modules/pi-lens/dist/clients/disposition-publish.js +0 -124
  413. package/node_modules/pi-lens/dist/clients/durable-store.js +0 -97
  414. package/node_modules/pi-lens/dist/clients/effective-config.js +0 -415
  415. package/node_modules/pi-lens/dist/clients/env-utils.js +0 -83
  416. package/node_modules/pi-lens/dist/clients/error-class.js +0 -23
  417. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +0 -17
  418. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +0 -274
  419. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +0 -250
  420. package/node_modules/pi-lens/dist/clients/extension-log.js +0 -504
  421. package/node_modules/pi-lens/dist/clients/extension-mode.js +0 -73
  422. package/node_modules/pi-lens/dist/clients/feature-hints.js +0 -103
  423. package/node_modules/pi-lens/dist/clients/file-kinds.js +0 -412
  424. package/node_modules/pi-lens/dist/clients/file-role.js +0 -134
  425. package/node_modules/pi-lens/dist/clients/file-time.js +0 -160
  426. package/node_modules/pi-lens/dist/clients/file-utils.js +0 -1032
  427. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +0 -494
  428. package/node_modules/pi-lens/dist/clients/finding-identity.js +0 -88
  429. package/node_modules/pi-lens/dist/clients/fix-worklog.js +0 -103
  430. package/node_modules/pi-lens/dist/clients/format-events-publish.js +0 -343
  431. package/node_modules/pi-lens/dist/clients/format-service.js +0 -222
  432. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +0 -9
  433. package/node_modules/pi-lens/dist/clients/formatters.js +0 -2032
  434. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +0 -17
  435. package/node_modules/pi-lens/dist/clients/freshness.js +0 -38
  436. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +0 -394
  437. package/node_modules/pi-lens/dist/clients/generation-guard.js +0 -215
  438. package/node_modules/pi-lens/dist/clients/git-guard.js +0 -1136
  439. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +0 -243
  440. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +0 -509
  441. package/node_modules/pi-lens/dist/clients/go-client.js +0 -104
  442. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +0 -605
  443. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +0 -348
  444. package/node_modules/pi-lens/dist/clients/grammar-source.js +0 -465
  445. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +0 -135
  446. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +0 -424
  447. package/node_modules/pi-lens/dist/clients/hook-budgets.js +0 -76
  448. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +0 -140
  449. package/node_modules/pi-lens/dist/clients/host-ports.js +0 -39
  450. package/node_modules/pi-lens/dist/clients/indent-retarget.js +0 -154
  451. package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +0 -186
  452. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +0 -156
  453. package/node_modules/pi-lens/dist/clients/installer/index.js +0 -5416
  454. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  455. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +0 -783
  456. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +0 -7
  457. package/node_modules/pi-lens/dist/clients/instance-reaper.js +0 -1137
  458. package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +0 -145
  459. package/node_modules/pi-lens/dist/clients/instance-registry.js +0 -773
  460. package/node_modules/pi-lens/dist/clients/jscpd-client.js +0 -378
  461. package/node_modules/pi-lens/dist/clients/json-cache-read.js +0 -65
  462. package/node_modules/pi-lens/dist/clients/knip-client.js +0 -788
  463. package/node_modules/pi-lens/dist/clients/language-policy.js +0 -252
  464. package/node_modules/pi-lens/dist/clients/language-profile.js +0 -361
  465. package/node_modules/pi-lens/dist/clients/language-registry.js +0 -603
  466. package/node_modules/pi-lens/dist/clients/latency-logger.js +0 -727
  467. package/node_modules/pi-lens/dist/clients/lazy-import.js +0 -21
  468. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +0 -54
  469. package/node_modules/pi-lens/dist/clients/lens-config.js +0 -404
  470. package/node_modules/pi-lens/dist/clients/lens-engine.js +0 -358
  471. package/node_modules/pi-lens/dist/clients/lens-events.js +0 -125
  472. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +0 -467
  473. package/node_modules/pi-lens/dist/clients/lens-map.js +0 -1156
  474. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +0 -74
  475. package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -222
  476. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +0 -178
  477. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +0 -421
  478. package/node_modules/pi-lens/dist/clients/lsp/client.js +0 -4593
  479. package/node_modules/pi-lens/dist/clients/lsp/config.js +0 -691
  480. package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +0 -41
  481. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +0 -225
  482. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +0 -467
  483. package/node_modules/pi-lens/dist/clients/lsp/edits.js +0 -1219
  484. package/node_modules/pi-lens/dist/clients/lsp/index.js +0 -8305
  485. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +0 -216
  486. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +0 -298
  487. package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -63
  488. package/node_modules/pi-lens/dist/clients/lsp/launch.js +0 -746
  489. package/node_modules/pi-lens/dist/clients/lsp/lombok.js +0 -158
  490. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +0 -5
  491. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -251
  492. package/node_modules/pi-lens/dist/clients/lsp/position-encoding.js +0 -61
  493. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  494. package/node_modules/pi-lens/dist/clients/lsp/server.js +0 -3290
  495. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +0 -192
  496. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +0 -17
  497. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -56
  498. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +0 -332
  499. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  500. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +0 -85
  501. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/index.js +0 -10
  502. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +0 -392
  503. package/node_modules/pi-lens/dist/clients/lsp/watch-queue.js +0 -61
  504. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  505. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  506. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  507. package/node_modules/pi-lens/dist/clients/lsp-budget.js +0 -186
  508. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +0 -110
  509. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +0 -9
  510. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +0 -396
  511. package/node_modules/pi-lens/dist/clients/lsp-status.js +0 -59
  512. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +0 -40
  513. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +0 -420
  514. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +0 -31
  515. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +0 -523
  516. package/node_modules/pi-lens/dist/clients/mcp/review.js +0 -197
  517. package/node_modules/pi-lens/dist/clients/mcp/session.js +0 -412
  518. package/node_modules/pi-lens/dist/clients/memory-sampler.js +0 -208
  519. package/node_modules/pi-lens/dist/clients/message-end-attribution.js +0 -30
  520. package/node_modules/pi-lens/dist/clients/metrics-client.js +0 -107
  521. package/node_modules/pi-lens/dist/clients/metrics-history.js +0 -327
  522. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +0 -263
  523. package/node_modules/pi-lens/dist/clients/model-provider.js +0 -53
  524. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +0 -189
  525. package/node_modules/pi-lens/dist/clients/module-report.js +0 -2150
  526. package/node_modules/pi-lens/dist/clients/mutating-tool.js +0 -651
  527. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +0 -368
  528. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +0 -240
  529. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -734
  530. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +0 -101
  531. package/node_modules/pi-lens/dist/clients/observed-mutation.js +0 -1253
  532. package/node_modules/pi-lens/dist/clients/oldtext-autopatch.js +0 -128
  533. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +0 -496
  534. package/node_modules/pi-lens/dist/clients/opengrep-client.js +0 -333
  535. package/node_modules/pi-lens/dist/clients/opengrep-config.js +0 -76
  536. package/node_modules/pi-lens/dist/clients/package-manager.js +0 -607
  537. package/node_modules/pi-lens/dist/clients/package-root.js +0 -38
  538. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +0 -439
  539. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +0 -43
  540. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +0 -108
  541. package/node_modules/pi-lens/dist/clients/path-utils.js +0 -1244
  542. package/node_modules/pi-lens/dist/clients/performance-report.js +0 -331
  543. package/node_modules/pi-lens/dist/clients/persist-debounce.js +0 -70
  544. package/node_modules/pi-lens/dist/clients/persistent-reverify.js +0 -271
  545. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +0 -119
  546. package/node_modules/pi-lens/dist/clients/pipeline.js +0 -1480
  547. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +0 -37
  548. package/node_modules/pi-lens/dist/clients/print-mode.js +0 -21
  549. package/node_modules/pi-lens/dist/clients/probe-home-state.js +0 -228
  550. package/node_modules/pi-lens/dist/clients/process-bridge.js +0 -66
  551. package/node_modules/pi-lens/dist/clients/process-singletons.js +0 -210
  552. package/node_modules/pi-lens/dist/clients/process-snapshot.js +0 -68
  553. package/node_modules/pi-lens/dist/clients/project-changes.js +0 -181
  554. package/node_modules/pi-lens/dist/clients/project-conventions.js +0 -171
  555. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +0 -137
  556. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +0 -109
  557. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
  558. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  559. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  560. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  561. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  562. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  563. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  564. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  565. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  566. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  567. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  568. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +0 -520
  569. package/node_modules/pi-lens/dist/clients/project-diagnostics/types.js +0 -1
  570. package/node_modules/pi-lens/dist/clients/project-lens-config.js +0 -807
  571. package/node_modules/pi-lens/dist/clients/project-report.js +0 -701
  572. package/node_modules/pi-lens/dist/clients/project-scale.js +0 -237
  573. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +0 -11
  574. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +0 -48
  575. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +0 -20
  576. package/node_modules/pi-lens/dist/clients/project-snapshot.js +0 -1653
  577. package/node_modules/pi-lens/dist/clients/project-trust.js +0 -181
  578. package/node_modules/pi-lens/dist/clients/python-environment.js +0 -217
  579. package/node_modules/pi-lens/dist/clients/python-provenance.js +0 -639
  580. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +0 -47
  581. package/node_modules/pi-lens/dist/clients/quiet-window.js +0 -236
  582. package/node_modules/pi-lens/dist/clients/read-bridge.js +0 -139
  583. package/node_modules/pi-lens/dist/clients/read-expansion.js +0 -266
  584. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +0 -251
  585. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +0 -1306
  586. package/node_modules/pi-lens/dist/clients/read-guard.js +0 -1561
  587. package/node_modules/pi-lens/dist/clients/recent-touches.js +0 -240
  588. package/node_modules/pi-lens/dist/clients/redact/secrets.js +0 -449
  589. package/node_modules/pi-lens/dist/clients/resource-sampler.js +0 -628
  590. package/node_modules/pi-lens/dist/clients/reverse-deps.js +0 -270
  591. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +0 -5126
  592. package/node_modules/pi-lens/dist/clients/review-graph/format.js +0 -33
  593. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +0 -163
  594. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +0 -481
  595. package/node_modules/pi-lens/dist/clients/review-graph/persist-worker.js +0 -10
  596. package/node_modules/pi-lens/dist/clients/review-graph/query.js +0 -244
  597. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +0 -21
  598. package/node_modules/pi-lens/dist/clients/review-graph/service.js +0 -96
  599. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  600. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +0 -103
  601. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +0 -299
  602. package/node_modules/pi-lens/dist/clients/review-graph/types.js +0 -1
  603. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +0 -449
  604. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +0 -81
  605. package/node_modules/pi-lens/dist/clients/ruff-client.js +0 -179
  606. package/node_modules/pi-lens/dist/clients/rules-scanner.js +0 -131
  607. package/node_modules/pi-lens/dist/clients/run-duration.js +0 -55
  608. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +0 -746
  609. package/node_modules/pi-lens/dist/clients/runtime-config.js +0 -77
  610. package/node_modules/pi-lens/dist/clients/runtime-context.js +0 -211
  611. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +0 -1324
  612. package/node_modules/pi-lens/dist/clients/runtime-session.js +0 -2485
  613. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +0 -1295
  614. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +0 -2049
  615. package/node_modules/pi-lens/dist/clients/runtime-turn.js +0 -3767
  616. package/node_modules/pi-lens/dist/clients/rust-client.js +0 -97
  617. package/node_modules/pi-lens/dist/clients/safe-spawn.js +0 -2357
  618. package/node_modules/pi-lens/dist/clients/sanitize.js +0 -286
  619. package/node_modules/pi-lens/dist/clients/scan-utils.js +0 -25
  620. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +0 -165
  621. package/node_modules/pi-lens/dist/clients/search-read-registration.js +0 -94
  622. package/node_modules/pi-lens/dist/clients/secret-findings.js +0 -114
  623. package/node_modules/pi-lens/dist/clients/security-scan-client.js +0 -352
  624. package/node_modules/pi-lens/dist/clients/session-event-guard.js +0 -297
  625. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +0 -484
  626. package/node_modules/pi-lens/dist/clients/session-start-observability.js +0 -94
  627. package/node_modules/pi-lens/dist/clients/session-state-store.js +0 -101
  628. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -15
  629. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +0 -27
  630. package/node_modules/pi-lens/dist/clients/sg-runner.js +0 -876
  631. package/node_modules/pi-lens/dist/clients/sgconfig.js +0 -347
  632. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +0 -338
  633. package/node_modules/pi-lens/dist/clients/single-flight.js +0 -158
  634. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +0 -108
  635. package/node_modules/pi-lens/dist/clients/skills-resolver.js +0 -141
  636. package/node_modules/pi-lens/dist/clients/slow-fs.js +0 -138
  637. package/node_modules/pi-lens/dist/clients/smells-rollup.js +0 -231
  638. package/node_modules/pi-lens/dist/clients/source-filter.js +0 -596
  639. package/node_modules/pi-lens/dist/clients/source-walker.js +0 -211
  640. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +0 -120
  641. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +0 -110
  642. package/node_modules/pi-lens/dist/clients/stale-marker.js +0 -17
  643. package/node_modules/pi-lens/dist/clients/startup-scan.js +0 -400
  644. package/node_modules/pi-lens/dist/clients/startup-timing.js +0 -130
  645. package/node_modules/pi-lens/dist/clients/string-utils.js +0 -33
  646. package/node_modules/pi-lens/dist/clients/subagent-mode.js +0 -111
  647. package/node_modules/pi-lens/dist/clients/symbol-containment.js +0 -24
  648. package/node_modules/pi-lens/dist/clients/symbol-types.js +0 -5
  649. package/node_modules/pi-lens/dist/clients/test-runner-client.js +0 -2507
  650. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +0 -287
  651. package/node_modules/pi-lens/dist/clients/todo-scanner.js +0 -229
  652. package/node_modules/pi-lens/dist/clients/tool-agreement.js +0 -423
  653. package/node_modules/pi-lens/dist/clients/tool-config.js +0 -249
  654. package/node_modules/pi-lens/dist/clients/tool-cwd.js +0 -270
  655. package/node_modules/pi-lens/dist/clients/tool-definition.js +0 -47
  656. package/node_modules/pi-lens/dist/clients/tool-event.js +0 -105
  657. package/node_modules/pi-lens/dist/clients/tool-policy.js +0 -2755
  658. package/node_modules/pi-lens/dist/clients/tool-probe.js +0 -53
  659. package/node_modules/pi-lens/dist/clients/tool-render.js +0 -156
  660. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +0 -118
  661. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +0 -364
  662. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +0 -4195
  663. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +0 -100
  664. package/node_modules/pi-lens/dist/clients/tree-sitter-navigator.js +0 -269
  665. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +0 -569
  666. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +0 -158
  667. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  668. package/node_modules/pi-lens/dist/clients/trivy-client.js +0 -467
  669. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -50
  670. package/node_modules/pi-lens/dist/clients/turn-context.js +0 -52
  671. package/node_modules/pi-lens/dist/clients/turn-end/lane.js +0 -51
  672. package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -112
  673. package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +0 -204
  674. package/node_modules/pi-lens/dist/clients/turn-summary-render.js +0 -72
  675. package/node_modules/pi-lens/dist/clients/turn-summary.js +0 -132
  676. package/node_modules/pi-lens/dist/clients/typos-config.js +0 -29
  677. package/node_modules/pi-lens/dist/clients/user-notify.js +0 -51
  678. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +0 -57
  679. package/node_modules/pi-lens/dist/clients/warm-attach.js +0 -305
  680. package/node_modules/pi-lens/dist/clients/widget-state.js +0 -1808
  681. package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -49
  682. package/node_modules/pi-lens/dist/clients/word-index-store.js +0 -459
  683. package/node_modules/pi-lens/dist/clients/word-index.js +0 -2080
  684. package/node_modules/pi-lens/dist/clients/workspace-topology.js +0 -443
  685. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +0 -65
  686. package/node_modules/pi-lens/dist/clients/zizmor-config.js +0 -340
  687. package/node_modules/pi-lens/dist/i18n.js +0 -69
  688. package/node_modules/pi-lens/dist/mcp/build-staleness.js +0 -124
  689. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +0 -583
  690. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +0 -129
  691. package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
  692. package/node_modules/pi-lens/dist/tools/activate-tools.js +0 -87
  693. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +0 -137
  694. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +0 -244
  695. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +0 -762
  696. package/node_modules/pi-lens/dist/tools/effective-config.js +0 -90
  697. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +0 -375
  698. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +0 -2571
  699. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +0 -1745
  700. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +0 -1367
  701. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +0 -294
  702. package/node_modules/pi-lens/dist/tools/module-report.js +0 -382
  703. package/node_modules/pi-lens/dist/tools/project-report.js +0 -86
  704. package/node_modules/pi-lens/dist/tools/render-compact.js +0 -374
  705. package/node_modules/pi-lens/dist/tools/scan-progress.js +0 -53
  706. package/node_modules/pi-lens/dist/tools/shared.js +0 -29
  707. package/node_modules/pi-lens/dist/tools/symbol-search.js +0 -155
@@ -0,0 +1,4692 @@
1
+ import { createRequire as __pilensCreateRequire } from "node:module"; const require = __pilensCreateRequire(import.meta.url);
2
+ import {
3
+ augmentPythonEnvironment,
4
+ detectPythonEnvironment,
5
+ detectPythonVenv,
6
+ pythonEnvironmentToolCandidates
7
+ } from "./chunk-DIULIWKU.js";
8
+ import {
9
+ resolveOpengrepConfig
10
+ } from "./chunk-VDBPVIKD.js";
11
+ import {
12
+ extensionsForLanguage
13
+ } from "./chunk-TGPXLY2J.js";
14
+ import {
15
+ load,
16
+ resolvePackagePath
17
+ } from "./chunk-QOZXJ4NA.js";
18
+ import {
19
+ hasCargoWorkspaceTable,
20
+ readCargoWorkspaceExclude,
21
+ readCargoWorkspaceMembers,
22
+ readTextFileOrUndefined
23
+ } from "./chunk-PAK6IDME.js";
24
+ import {
25
+ HOOK_WALL_BUDGET_MS,
26
+ bounded
27
+ } from "./chunk-GUOGVTCQ.js";
28
+ import {
29
+ ensureTool,
30
+ findManagedToolBinary,
31
+ getInstallAttempt,
32
+ getToolEnvironment,
33
+ getToolPath,
34
+ isZizmorAuditTarget,
35
+ logSessionStart,
36
+ resolveZizmorGitHubToken
37
+ } from "./chunk-OQGFCZJ4.js";
38
+ import {
39
+ resolveToolCwd
40
+ } from "./chunk-RUOG5D2C.js";
41
+ import {
42
+ findGlobalBinary
43
+ } from "./chunk-U3VGR4VU.js";
44
+ import {
45
+ classifyProbeFailure,
46
+ createAvailabilityLatch,
47
+ describeInstallAttempt,
48
+ logAvailabilityDecision,
49
+ startHostStallSampler
50
+ } from "./chunk-WONERJTP.js";
51
+ import {
52
+ OWNER_TAG_ENV,
53
+ SpawnFailureError,
54
+ classifySpawnFailure,
55
+ createGenerationSource,
56
+ ephemeralStagingRoot,
57
+ getGlobalPiLensDir,
58
+ getProjectIgnoreGlobs,
59
+ hasSpawnFailureKind,
60
+ holdOwnChildPid,
61
+ isCommandAvailableAsync,
62
+ isPathIgnoredByProject,
63
+ ownerTagForChildren,
64
+ safeSpawnAsync
65
+ } from "./chunk-VN2AXLEX.js";
66
+ import {
67
+ DOTNET_CSHARP_ROOT_MARKERS,
68
+ DOTNET_FSHARP_ROOT_MARKERS,
69
+ KIND_EXTENSIONS
70
+ } from "./chunk-5ZEJHV35.js";
71
+ import {
72
+ lspSectionOf,
73
+ migrationSubject,
74
+ reportConfigReadFailure,
75
+ reportPiLensConfigRecords,
76
+ resolvePiLensConfig,
77
+ summarizeConfigResolution
78
+ } from "./chunk-DQ2NZ7C4.js";
79
+ import {
80
+ FRESHNESS_CADENCE_MS,
81
+ LSP_NAMESPACE_KEY,
82
+ dirMtimeRecordsAsync,
83
+ dirMtimesStillFreshAsync,
84
+ getPiLensGlobalConfigPath,
85
+ unknownDirMtimeRecords
86
+ } from "./chunk-VNMT7C64.js";
87
+ import {
88
+ incrementDegradationCount,
89
+ recordDegradationOnce
90
+ } from "./chunk-N3YQJI6O.js";
91
+ import {
92
+ claimPhaseOncePerSession,
93
+ currentSessionRecordId,
94
+ logLatency,
95
+ releasePhaseClaim
96
+ } from "./chunk-5THXD6X5.js";
97
+ import {
98
+ getGlobalPiLensLogDir,
99
+ getProcessSingleton,
100
+ isTestMode,
101
+ redactSecrets
102
+ } from "./chunk-UK3CMEAL.js";
103
+ import {
104
+ STAGE_TMP_PATTERN
105
+ } from "./chunk-LJDODBBZ.js";
106
+ import {
107
+ BoundedFifoMap,
108
+ BoundedLruCache
109
+ } from "./chunk-ABBOA7UD.js";
110
+ import {
111
+ CARGO_WORKSPACE_MEMBER_DIALECT,
112
+ direntsHaveMarkerGlobMatch,
113
+ findLocalToolConfig,
114
+ isAtOrAboveHomeDir,
115
+ isFullyQualified,
116
+ isWindowsPath,
117
+ matchesWorkspaceMemberPattern,
118
+ normalizeEphemeralMapKey,
119
+ normalizeFilePath,
120
+ normalizeMapKey,
121
+ pathsEqual,
122
+ toPosix
123
+ } from "./chunk-Q5U6FMDI.js";
124
+ import {
125
+ __require
126
+ } from "./chunk-NXL4FFQQ.js";
127
+
128
+ // dist/clients/lsp/server.js
129
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, statSync as statSync3 } from "node:fs";
130
+ import { access, readFile, readdir, stat } from "node:fs/promises";
131
+ import os6 from "node:os";
132
+ import path7 from "node:path";
133
+
134
+ // dist/clients/sgconfig.js
135
+ import { createHash } from "node:crypto";
136
+ import * as fs from "node:fs";
137
+ import * as os from "node:os";
138
+ import * as path from "node:path";
139
+ var SGCONFIG_NAMES = ["sgconfig.yml", "sgconfig.yaml"];
140
+ function findLocalSgconfig(startDir) {
141
+ return findLocalToolConfig(startDir, SGCONFIG_NAMES);
142
+ }
143
+ function canonicalDir(dir) {
144
+ try {
145
+ return fs.realpathSync.native(dir);
146
+ } catch {
147
+ return path.resolve(dir);
148
+ }
149
+ }
150
+ function getAstGrepRuleSources(projectRoot = process.cwd()) {
151
+ const root = path.resolve(projectRoot || process.cwd());
152
+ const packageRoot = resolvePackagePath(import.meta.url);
153
+ const candidates = [];
154
+ if (canonicalDir(root) !== canonicalDir(packageRoot)) {
155
+ candidates.push({
156
+ dir: path.join(root, "rules", "ast-grep-rules", "rules"),
157
+ origin: "project",
158
+ tier: "primary"
159
+ }, {
160
+ dir: path.join(root, "rules", "ast-grep-rules", "coderabbit", "rules"),
161
+ origin: "project",
162
+ tier: "secondary"
163
+ });
164
+ }
165
+ candidates.push({
166
+ dir: path.join(packageRoot, "rules", "ast-grep-rules", "rules"),
167
+ origin: "bundled",
168
+ tier: "primary"
169
+ }, {
170
+ dir: path.join(packageRoot, "rules", "ast-grep-rules", "coderabbit", "rules"),
171
+ origin: "bundled",
172
+ tier: "secondary"
173
+ });
174
+ const seen = /* @__PURE__ */ new Set();
175
+ return candidates.filter((source) => {
176
+ if (!fs.existsSync(source.dir))
177
+ return false;
178
+ const key = canonicalDir(source.dir);
179
+ if (seen.has(key))
180
+ return false;
181
+ seen.add(key);
182
+ return true;
183
+ });
184
+ }
185
+ function findYamlFiles(dir) {
186
+ const files = [];
187
+ let entries;
188
+ try {
189
+ entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
190
+ } catch {
191
+ return files;
192
+ }
193
+ for (const entry of entries) {
194
+ const full = path.join(dir, entry.name);
195
+ if (entry.isDirectory()) {
196
+ files.push(...findYamlFiles(full));
197
+ } else if (entry.isFile() && /\.ya?ml$/i.test(entry.name)) {
198
+ files.push(full);
199
+ }
200
+ }
201
+ return files;
202
+ }
203
+ function parseRuleId(raw) {
204
+ const scalar = raw.match(/^id:\s*(.*?)\s*$/m)?.[1];
205
+ if (!scalar)
206
+ return void 0;
207
+ const withoutComment = scalar.replace(/\s+#.*$/, "").trim();
208
+ const unquoted = withoutComment.startsWith('"') && withoutComment.endsWith('"') || withoutComment.startsWith("'") && withoutComment.endsWith("'") ? withoutComment.slice(1, -1) : withoutComment;
209
+ if (/^[A-Za-z0-9_.:-]+$/.test(unquoted))
210
+ return unquoted;
211
+ try {
212
+ const parsed = load(raw);
213
+ if (!parsed || typeof parsed !== "object" || !("id" in parsed)) {
214
+ return void 0;
215
+ }
216
+ const id = parsed.id;
217
+ return typeof id === "string" ? id : void 0;
218
+ } catch {
219
+ return void 0;
220
+ }
221
+ }
222
+ function parseRuleDocuments(content) {
223
+ return content.split(/^---\s*$/m).filter((document) => document.trim()).map((raw) => ({ raw, id: parseRuleId(raw) }));
224
+ }
225
+ var bundledSnapshots = /* @__PURE__ */ new Map();
226
+ function snapshotRuleSource(source) {
227
+ const cacheKey = canonicalDir(source.dir);
228
+ if (source.origin === "bundled") {
229
+ const cached = bundledSnapshots.get(cacheKey);
230
+ if (cached)
231
+ return cached;
232
+ }
233
+ const hash = createHash("sha256");
234
+ const files = [];
235
+ for (const file of findYamlFiles(source.dir)) {
236
+ const relativePath = path.relative(source.dir, file);
237
+ hash.update(relativePath);
238
+ hash.update("\0");
239
+ let content;
240
+ try {
241
+ content = fs.readFileSync(file, "utf8");
242
+ } catch {
243
+ hash.update("missing");
244
+ hash.update("\0");
245
+ continue;
246
+ }
247
+ hash.update(content);
248
+ hash.update("\0");
249
+ files.push({ file, relativePath, documents: parseRuleDocuments(content) });
250
+ }
251
+ const snapshot = { ...source, files, digest: hash.digest("hex") };
252
+ if (source.origin === "bundled")
253
+ bundledSnapshots.set(cacheKey, snapshot);
254
+ return snapshot;
255
+ }
256
+ function sourceFingerprint(sources) {
257
+ const hash = createHash("sha256");
258
+ for (const source of sources) {
259
+ hash.update(source.origin);
260
+ hash.update("\0");
261
+ hash.update(source.tier);
262
+ hash.update("\0");
263
+ hash.update(canonicalDir(source.dir));
264
+ hash.update("\0");
265
+ hash.update(source.digest);
266
+ hash.update("\0");
267
+ }
268
+ return hash.digest("hex");
269
+ }
270
+ function materializeMergedRuleDir(sources, mergedDir) {
271
+ fs.rmSync(mergedDir, { recursive: true, force: true });
272
+ fs.mkdirSync(mergedDir, { recursive: true });
273
+ const claimedByEarlierSource = /* @__PURE__ */ new Set();
274
+ for (const [sourceIndex, source] of sources.entries()) {
275
+ const claimedThisSource = /* @__PURE__ */ new Set();
276
+ for (const [fileIndex, file] of source.files.entries()) {
277
+ const survivingDocuments = file.documents.filter((document) => {
278
+ if (!document.id)
279
+ return true;
280
+ if (claimedByEarlierSource.has(document.id))
281
+ return false;
282
+ claimedThisSource.add(document.id);
283
+ return true;
284
+ });
285
+ if (survivingDocuments.length === 0)
286
+ continue;
287
+ const destination = path.join(mergedDir, `source${sourceIndex}-${String(fileIndex).padStart(5, "0")}.yml`);
288
+ if (survivingDocuments.length === file.documents.length) {
289
+ fs.copyFileSync(file.file, destination);
290
+ } else {
291
+ fs.writeFileSync(destination, `${survivingDocuments.map((document) => document.raw.trim()).join("\n---\n")}
292
+ `);
293
+ }
294
+ }
295
+ for (const id of claimedThisSource)
296
+ claimedByEarlierSource.add(id);
297
+ }
298
+ }
299
+ var cachedBaselines = /* @__PURE__ */ new Map();
300
+ function rootArtifactKey(root) {
301
+ return createHash("sha256").update(root).digest("hex").slice(0, 12);
302
+ }
303
+ function resolveBaselineSgconfig(projectRoot = process.cwd()) {
304
+ const root = canonicalDir(path.resolve(projectRoot || process.cwd()));
305
+ const sources = getAstGrepRuleSources(root).map(snapshotRuleSource);
306
+ if (sources.length === 0)
307
+ return void 0;
308
+ const fingerprint = sourceFingerprint(sources);
309
+ const cached = cachedBaselines.get(root);
310
+ if (cached?.fingerprint === fingerprint && fs.existsSync(cached.path) && fs.existsSync(cached.mergedDir)) {
311
+ return cached.path;
312
+ }
313
+ const dir = path.join(os.tmpdir(), "pi-lens-ast-grep");
314
+ fs.mkdirSync(dir, { recursive: true });
315
+ const artifactKey = rootArtifactKey(root);
316
+ const file = path.join(dir, `baseline-${process.pid}-${artifactKey}.sgconfig.yml`);
317
+ const mergedDir = path.join(dir, `baseline-${process.pid}-${artifactKey}.rules`);
318
+ const protectedArtifacts = /* @__PURE__ */ new Set([file, mergedDir]);
319
+ for (const baseline of cachedBaselines.values()) {
320
+ protectedArtifacts.add(baseline.path);
321
+ protectedArtifacts.add(baseline.mergedDir);
322
+ }
323
+ cleanupStaleBaselines(dir, protectedArtifacts);
324
+ materializeMergedRuleDir(sources, mergedDir);
325
+ const ruleDirForYaml = mergedDir.split(path.sep).join("/");
326
+ fs.writeFileSync(file, `ruleDirs:
327
+ - ${JSON.stringify(ruleDirForYaml)}
328
+ `);
329
+ cachedBaselines.set(root, { fingerprint, path: file, mergedDir });
330
+ enforceBaselineEntryCap(dir, /* @__PURE__ */ new Set([file, mergedDir]));
331
+ return file;
332
+ }
333
+ var SG_BASELINE_RETAINED_ENTRIES = 24;
334
+ function enforceBaselineEntryCap(dir, keep) {
335
+ let names;
336
+ try {
337
+ names = fs.readdirSync(dir);
338
+ } catch {
339
+ return;
340
+ }
341
+ const candidates = [];
342
+ for (const name of names) {
343
+ const isConfig = /^baseline(?:-\d+(?:-[a-f0-9]+)?)?\.sgconfig\.yml$/.test(name);
344
+ const isMergedDir = /^baseline-\d+(?:-[a-f0-9]+)?\.rules$/.test(name);
345
+ if (!isConfig && !isMergedDir)
346
+ continue;
347
+ const full = path.join(dir, name);
348
+ if (keep.has(full))
349
+ continue;
350
+ try {
351
+ candidates.push({
352
+ full,
353
+ mtimeMs: fs.statSync(full).mtimeMs,
354
+ recursive: isMergedDir
355
+ });
356
+ } catch {
357
+ }
358
+ }
359
+ const over = candidates.length + keep.size - SG_BASELINE_RETAINED_ENTRIES;
360
+ if (over <= 0)
361
+ return;
362
+ candidates.sort((a, b) => a.mtimeMs - b.mtimeMs);
363
+ let evicted = 0;
364
+ for (const candidate of candidates.slice(0, over)) {
365
+ try {
366
+ fs.rmSync(candidate.full, {
367
+ recursive: candidate.recursive,
368
+ force: true
369
+ });
370
+ evicted += 1;
371
+ for (const [root, baseline] of cachedBaselines) {
372
+ if (baseline.path === candidate.full || baseline.mergedDir === candidate.full) {
373
+ cachedBaselines.delete(root);
374
+ }
375
+ }
376
+ } catch {
377
+ }
378
+ }
379
+ if (evicted > 0) {
380
+ recordDegradationOnce({
381
+ kind: "sgconfig-baseline-cap-evict",
382
+ subject: dir,
383
+ reason: `evicted ${evicted} oldest baseline entries over the ${SG_BASELINE_RETAINED_ENTRIES}-entry cap`
384
+ });
385
+ }
386
+ }
387
+ function cleanupStaleBaselines(dir, keep) {
388
+ try {
389
+ const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1e3;
390
+ for (const name of fs.readdirSync(dir)) {
391
+ const isConfig = /^baseline(?:-\d+(?:-[a-f0-9]+)?)?\.sgconfig\.yml$/.test(name);
392
+ const isMergedDir = /^baseline-\d+(?:-[a-f0-9]+)?\.rules$/.test(name);
393
+ if (!isConfig && !isMergedDir)
394
+ continue;
395
+ const full = path.join(dir, name);
396
+ if (keep.has(full))
397
+ continue;
398
+ try {
399
+ const stat2 = fs.statSync(full);
400
+ if (stat2.mtimeMs < cutoff) {
401
+ fs.rmSync(full, { recursive: stat2.isDirectory(), force: true });
402
+ }
403
+ } catch {
404
+ }
405
+ }
406
+ } catch {
407
+ }
408
+ }
409
+
410
+ // dist/clients/typos-config.js
411
+ var LOCAL_TYPOS_CONFIG_NAMES = [
412
+ "typos.toml",
413
+ "_typos.toml",
414
+ ".typos.toml"
415
+ ];
416
+ function findLocalTyposConfig(startDir) {
417
+ return findLocalToolConfig(startDir, LOCAL_TYPOS_CONFIG_NAMES);
418
+ }
419
+
420
+ // dist/clients/lsp/config.js
421
+ import * as os3 from "node:os";
422
+ import path4 from "node:path";
423
+
424
+ // dist/clients/dispatch/known-runner-ids.js
425
+ var knownRunnerIds = /* @__PURE__ */ new Set();
426
+ function registerRunnerId(id) {
427
+ knownRunnerIds.add(id);
428
+ }
429
+ function runnerIdentityPopulated() {
430
+ return knownRunnerIds.size > 0;
431
+ }
432
+ function isKnownRunnerId(id) {
433
+ return knownRunnerIds.has(id);
434
+ }
435
+
436
+ // dist/clients/lsp/launch.js
437
+ import { execFileSync, spawn as nodeSpawn } from "node:child_process";
438
+ import fs3 from "node:fs";
439
+ import os2 from "node:os";
440
+ import path2 from "node:path";
441
+
442
+ // dist/clients/lsp/ruby-drive-dirs.js
443
+ import * as fs2 from "node:fs";
444
+ var RUBY_VERSION_DIR = /^ruby\d/i;
445
+ var rubyDirNamesCache = new BoundedLruCache(16);
446
+ function rubyDriveKey(driveRoot) {
447
+ return normalizeMapKey(driveRoot);
448
+ }
449
+ function filterRubyDirNames(entries) {
450
+ return entries.filter((name) => RUBY_VERSION_DIR.test(name));
451
+ }
452
+ function getRubyVersionDirNamesSync(driveRoot) {
453
+ const key = rubyDriveKey(driveRoot);
454
+ const cached = rubyDirNamesCache.get(key);
455
+ if (cached !== void 0)
456
+ return cached;
457
+ let names;
458
+ try {
459
+ names = filterRubyDirNames(fs2.readdirSync(driveRoot));
460
+ } catch {
461
+ names = [];
462
+ }
463
+ rubyDirNamesCache.set(key, names);
464
+ return names;
465
+ }
466
+ async function getRubyVersionDirNamesAsync(driveRoot) {
467
+ const key = rubyDriveKey(driveRoot);
468
+ const cached = rubyDirNamesCache.get(key);
469
+ if (cached !== void 0)
470
+ return cached;
471
+ let names;
472
+ try {
473
+ names = filterRubyDirNames(await fs2.promises.readdir(driveRoot));
474
+ } catch {
475
+ names = [];
476
+ }
477
+ rubyDirNamesCache.set(key, names);
478
+ return names;
479
+ }
480
+
481
+ // dist/clients/lsp/launch.js
482
+ var isWindows = process.platform === "win32";
483
+ var OWNER_TAG_READ_MS = 5e3;
484
+ function computeNeedsShell(resolvedCommand) {
485
+ return isWindows && (resolvedCommand.includes(" ") || /\.(cmd|bat)$/i.test(resolvedCommand) || !/\.(exe|cmd|bat)$/i.test(resolvedCommand));
486
+ }
487
+ var DEFAULT_STARTUP_FAILURE_WINDOW_MS = 50;
488
+ var WINDOWS_NAV_STARTUP_FAILURE_WINDOW_MS = 500;
489
+ var SESSIONSTART_LOG_DIR = getGlobalPiLensLogDir();
490
+ var SESSIONSTART_LOG = path2.join(SESSIONSTART_LOG_DIR, "sessionstart.log");
491
+ var PI_LENS_BIN_DIR = path2.join(getGlobalPiLensDir(), "bin");
492
+ var PI_LENS_TOOLS_BIN_DIR = path2.join(getGlobalPiLensDir(), "tools", "node_modules", ".bin");
493
+ function logSessionStart2(msg) {
494
+ if (isTestMode()) {
495
+ return;
496
+ }
497
+ const line = redactSecrets(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
498
+ `);
499
+ try {
500
+ fs3.mkdirSync(SESSIONSTART_LOG_DIR, { recursive: true });
501
+ fs3.appendFileSync(SESSIONSTART_LOG, line);
502
+ } catch {
503
+ }
504
+ }
505
+ function compactLogValue(value, max = 280) {
506
+ const normalized = value.replace(/\s+/g, " ").trim();
507
+ if (!normalized)
508
+ return "";
509
+ return normalized.length > max ? `${normalized.slice(0, max)}...` : normalized;
510
+ }
511
+ function delimiterForPlatform(platform) {
512
+ return platform === "win32" ? ";" : ":";
513
+ }
514
+ function splitPathEntries(value, delimiter) {
515
+ if (!value)
516
+ return [];
517
+ return value.split(delimiter).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
518
+ }
519
+ function normalizePathEntry(entry, platform) {
520
+ if (platform !== "win32")
521
+ return path2.posix.normalize(entry);
522
+ return path2.win32.normalize(entry).toLowerCase();
523
+ }
524
+ function combinePathValuesForPlatform(values, platform = process.platform) {
525
+ const unique = [];
526
+ const seen = /* @__PURE__ */ new Set();
527
+ const delimiter = delimiterForPlatform(platform);
528
+ for (const value of values) {
529
+ for (const entry of splitPathEntries(value, delimiter)) {
530
+ const key = normalizePathEntry(entry, platform);
531
+ if (seen.has(key))
532
+ continue;
533
+ seen.add(key);
534
+ unique.push(entry);
535
+ }
536
+ }
537
+ return unique.join(delimiter);
538
+ }
539
+ function resolvePathValue(env) {
540
+ return combinePathValuesForPlatform([env.PATH, env.Path, env.path]);
541
+ }
542
+ function runStderrGuardedProbe(command, args) {
543
+ try {
544
+ const { execFileSync: execFileSync2 } = __require("node:child_process");
545
+ const out = execFileSync2(command, args, {
546
+ timeout: 3e3,
547
+ encoding: "utf8",
548
+ // #2095 sibling: execFileSync inherits stderr to the parent by
549
+ // default (only stdout is captured into `out`), so a failed
550
+ // powershell.exe launch would print raw diagnostics into the pi
551
+ // TUI even though the surrounding catch already returns "" (read as
552
+ // "unknown" PATH by every caller). Pipe stderr instead of inheriting it.
553
+ stdio: ["ignore", "pipe", "ignore"]
554
+ });
555
+ return out.trim();
556
+ } catch {
557
+ return "";
558
+ }
559
+ }
560
+ function readWindowsRegistryPath() {
561
+ return runStderrGuardedProbe("powershell.exe", [
562
+ "-NoProfile",
563
+ "-NonInteractive",
564
+ "-Command",
565
+ "[System.Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path','User')"
566
+ ]);
567
+ }
568
+ var _liveWindowsPath = null;
569
+ function getLiveWindowsPath() {
570
+ if (_liveWindowsPath === null) {
571
+ _liveWindowsPath = readWindowsRegistryPath();
572
+ }
573
+ return _liveWindowsPath;
574
+ }
575
+ async function buildAugmentedPath(basePath) {
576
+ const candidates = [];
577
+ const nodeDir = path2.dirname(process.execPath);
578
+ if (nodeDir) {
579
+ candidates.push(nodeDir);
580
+ }
581
+ if (isWindows) {
582
+ const home = os2.homedir();
583
+ const driveRoot = path2.parse(home).root;
584
+ candidates.push(path2.join(home, ".cargo", "bin"));
585
+ candidates.push(path2.join(home, "go", "bin"));
586
+ candidates.push(path2.join(home, ".dotnet", "tools"));
587
+ candidates.push(PI_LENS_BIN_DIR);
588
+ candidates.push(PI_LENS_TOOLS_BIN_DIR);
589
+ candidates.push(path2.join(driveRoot, "Program Files", "Go", "bin"));
590
+ candidates.push(path2.join(driveRoot, "Go", "bin"));
591
+ for (const entry of await getRubyVersionDirNamesAsync(driveRoot)) {
592
+ candidates.push(path2.join(driveRoot, entry, "bin"));
593
+ }
594
+ }
595
+ const effectiveBase = isWindows ? combinePathValuesForPlatform([basePath, getLiveWindowsPath()]) : basePath;
596
+ const existing = /* @__PURE__ */ new Set();
597
+ for (const entry of splitPathEntries(effectiveBase, path2.delimiter)) {
598
+ if (!entry)
599
+ continue;
600
+ existing.add(normalizePathEntry(entry, process.platform));
601
+ }
602
+ const toAppend = [];
603
+ for (const candidate of candidates) {
604
+ if (!candidate || !fs3.existsSync(candidate))
605
+ continue;
606
+ const normalized = normalizePathEntry(candidate, process.platform);
607
+ if (existing.has(normalized))
608
+ continue;
609
+ toAppend.push(candidate);
610
+ existing.add(normalized);
611
+ }
612
+ if (toAppend.length === 0)
613
+ return basePath ?? "";
614
+ if (!basePath)
615
+ return toAppend.join(path2.delimiter);
616
+ return `${basePath}${path2.delimiter}${toAppend.join(path2.delimiter)}`;
617
+ }
618
+ function isCmdShimValid(cmdPath) {
619
+ try {
620
+ const content = fs3.readFileSync(cmdPath, "utf-8");
621
+ const match = content.match(/"%~dp0[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
622
+ if (!match)
623
+ return true;
624
+ const relPath = match[1].replace(/[/\\]/g, path2.sep);
625
+ const target = path2.resolve(path2.dirname(cmdPath), "..", relPath);
626
+ return fs3.existsSync(target);
627
+ } catch {
628
+ return true;
629
+ }
630
+ }
631
+ function bypassPs1OnWindows(ps1Path, args) {
632
+ const cmdPath = `${ps1Path.slice(0, -4)}.cmd`;
633
+ if (fs3.existsSync(cmdPath)) {
634
+ return { command: cmdPath, args, needsShell: true };
635
+ }
636
+ try {
637
+ const content = fs3.readFileSync(ps1Path, "utf-8");
638
+ const match = content.match(/"\$basedir[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
639
+ if (match) {
640
+ const relPath = match[1].replace(/[/\\]/g, path2.sep);
641
+ const jsPath = path2.resolve(path2.dirname(ps1Path), "..", relPath);
642
+ if (fs3.existsSync(jsPath)) {
643
+ return {
644
+ command: process.execPath,
645
+ args: [jsPath, ...args],
646
+ needsShell: false
647
+ };
648
+ }
649
+ }
650
+ } catch {
651
+ }
652
+ return void 0;
653
+ }
654
+ function findBinaryOnPath(command, env) {
655
+ try {
656
+ const result = execFileSync(isWindows ? "where" : "which", [command], {
657
+ encoding: "utf-8",
658
+ stdio: ["ignore", "pipe", "ignore"],
659
+ env,
660
+ // #1980 population sweep: this was the one synchronous
661
+ // child-process site in the repo with no bound at all. It runs on
662
+ // the LSP server spawn path, so an unresponsive `where`/`which` — a
663
+ // stale network PATH entry is the classic cause — parked the event
664
+ // loop with no ceiling, and read as ordinary compute in
665
+ // `loop_block`. 5s matches `isCommandAvailable`/`findCommand` in
666
+ // clients/safe-spawn.ts, which run these same two binaries.
667
+ timeout: 5e3
668
+ }).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
669
+ for (const candidate of result) {
670
+ if (fs3.existsSync(candidate)) {
671
+ return candidate;
672
+ }
673
+ }
674
+ } catch {
675
+ }
676
+ return void 0;
677
+ }
678
+ function trySpawn(command, args, cwd, env, needsShell) {
679
+ let proc;
680
+ if (needsShell) {
681
+ const escapeCmdArg = (s) => {
682
+ const escaped = s.replace(/([&|<>^()!])/g, "^$1");
683
+ return /[\s"]/.test(escaped) ? `"${escaped.replace(/"/g, '""')}"` : escaped;
684
+ };
685
+ const shellCommand = `"${command}" ${args.map(escapeCmdArg).join(" ")}`;
686
+ proc = nodeSpawn(shellCommand, [], {
687
+ cwd,
688
+ env,
689
+ stdio: ["pipe", "pipe", "pipe"],
690
+ detached: !isWindows,
691
+ windowsHide: true,
692
+ shell: true
693
+ });
694
+ } else {
695
+ proc = nodeSpawn(command, args, {
696
+ cwd,
697
+ env,
698
+ stdio: ["pipe", "pipe", "pipe"],
699
+ detached: !isWindows,
700
+ windowsHide: isWindows
701
+ });
702
+ }
703
+ if (!proc.stdin || !proc.stdout || !proc.stderr) {
704
+ throw new Error(`Failed to spawn LSP server: ${command}`);
705
+ }
706
+ if (proc.exitCode !== null || proc.killed) {
707
+ throw new Error(`LSP server ${command} exited immediately (code: ${proc.exitCode}). The binary may be missing or corrupted.`);
708
+ }
709
+ holdOwnChildPid(proc.pid, "lsp-spawn");
710
+ return proc;
711
+ }
712
+ function unrefLspProcessHandles(proc) {
713
+ try {
714
+ proc.unref();
715
+ } catch {
716
+ }
717
+ for (const stream of [proc.stdin, proc.stdout, proc.stderr]) {
718
+ try {
719
+ stream?.unref?.();
720
+ } catch {
721
+ }
722
+ }
723
+ }
724
+ function _attachErrorHandler(proc, context, logContext, rejectOnImmediateError) {
725
+ let stderrPreview = "";
726
+ let closeLogged = false;
727
+ const onStderr = (chunk) => {
728
+ if (stderrPreview.length >= 4e3)
729
+ return;
730
+ stderrPreview += chunk.toString();
731
+ };
732
+ proc.stderr?.on("data", onStderr);
733
+ proc.on("error", (err) => {
734
+ if (logContext) {
735
+ logSessionStart2("lsp process " + context + ": spawn-error command=" + logContext.command + " args=" + JSON.stringify(logContext.args) + " cwd=" + logContext.cwd + " pid=" + (logContext.pid ?? 0) + " error=" + err.message + (stderrPreview ? " stderr=" + compactLogValue(stderrPreview) : ""));
736
+ }
737
+ if (rejectOnImmediateError && logContext) {
738
+ void classifySpawnFailure(err, {
739
+ command: logContext.command,
740
+ cwd: logContext.cwd
741
+ }).then(rejectOnImmediateError);
742
+ }
743
+ });
744
+ proc.on("close", (code, signal) => {
745
+ if (closeLogged)
746
+ return;
747
+ closeLogged = true;
748
+ proc.stderr?.off("data", onStderr);
749
+ if (code !== 0 && code !== null) {
750
+ if (logContext) {
751
+ logSessionStart2("lsp process " + context + ": closed code=" + code + (signal ? " signal=" + signal : "") + " command=" + logContext.command + " args=" + JSON.stringify(logContext.args) + " cwd=" + logContext.cwd + " pid=" + (logContext.pid ?? 0) + (stderrPreview ? " stderr=" + compactLogValue(stderrPreview) : ""));
752
+ }
753
+ } else if (signal && logContext) {
754
+ logSessionStart2("lsp process " + context + ": closed signal=" + signal + " command=" + logContext.command + " args=" + JSON.stringify(logContext.args) + " cwd=" + logContext.cwd + " pid=" + (logContext.pid ?? 0) + (stderrPreview ? " stderr=" + compactLogValue(stderrPreview) : ""));
755
+ }
756
+ });
757
+ }
758
+ async function launchLSP(command, args = [], options = {}) {
759
+ const cwd = String(options.cwd ?? process.cwd());
760
+ const mergedEnv = { ...process.env, ...options.env };
761
+ const augmentedPath = await buildAugmentedPath(resolvePathValue(mergedEnv));
762
+ const ownerTag = await ownerTagForChildren({ timeoutMs: OWNER_TAG_READ_MS });
763
+ const env = {
764
+ ...mergedEnv,
765
+ PATH: augmentedPath,
766
+ ...isWindows ? { Path: augmentedPath } : {}
767
+ };
768
+ if (ownerTag === void 0)
769
+ delete env[OWNER_TAG_ENV];
770
+ else
771
+ env[OWNER_TAG_ENV] = ownerTag;
772
+ const isRelativePath = !isFullyQualified(command) && (command.includes(path2.sep) || command.includes("/"));
773
+ const explicitCommand = isRelativePath ? path2.resolve(cwd, command) : command;
774
+ const resolvedCommand = !isFullyQualified(command) && !command.includes(path2.sep) && !command.includes("/") ? findBinaryOnPath(command, env) ?? explicitCommand : explicitCommand;
775
+ let needsShell = computeNeedsShell(resolvedCommand);
776
+ let spawnCommand = resolvedCommand;
777
+ if (!isFullyQualified(command) && !command.includes(path2.sep) && !command.includes("/")) {
778
+ const globalBinPath = await findGlobalBinary(command);
779
+ if (globalBinPath) {
780
+ spawnCommand = globalBinPath;
781
+ needsShell = computeNeedsShell(spawnCommand);
782
+ }
783
+ }
784
+ if (isWindows && /\.(cmd|bat)$/i.test(spawnCommand) && !isCmdShimValid(spawnCommand)) {
785
+ logSessionStart2(`lsp cmd-shim-invalid: ${spawnCommand} target missing \u2014 skipping candidate`);
786
+ const cause = Object.assign(new Error(`LSP .cmd shim target not found: ${spawnCommand}`), { code: "ENOENT" });
787
+ throw await classifySpawnFailure(cause, { command, cwd });
788
+ }
789
+ if (isWindows && /\.ps1$/i.test(spawnCommand)) {
790
+ const bypass = bypassPs1OnWindows(spawnCommand, args);
791
+ if (bypass) {
792
+ logSessionStart2(`lsp ps1-bypass: ${spawnCommand} \u2192 ${bypass.command} shell=${bypass.needsShell}`);
793
+ spawnCommand = bypass.command;
794
+ args = bypass.args;
795
+ needsShell = bypass.needsShell;
796
+ } else {
797
+ logSessionStart2(`lsp ps1-bypass: no .cmd or JS entry found for ${spawnCommand}, spawn may hang`);
798
+ }
799
+ }
800
+ let proc;
801
+ try {
802
+ proc = trySpawn(spawnCommand, args, cwd, env, needsShell);
803
+ } catch (err) {
804
+ if (!isFullyQualified(command) && !command.includes(path2.sep) && !command.includes("/")) {
805
+ const globalBinPath = await findGlobalBinary(command);
806
+ if (globalBinPath && globalBinPath !== spawnCommand) {
807
+ const needsShellGlobal = computeNeedsShell(globalBinPath);
808
+ proc = trySpawn(globalBinPath, args, cwd, env, needsShellGlobal);
809
+ } else {
810
+ throw await classifySpawnFailure(err, { command, cwd });
811
+ }
812
+ } else {
813
+ throw await classifySpawnFailure(err, { command, cwd });
814
+ }
815
+ }
816
+ if (!proc.stdin || !proc.stdout || !proc.stderr) {
817
+ throw new Error(`Failed to spawn LSP server: ${command}`);
818
+ }
819
+ if (proc.exitCode !== null || proc.killed) {
820
+ throw new Error(`LSP server ${command} exited immediately (code: ${proc.exitCode}). The binary may be missing or corrupted.`);
821
+ }
822
+ logSessionStart2(`lsp launch: command=${command} resolved=${spawnCommand} args=${JSON.stringify(args)} cwd=${cwd} shell=${needsShell ? "true" : "false"} pid=${proc.pid ?? 0}`);
823
+ const formatStartupStderr = (stderr) => {
824
+ const normalized = compactLogValue(stderr);
825
+ if (!normalized)
826
+ return "";
827
+ return ` stderr=${normalized}`;
828
+ };
829
+ let startupStderr = "";
830
+ const onStartupStderr = (chunk) => {
831
+ if (startupStderr.length >= 4e3)
832
+ return;
833
+ startupStderr += chunk.toString();
834
+ };
835
+ proc.stderr?.on("data", onStartupStderr);
836
+ try {
837
+ await new Promise((resolve3, reject) => {
838
+ let settled = false;
839
+ proc.on("error", (err) => {
840
+ if (!settled) {
841
+ settled = true;
842
+ void classifySpawnFailure(err, { command, cwd }).then((failure) => {
843
+ const detail = formatStartupStderr(startupStderr);
844
+ reject(detail ? new SpawnFailureError(failure.kind, `${failure.message}${detail}`, failure.cause) : failure);
845
+ });
846
+ }
847
+ });
848
+ proc.on("exit", (code) => {
849
+ if (!settled && code !== null) {
850
+ settled = true;
851
+ const isWindowsCmd = isWindows && command.endsWith(".cmd");
852
+ const errorMsg = isWindowsCmd && code === 1 ? `npm .cmd shim failed (underlying binary not installed). Run 'npm install' in this project or use a global installation.` : `The binary may be missing or corrupted.`;
853
+ reject(new Error(`LSP server ${command} exited immediately with code ${code}. ${errorMsg}${formatStartupStderr(startupStderr)}`));
854
+ }
855
+ });
856
+ const startupFailureWindowMs = (() => {
857
+ if (options?.startupFailureWindowMs) {
858
+ return options.startupFailureWindowMs;
859
+ }
860
+ if (isWindows && needsShell) {
861
+ return WINDOWS_NAV_STARTUP_FAILURE_WINDOW_MS;
862
+ }
863
+ return DEFAULT_STARTUP_FAILURE_WINDOW_MS;
864
+ })();
865
+ setTimeout(() => {
866
+ if (!settled) {
867
+ settled = true;
868
+ resolve3();
869
+ }
870
+ }, startupFailureWindowMs);
871
+ });
872
+ } finally {
873
+ proc.stderr?.off("data", onStartupStderr);
874
+ }
875
+ _attachErrorHandler(proc, command, {
876
+ command: spawnCommand,
877
+ args,
878
+ cwd,
879
+ pid: proc.pid ?? 0
880
+ });
881
+ unrefLspProcessHandles(proc);
882
+ return {
883
+ process: proc,
884
+ stdin: proc.stdin,
885
+ stdout: proc.stdout,
886
+ stderr: proc.stderr,
887
+ pid: proc.pid ?? 0,
888
+ command: spawnCommand,
889
+ args
890
+ };
891
+ }
892
+
893
+ // dist/clients/lsp/session-roots.js
894
+ import path3 from "node:path";
895
+ var SESSION_ROOT_CAP = 128;
896
+ var sessionRoots = new BoundedFifoMap(SESSION_ROOT_CAP);
897
+ function noteEvictedRoots(evicted) {
898
+ const roots = evicted.map(([root]) => root);
899
+ if (roots.length > 0) {
900
+ incrementDegradationCount({
901
+ kind: "lsp-session-root-evicted",
902
+ subject: `cap=${SESSION_ROOT_CAP}`,
903
+ reason: `session root registry at capacity; will load the dropped root again on the next session start or tool call naming it (dropped: ${roots[0]})`
904
+ });
905
+ }
906
+ return roots;
907
+ }
908
+ function registerSessionRoot(cwd) {
909
+ const root = path3.resolve(cwd);
910
+ if (sessionRoots.has(root))
911
+ return [];
912
+ return noteEvictedRoots(sessionRoots.set(root, void 0));
913
+ }
914
+ function setSessionRootConfig(cwd, config) {
915
+ return noteEvictedRoots(sessionRoots.set(path3.resolve(cwd), config));
916
+ }
917
+ function sessionRootConfigEntries() {
918
+ return sessionRoots;
919
+ }
920
+ function isSessionRootRegistered(cwd) {
921
+ return sessionRoots.has(path3.resolve(cwd));
922
+ }
923
+ function shouldInitializeSessionRoot(cwd, readyRoots) {
924
+ const normalized = path3.resolve(cwd);
925
+ return !readyRoots.has(normalized) || !isSessionRootRegistered(normalized);
926
+ }
927
+ function isOutsideAllSessionRoots(filePath) {
928
+ if (sessionRoots.size === 0)
929
+ return false;
930
+ const resolved = path3.resolve(filePath);
931
+ for (const root of sessionRoots.keys()) {
932
+ if (isSameOrWithin(root, resolved))
933
+ return false;
934
+ }
935
+ return true;
936
+ }
937
+ function getSessionRootsForTelemetry(limit = 4) {
938
+ return [...sessionRoots.keys()].sort((a, b) => Number(a > b) - Number(a < b)).slice(0, limit);
939
+ }
940
+
941
+ // dist/clients/lsp/config.js
942
+ function asRecord(value) {
943
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
944
+ }
945
+ var CONFIG_RESOLVED_PHASE = "config_resolved";
946
+ function configResolutionKey(cwd) {
947
+ return normalizeFilePath(path4.resolve(normalizeFilePath(cwd)));
948
+ }
949
+ function publishConfigResolutionPending(cwd) {
950
+ logSessionStart(`session_start config_resolution_pending session=${currentSessionRecordId()} root=${configResolutionKey(cwd)}`);
951
+ }
952
+ function recordConfigResolved(cwd, resolution, lspConfig, homeDir, resolveMs) {
953
+ const root = configResolutionKey(cwd);
954
+ if (!claimPhaseOncePerSession(CONFIG_RESOLVED_PHASE, root)) {
955
+ return;
956
+ }
957
+ const summary = summarizeConfigResolution(resolution, homeDir);
958
+ const sessionId = currentSessionRecordId();
959
+ const deniedServers = lspConfig.disabledServers?.length ?? 0;
960
+ const legacyDocuments = summary.documents.filter((document) => document.legacy).length;
961
+ logLatency({
962
+ type: "phase",
963
+ phase: CONFIG_RESOLVED_PHASE,
964
+ filePath: root,
965
+ durationMs: resolveMs,
966
+ metadata: {
967
+ sessionId,
968
+ documents: summary.documents,
969
+ countsByTier: summary.countsByTier,
970
+ recordCount: summary.recordCount,
971
+ deniedServers,
972
+ resolveMs
973
+ }
974
+ });
975
+ logSessionStart(`config resolved documents=${summary.documents.length} legacy=${legacyDocuments} records=${summary.recordCount} deniedServers=${deniedServers} resolveMs=${resolveMs} session=${sessionId} root=${root}`);
976
+ }
977
+ async function loadLSPConfig(cwd, homeDir = os3.homedir(), options = {}) {
978
+ const reporting = options.report !== false;
979
+ publishConfigResolutionPending(cwd);
980
+ const resolveStartedAt = Date.now();
981
+ const resolution = resolvePiLensConfig({
982
+ cwd,
983
+ globalDir: getGlobalPiLensDir(),
984
+ // The global tier reads the PRODUCTION resolution (global-config-location
985
+ // PR, refs #2457): which file supplies it is an env fact (PI_LENS_CONFIG_PATH,
986
+ // then a legacy default, then PI_CODING_AGENT_DIR, then the
987
+ // PI_LENS_HOME-relocated canonical default), not a property of the
988
+ // `$HOME` this call's project walk is ceiling-bounded by. `homeDir`
989
+ // stays threaded below for the walk and `globalDir`; a test redirecting
990
+ // the global tier does it through the env, the same way production is
991
+ // controlled.
992
+ globalConfigPath: getPiLensGlobalConfigPath(),
993
+ homeDir,
994
+ // The subsystem comes from the failing DOCUMENT, not from this loader
995
+ // (#2445). This resolution opens `~/.pi-lens/config.json` and
996
+ // `.pi-lens.json` as well as the LSP-scoped files, and reporting all of
997
+ // them as `lsp-config` announced an "invalid LSP config" for a file whose
998
+ // contents are pi-lens settings. An LSP-scoped file still reports here.
999
+ ...reporting ? { onReadError: reportConfigReadFailure } : {}
1000
+ });
1001
+ const coversProblems = newCoversClaimProblems();
1002
+ const config = lspConfigOf(resolution.value, coversProblems);
1003
+ if (reporting) {
1004
+ reportPiLensConfigRecords([
1005
+ ...resolution.records,
1006
+ ...coversClaimRecords(resolution, coversProblems)
1007
+ ]);
1008
+ }
1009
+ recordCoversUnvalidated(resolution, coversProblems);
1010
+ recordConfigResolved(cwd, resolution, config, homeDir, Date.now() - resolveStartedAt);
1011
+ return config;
1012
+ }
1013
+ function newCoversClaimProblems() {
1014
+ return { refusals: [], unvalidated: [] };
1015
+ }
1016
+ function coversPointer(serverId) {
1017
+ return `/${LSP_NAMESPACE_KEY}/servers/${serverId}/covers`;
1018
+ }
1019
+ function coversClaimSource(resolution, pointer) {
1020
+ let candidate = pointer;
1021
+ while (candidate !== void 0) {
1022
+ const entry = resolution.provenance.get(candidate);
1023
+ if (entry) {
1024
+ return {
1025
+ file: entry.file ?? "",
1026
+ ...entry.tier ? { tier: entry.tier } : {}
1027
+ };
1028
+ }
1029
+ const cut = candidate.lastIndexOf("/");
1030
+ candidate = cut > 0 ? candidate.slice(0, cut) : void 0;
1031
+ }
1032
+ return { file: resolution.documents.at(-1)?.file ?? "" };
1033
+ }
1034
+ function coversClaimRecords(resolution, problems) {
1035
+ return problems.refusals.map((refusal) => {
1036
+ const pointer = coversPointer(refusal.serverId);
1037
+ const { file, tier } = coversClaimSource(resolution, pointer);
1038
+ const dropped = refusal.declaredCount - refusal.keptCount;
1039
+ return {
1040
+ code: "PILENS_CFG_0005",
1041
+ file,
1042
+ key: pointer,
1043
+ subject: migrationSubject(file, pointer),
1044
+ reason: `lsp.servers.${refusal.serverId}.covers declares member(s) that are not recognized dispatch runner ids; ${dropped} of ${refusal.declaredCount} member(s) dropped, the server still ` + keptTail(refusal.keptCount),
1045
+ ...tier ? { tier } : {}
1046
+ };
1047
+ });
1048
+ }
1049
+ function keptTail(keptCount) {
1050
+ return keptCount > 0 ? "registers with the remaining covers claim" : "registers with no covers claim";
1051
+ }
1052
+ function recordCoversUnvalidated(resolution, problems) {
1053
+ for (const unvalidated of problems.unvalidated) {
1054
+ const pointer = coversPointer(unvalidated.serverId);
1055
+ const { file } = coversClaimSource(resolution, pointer);
1056
+ recordDegradationOnce({
1057
+ kind: "lsp-covers-unvalidated",
1058
+ subject: `${file}\0${pointer}`,
1059
+ reason: "no runner registry has populated this process yet; the covers claim was accepted without runner-id validation and the next config load validates it",
1060
+ metadata: { pointer }
1061
+ });
1062
+ }
1063
+ }
1064
+ function coversValidatedServers(servers, problems = void 0) {
1065
+ const out = {};
1066
+ for (const [id, raw] of Object.entries(servers)) {
1067
+ const entry = raw;
1068
+ if (!entry.covers?.length) {
1069
+ out[id] = entry;
1070
+ continue;
1071
+ }
1072
+ if (!runnerIdentityPopulated()) {
1073
+ problems?.unvalidated.push({ serverId: id });
1074
+ out[id] = entry;
1075
+ continue;
1076
+ }
1077
+ const kept = [];
1078
+ for (const member of entry.covers) {
1079
+ if (isKnownRunnerId(member))
1080
+ kept.push(member);
1081
+ }
1082
+ if (kept.length === entry.covers.length) {
1083
+ out[id] = entry;
1084
+ continue;
1085
+ }
1086
+ problems?.refusals.push({
1087
+ serverId: id,
1088
+ declaredCount: entry.covers.length,
1089
+ keptCount: kept.length
1090
+ });
1091
+ const { covers: _dropped, ...rest } = entry;
1092
+ out[id] = kept.length > 0 ? { ...rest, covers: kept } : rest;
1093
+ }
1094
+ return out;
1095
+ }
1096
+ function customServerSpecsOf(value) {
1097
+ const servers = asRecord(lspSectionOf(value).servers);
1098
+ return servers ? coversValidatedServers(servers) : {};
1099
+ }
1100
+ function lspConfigOf(value, problems) {
1101
+ const section = lspSectionOf(value);
1102
+ const config = {};
1103
+ const servers = asRecord(section.servers);
1104
+ if (servers)
1105
+ config.servers = coversValidatedServers(servers, problems);
1106
+ const serverOverrides = asRecord(section.serverOverrides);
1107
+ if (serverOverrides) {
1108
+ config.serverOverrides = serverOverrides;
1109
+ }
1110
+ if (Array.isArray(section.disabledServers)) {
1111
+ config.disabledServers = section.disabledServers;
1112
+ }
1113
+ if (Array.isArray(section.warmFiles)) {
1114
+ config.warmFiles = section.warmFiles;
1115
+ }
1116
+ return config;
1117
+ }
1118
+ function createCustomServer(config, id) {
1119
+ return {
1120
+ id,
1121
+ name: config.name,
1122
+ custom: true,
1123
+ // The own-command token the runner-coverage seam gates this row's
1124
+ // covers claim on (#3968 F2): the declared covering lane's binary must
1125
+ // be probeable before the claim can defer a CLI runner.
1126
+ command: config.command,
1127
+ extensions: config.extensions,
1128
+ idleEviction: "unmeasured",
1129
+ // The config-declared covers channel (#3968): the claim the loader
1130
+ // validated (`lspConfigOf`'s projection drops unknown runner ids) rides
1131
+ // the server entry into the runner-coverage seam.
1132
+ ...config.covers ? { covers: config.covers } : {},
1133
+ ...config.rootMarkers ? { rootMarkers: config.rootMarkers } : {},
1134
+ root: config.rootMarkers ? async (file) => resolveToolCwd("lsp", id, file, {
1135
+ cwd: process.cwd(),
1136
+ ...config.rootMarkers ? { rootMarkers: config.rootMarkers } : {}
1137
+ }).cwd : async (file) => resolveToolCwd("lsp", id, file, { cwd: process.cwd() }).cwd,
1138
+ async spawn(root) {
1139
+ const proc = await launchLSP(config.command, config.args ?? ["--stdio"], {
1140
+ cwd: root,
1141
+ env: config.env ? { ...process.env, ...config.env } : process.env
1142
+ });
1143
+ return { process: proc };
1144
+ }
1145
+ };
1146
+ }
1147
+ var EMPTY_CONFIG = {
1148
+ customServers: [],
1149
+ disabledServerIds: /* @__PURE__ */ new Set(),
1150
+ serverOverrides: /* @__PURE__ */ new Map()
1151
+ };
1152
+ var configInFlight = /* @__PURE__ */ new Map();
1153
+ function normalizeWorkspacePath(cwd) {
1154
+ return path4.resolve(cwd);
1155
+ }
1156
+ function isSameOrChildPath(filePath, candidateRoot) {
1157
+ if (filePath === candidateRoot)
1158
+ return true;
1159
+ return filePath.startsWith(`${candidateRoot}${path4.sep}`);
1160
+ }
1161
+ function getConfigForFile(filePath) {
1162
+ const resolvedFilePath = path4.resolve(filePath);
1163
+ let bestMatch;
1164
+ for (const [root, config] of sessionRootConfigEntries()) {
1165
+ if (config === void 0)
1166
+ continue;
1167
+ if (!isSameOrChildPath(resolvedFilePath, root))
1168
+ continue;
1169
+ if (!bestMatch || root.length > bestMatch.root.length) {
1170
+ bestMatch = { root, config };
1171
+ }
1172
+ }
1173
+ return bestMatch?.config ?? EMPTY_CONFIG;
1174
+ }
1175
+ function registerLSPConfig(config) {
1176
+ const customServers = [];
1177
+ const disabledServerIds = new Set(config.disabledServers ?? []);
1178
+ if (config.servers) {
1179
+ for (const [id, serverConfig] of Object.entries(config.servers)) {
1180
+ try {
1181
+ const server = createCustomServer(serverConfig, id);
1182
+ customServers.push(server);
1183
+ } catch {
1184
+ }
1185
+ }
1186
+ }
1187
+ const serverOverrides = /* @__PURE__ */ new Map();
1188
+ if (config.serverOverrides) {
1189
+ for (const [id, entry] of Object.entries(config.serverOverrides)) {
1190
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
1191
+ const initOpts = entry.initializationOptions;
1192
+ if (initOpts !== void 0 && typeof initOpts === "object" && initOpts !== null && !Array.isArray(initOpts)) {
1193
+ serverOverrides.set(id, {
1194
+ initializationOptions: initOpts
1195
+ });
1196
+ }
1197
+ }
1198
+ }
1199
+ }
1200
+ return { customServers, disabledServerIds, serverOverrides };
1201
+ }
1202
+ function forgetConfigResolvedClaims(evictedRoots) {
1203
+ for (const root of evictedRoots) {
1204
+ releasePhaseClaim(CONFIG_RESOLVED_PHASE, configResolutionKey(root));
1205
+ }
1206
+ }
1207
+ async function initLSPConfig(cwd) {
1208
+ const normalizedCwd = normalizeWorkspacePath(cwd);
1209
+ forgetConfigResolvedClaims(registerSessionRoot(normalizedCwd));
1210
+ const existing = configInFlight.get(normalizedCwd);
1211
+ if (existing)
1212
+ return existing;
1213
+ const promise = (async () => {
1214
+ const config = registerLSPConfig(await loadLSPConfig(cwd, os3.homedir()));
1215
+ forgetConfigResolvedClaims(setSessionRootConfig(normalizedCwd, config));
1216
+ })();
1217
+ configInFlight.set(normalizedCwd, promise);
1218
+ try {
1219
+ await promise;
1220
+ } finally {
1221
+ if (configInFlight.get(normalizedCwd) === promise) {
1222
+ configInFlight.delete(normalizedCwd);
1223
+ }
1224
+ }
1225
+ }
1226
+ function registeredServers(config) {
1227
+ return [...LSP_SERVERS, ...config.customServers];
1228
+ }
1229
+ function selectionReason(server, config, filePath, ext, base) {
1230
+ if (config.disabledServerIds.has(server.id))
1231
+ return "disabled-by-config";
1232
+ let matched = false;
1233
+ for (const value of server.extensions) {
1234
+ const lower = value.toLowerCase();
1235
+ if (lower === ext || lower === base) {
1236
+ matched = true;
1237
+ break;
1238
+ }
1239
+ }
1240
+ if (!matched)
1241
+ return "extension-mismatch";
1242
+ if (server.pathFilter && !server.pathFilter(filePath))
1243
+ return "path-filter";
1244
+ return "selected";
1245
+ }
1246
+ function explainServersForFile(filePath, config = getConfigForFile(filePath)) {
1247
+ const ext = path4.extname(filePath).toLowerCase();
1248
+ const base = path4.basename(filePath).toLowerCase();
1249
+ return registeredServers(config).map((server) => {
1250
+ const reason = selectionReason(server, config, filePath, ext, base);
1251
+ return { server, selected: reason === "selected", reason };
1252
+ });
1253
+ }
1254
+ function getServersForFileWithConfig(filePath) {
1255
+ const config = getConfigForFile(filePath);
1256
+ const ext = path4.extname(filePath).toLowerCase();
1257
+ const base = path4.basename(filePath).toLowerCase();
1258
+ return registeredServers(config).filter((server) => selectionReason(server, config, filePath, ext, base) === "selected");
1259
+ }
1260
+ function primaryServerEntry(filePath) {
1261
+ return getServersForFileWithConfig(filePath).find((s) => s.role !== "auxiliary");
1262
+ }
1263
+ function primaryServerId(filePath) {
1264
+ return primaryServerEntry(filePath)?.id;
1265
+ }
1266
+ async function resolveLspCwdForFile(filePath, sessionCwd, onRootFallback) {
1267
+ const primary = primaryServerEntry(filePath);
1268
+ if (!primary)
1269
+ return void 0;
1270
+ return resolveLspServerCwd(primary, filePath, sessionCwd, void 0, onRootFallback);
1271
+ }
1272
+ function getServerInitOverride(serverId, filePath) {
1273
+ return getConfigForFile(filePath).serverOverrides.get(serverId);
1274
+ }
1275
+
1276
+ // dist/clients/lsp/wait-policy/strategies.js
1277
+ import { createRequire } from "node:module";
1278
+ var _require = createRequire(import.meta.url);
1279
+ function astGrepNativePackageName(platform, arch) {
1280
+ switch (platform) {
1281
+ case "win32":
1282
+ if (arch === "x64")
1283
+ return "@ast-grep/cli-win32-x64-msvc";
1284
+ if (arch === "arm64")
1285
+ return "@ast-grep/cli-win32-arm64-msvc";
1286
+ if (arch === "ia32")
1287
+ return "@ast-grep/cli-win32-ia32-msvc";
1288
+ return void 0;
1289
+ case "darwin":
1290
+ if (arch === "arm64")
1291
+ return "@ast-grep/cli-darwin-arm64";
1292
+ if (arch === "x64")
1293
+ return "@ast-grep/cli-darwin-x64";
1294
+ return void 0;
1295
+ case "linux":
1296
+ if (arch === "x64")
1297
+ return "@ast-grep/cli-linux-x64-gnu";
1298
+ if (arch === "arm64")
1299
+ return "@ast-grep/cli-linux-arm64-gnu";
1300
+ return void 0;
1301
+ default:
1302
+ return void 0;
1303
+ }
1304
+ }
1305
+ function resolveAstGrepNativeExe(platform = process.platform, arch = process.arch) {
1306
+ const pkgName = astGrepNativePackageName(platform, arch);
1307
+ if (!pkgName)
1308
+ return void 0;
1309
+ const binaryName = platform === "win32" ? "ast-grep.exe" : "ast-grep";
1310
+ try {
1311
+ return _require.resolve(`${pkgName}/${binaryName}`);
1312
+ } catch {
1313
+ return void 0;
1314
+ }
1315
+ }
1316
+ var SERVER_DIAGNOSTIC_STRATEGIES = {
1317
+ typescript: {
1318
+ seedFirstPush: true,
1319
+ pullRetryBudgetMs: 0,
1320
+ debounceMs: 50,
1321
+ aggregateWaitMs: 1e3,
1322
+ expectSemanticSecondPush: false,
1323
+ // Tier 3 (#458): typescript-language-server publishes nothing on a
1324
+ // clean→clean edit (docs/lsp-capability-matrix.md, re-confirmed
1325
+ // 2026-07-12). It's the lone core-set tier-3 server, which is exactly
1326
+ // why the cascade lane's in-lane wait is worth skipping for it
1327
+ // specifically. Applies to the CLASSIC server only (#524/#529/#558)
1328
+ // — TS7's native `tsc --lsp --stdio` variant shares this
1329
+ // "typescript" server id but the 2026-07-12 dual-environment
1330
+ // re-measurement found it now publishes on clean (a drift from the
1331
+ // #541 measurement); wait-policy/classification.ts's classifier checks the live
1332
+ // snapshot's launchVariant and never applies this flag to a
1333
+ // native-ts7 instance.
1334
+ silentOnClean: true
1335
+ },
1336
+ "rust-analyzer": {
1337
+ seedFirstPush: false,
1338
+ pullRetryBudgetMs: 500,
1339
+ debounceMs: 150,
1340
+ aggregateWaitMs: 3e3,
1341
+ expectSemanticSecondPush: true
1342
+ },
1343
+ // PythonServer (pyright / basedpyright) — openFilesOnly mode: lazy per-file
1344
+ // analysis, startup similar to jedi. seedFirstPush: true because pyright's
1345
+ // first publishDiagnostics after didOpen is the complete result for that file.
1346
+ python: {
1347
+ seedFirstPush: true,
1348
+ pullRetryBudgetMs: 0,
1349
+ debounceMs: 100,
1350
+ aggregateWaitMs: 1500,
1351
+ expectSemanticSecondPush: false
1352
+ },
1353
+ // jedi-language-server is push-only (no pull diagnostics) and its FIRST
1354
+ // publishDiagnostics is the complete result (seedFirstPush). But that first
1355
+ // push lands just after didOpen+~1s on cold start (Python/parso import) —
1356
+ // measured ~1011ms — so a 1000ms aggregate budget misses it by a hair and
1357
+ // returns zero. 3000ms gives cold-start headroom without stalling the warm path.
1358
+ "python-jedi": {
1359
+ seedFirstPush: true,
1360
+ pullRetryBudgetMs: 0,
1361
+ debounceMs: 100,
1362
+ aggregateWaitMs: 3e3,
1363
+ expectSemanticSecondPush: false
1364
+ },
1365
+ eslint: {
1366
+ seedFirstPush: true,
1367
+ pullRetryBudgetMs: 0,
1368
+ debounceMs: 200,
1369
+ aggregateWaitMs: 2e3,
1370
+ expectSemanticSecondPush: false
1371
+ },
1372
+ // Opengrep security scanner (cross-language LSP). It pushes an EMPTY result
1373
+ // during the one-time rule-load window at startup, then the real scan after
1374
+ // `semgrep/rulesRefreshed` — so never seed the first push. Push-only (no pull
1375
+ // diagnostics). Warm per-file scan ~1.3s; the first touch in a session may
1376
+ // also pay rule-load (~3.5s cold). aggregateWaitMs is 3500: it's this
1377
+ // server's OWN deadline, bounded by the per-edit caller cap as a ceiling
1378
+ // (#242), so on a 2500ms-capped edit opengrep waits min(2500, 3500)=2500
1379
+ // and on uncapped paths it gets its full 3500. 3500 covers warm and most
1380
+ // cold; a cold scan that overruns isn't lost — late diagnostics are cached
1381
+ // and surface on the next unchanged-content read through the content-bound
1382
+ // auxiliary carry-over path.
1383
+ opengrep: {
1384
+ seedFirstPush: false,
1385
+ pullRetryBudgetMs: 0,
1386
+ debounceMs: 250,
1387
+ aggregateWaitMs: 3500,
1388
+ expectSemanticSecondPush: false,
1389
+ // Opengrep re-scans only on a fresh didOpen — didChange is a no-op for it.
1390
+ reopenOnResync: true,
1391
+ rescansOnSave: true
1392
+ },
1393
+ // ast-grep structural linter (sgconfig-gated auxiliary LSP). Push-only,
1394
+ // compiles the project rules on the first scan of a session, and — like
1395
+ // Opengrep — is re-synced via didClose+didOpen so edits trigger a re-scan.
1396
+ // Conservative budget until measured against real projects (#239).
1397
+ // ast-grep re-scans on didChange (verified: toggling the violation count
1398
+ // 3→1→4→2 returns the correct fresh count each touch, with matching doc
1399
+ // versions), so reopen isn't needed and didChange is the lighter path.
1400
+ // aggregateWaitMs is 1800: its warm scan is ~1.3s, so 1000 was under-budgeted
1401
+ // (only masked before because the old with-auxiliary deadline was a global
1402
+ // max() floor; now each server has its own caller-cap-bounded deadline, #242,
1403
+ // so the budget must actually cover the scan).
1404
+ "ast-grep": {
1405
+ seedFirstPush: false,
1406
+ pullRetryBudgetMs: 0,
1407
+ debounceMs: 150,
1408
+ aggregateWaitMs: 1800,
1409
+ expectSemanticSecondPush: false,
1410
+ reopenOnResync: false
1411
+ },
1412
+ // zizmor (GitHub Actions security scanner, auxiliary LSP #272). Push-only
1413
+ // (no pull diagnostics). Its audit set is compiled-in — there's no rule-load
1414
+ // window like Opengrep — so the FIRST publishDiagnostics after didOpen IS the
1415
+ // complete result: seedFirstPush. It re-scans on didChange (FULL sync), so no
1416
+ // reopen-on-resync. A native single-workflow audit is sub-second offline;
1417
+ // online mode may add a GitHub-API round-trip, so 2000ms gives headroom
1418
+ // (bounded by the per-edit caller cap as a ceiling, #242), and any late online
1419
+ // finding can surface on the next unchanged-content read through the
1420
+ // content-bound auxiliary carry-over path.
1421
+ zizmor: {
1422
+ seedFirstPush: true,
1423
+ pullRetryBudgetMs: 0,
1424
+ debounceMs: 150,
1425
+ aggregateWaitMs: 2e3,
1426
+ expectSemanticSecondPush: false,
1427
+ reopenOnResync: false,
1428
+ // #3548: zizmor@main `crates/zizmor/src/lsp.rs` `initialized()`
1429
+ // registers `textDocument/didSave` DYNAMICALLY (`include_text: true`),
1430
+ // and `did_save` re-audits and republishes with `version: None` — the
1431
+ // same surplus shape as opengrep's static save rescan (#3482). This is
1432
+ // presently INERT: `applyDynamicCapabilities` (client.ts) does not map
1433
+ // a dynamic didSave registration to anything, and `negotiateSaveOptions`
1434
+ // (sync-kind.ts) reads only the static `initialize` reply, so
1435
+ // `state.saveOptions` never gets set for zizmor and `sendDidSave` never
1436
+ // fires (its `if (!save) return;` guard). Set now anyway, measured
1437
+ // fact style (like `silentOnClean`'s launch-variant scoping above): the
1438
+ // day dynamic registration is honoured, this is the correct value with
1439
+ // no further plumbing, and `expectSaveRescan`/`rescansOnSave`'s
1440
+ // counting logic does not care how `saveOptions` got set — proven by
1441
+ // `ZIZMOR-SAVE-RESCAN-EXPECTED` in
1442
+ // tests/clients/lsp/late-auxiliary-findings.test.ts, which sets
1443
+ // `state.saveOptions` directly (the same shape as the pre-existing
1444
+ // `SAVE-RESCAN-EXPECTED` opengrep test) rather than through the
1445
+ // unbuilt dynamic-capability path.
1446
+ rescansOnSave: true
1447
+ },
1448
+ // typos (source-code spell checker, auxiliary LSP #283). Push-only (no pull
1449
+ // diagnostics). Its dictionary is compiled in — there's NO rule-load window
1450
+ // like Opengrep — so the FIRST publishDiagnostics after didOpen IS the
1451
+ // complete result: seedFirstPush. It re-scans on didChange (FULL sync), so no
1452
+ // reopen-on-resync. A native single-file spell scan is sub-100ms, so the seed
1453
+ // arrives near-instantly; aggregateWaitMs is a generous ceiling (bounded by
1454
+ // the per-edit caller cap, #242) that the early seed resolves well under.
1455
+ typos: {
1456
+ seedFirstPush: true,
1457
+ pullRetryBudgetMs: 0,
1458
+ debounceMs: 150,
1459
+ aggregateWaitMs: 1500,
1460
+ expectSemanticSecondPush: false,
1461
+ reopenOnResync: false,
1462
+ // #3548: see `publishesOnClose`'s doc comment above — typos'
1463
+ // `did_close` always publishes an empty, version-less set.
1464
+ publishesOnClose: true
1465
+ },
1466
+ // marksman (Markdown LSP, #274). Push-based; native binary so the per-file
1467
+ // parse is fast, but its value is CROSS-file (broken intra-repo links,
1468
+ // missing anchors/heading refs) which needs the workspace index — so the
1469
+ // first push after didOpen can be empty before indexing completes. Don't
1470
+ // seed it (like opengrep/rust-analyzer); a modest 1500ms aggregate covers
1471
+ // warm edits, and any late cross-file finding surfaces on the next touch.
1472
+ marksman: {
1473
+ seedFirstPush: false,
1474
+ pullRetryBudgetMs: 0,
1475
+ debounceMs: 150,
1476
+ aggregateWaitMs: 1500,
1477
+ expectSemanticSecondPush: false,
1478
+ // #645: a full-tree sweep opens every markdown file, all racing the
1479
+ // SAME one-time workspace index build — pay the 1500ms budget once
1480
+ // per sweep (the first markdown file touched), not once per file.
1481
+ // 250ms covers a warm per-file publish (native binary, fast parse)
1482
+ // once the index has already had a full aggregateWaitMs window.
1483
+ workspaceIndexing: true,
1484
+ workspaceIndexingWarmWaitMs: 250,
1485
+ // #799 / run 35914033696: marksman is push-only and publishes NOTHING on
1486
+ // a clean transition — there is no pull fallback and no sync-confirm protocol (unlike
1487
+ // typescript's tsserver commands), so a clean markdown file's touch
1488
+ // waits its full budget with zero signal either way. Marking it
1489
+ // `silentOnClean` lets the generic push-only clean-confirm gate
1490
+ // (`touchFile`, the `classifyCascadeWaitTier`-driven fallback next to
1491
+ // the tsserver sync-confirm block) treat "no publish within budget,
1492
+ // notify succeeded" as CONFIRMED clean instead of inconclusive/timed
1493
+ // out — closing the observed 2x20s-per-sweep burn on clean markdown
1494
+ // (evidence: agents.md timed out at 20009ms/20014ms on both the
1495
+ // warm-up attempt and its retry, with zero diagnostics either time).
1496
+ silentOnClean: true
1497
+ },
1498
+ // cue lsp serve (#1522, #1519, #1520). Measured directly against the real
1499
+ // v0.17.1 binary (`getWorkspaceDiagnosticsSupport` reports
1500
+ // `mode: "push-only"`; no pull support advertised).
1501
+ //
1502
+ // It reports load/parse (syntax) errors as you type, but leaves
1503
+ // conflicting-value/constraint-failure (evaluation) errors to `cue vet`
1504
+ // — the #1522 cue-vet auxiliary runner covers that gap. So the syntax
1505
+ // diagnostics this strategy governs are a REAL but PARTIAL signal, not
1506
+ // full CUE validation.
1507
+ //
1508
+ // The repaired clean-signal probe measured cue as publishing a versioned
1509
+ // clean-transition set (run 35914033696), so this marker stays absent:
1510
+ // the cascade must retain its normal early-publish path.
1511
+ //
1512
+ // seedFirstPush: true — the one cold-open case that DOES publish (a
1513
+ // file that is already broken) sends the complete single diagnostic on
1514
+ // its first push; there is no observed partial-then-complete sequence to
1515
+ // wait out.
1516
+ //
1517
+ // aggregateWaitMs: 2000 covers the measured warm edit-to-publish latency
1518
+ // (~930ms, syntax reparse) with margin; a cold spawn's first push (~2.1s
1519
+ // end-to-end including process start) is bounded separately by
1520
+ // maxClientWaitMs, not this per-diagnostics budget.
1521
+ // intelephense (php, #3310). Measured directly against the real v1.18.5
1522
+ // binary over a raw JSON-RPC session answering `workspace/configuration`
1523
+ // the way pi-lens does (2026-09-23, linux):
1524
+ //
1525
+ // +284ms initialize response — NO diagnosticProvider (push-only)
1526
+ // +295ms publishDiagnostics diags=0 version=undefined <- pre-index
1527
+ // +301ms indexingStarted
1528
+ // +689ms indexingEnded
1529
+ // +696ms publishDiagnostics diags=2 version=undefined <- the answer
1530
+ //
1531
+ // so `emptyFirstPublish: "indexing"`: the first publish is an artifact of
1532
+ // the cold index, not an answer. The same session on a genuinely CLEAN
1533
+ // file publishes `[]` at +304ms and `[]` AGAIN at +663ms (right after
1534
+ // `indexingEnded`), which is what lets the held publish be released by
1535
+ // the server's own second publish instead of by a timer — and a WARM
1536
+ // touch (a second file, index already built) publishes the real set
1537
+ // FIRST at +5ms, so the hold costs nothing once the session is warm.
1538
+ //
1539
+ // seedFirstPush: false — the measurement above is the direct refutation
1540
+ // of "the first push is complete" for this server.
1541
+ // pullRetryBudgetMs: 0 — no pull provider is advertised at all.
1542
+ // aggregateWaitMs: 8000 — the budget must cover the cold index window,
1543
+ // which is what the second (real) publish waits on: ~0.4s for a 139-file
1544
+ // index on the dev box, ~5s on the nightly ubuntu runner (#3217's
1545
+ // transcript). Per-edit callers cap this as a CEILING (#242), so an
1546
+ // interactive edit still waits only its own cap; the uncapped paths (the
1547
+ // tool-smoke LSP gate, which itself caps at 8000ms) get the full budget,
1548
+ // and the cold index is paid once per session, not once per touch.
1549
+ php: {
1550
+ seedFirstPush: false,
1551
+ pullRetryBudgetMs: 0,
1552
+ debounceMs: 150,
1553
+ aggregateWaitMs: 8e3,
1554
+ expectSemanticSecondPush: false,
1555
+ emptyFirstPublish: "indexing",
1556
+ // #3484: the fence reply (+2..4 ms) precedes the publish (~+1 s).
1557
+ diagnosticsFence: "reply-first"
1558
+ },
1559
+ // terraform-ls (#3310). The nightly tool-smoke measurement was identical
1560
+ // on 2026-09-27, 2026-09-28, and 2026-09-29:
1561
+ //
1562
+ // [terraform] clean-behavior=publishes-unversioned (tier 2*)
1563
+ // dirtyPubs=2(v:0) cleanPubs=2(v:0) first-publish=empty-first
1564
+ // provisional pre-index publish
1565
+ //
1566
+ // The first empty, unversioned publish is the cold-index artifact, so hold
1567
+ // it once and let terraform-ls's next publish resolve the wait. A held
1568
+ // clean-only trace therefore reaches the caller as unanswered/indeterminate
1569
+ // at the wait ceiling rather than a false clean, by design (#3310). The
1570
+ // marker is measured policy, not a blanket rule for Tier 2* push servers.
1571
+ terraform: {
1572
+ seedFirstPush: false,
1573
+ pullRetryBudgetMs: 0,
1574
+ debounceMs: 150,
1575
+ aggregateWaitMs: 1500,
1576
+ expectSemanticSecondPush: false,
1577
+ emptyFirstPublish: "indexing"
1578
+ },
1579
+ // yaml-language-server (#3484): the default strategy plus the measured
1580
+ // fence order — reply +3..6 ms, publish +207..242 ms after didChange.
1581
+ yaml: {
1582
+ seedFirstPush: false,
1583
+ pullRetryBudgetMs: 250,
1584
+ debounceMs: 150,
1585
+ aggregateWaitMs: 1500,
1586
+ expectSemanticSecondPush: false,
1587
+ diagnosticsFence: "reply-first"
1588
+ },
1589
+ // Svelte's pull diagnostics settle after the default 1500ms budget on a
1590
+ // cold server. The tool-smoke gate caps waits at 8000ms, so give this
1591
+ // server enough aggregate budget to return its seeded findings (#3311).
1592
+ svelte: {
1593
+ seedFirstPush: false,
1594
+ pullRetryBudgetMs: 0,
1595
+ debounceMs: 150,
1596
+ aggregateWaitMs: 4e3,
1597
+ expectSemanticSecondPush: false
1598
+ },
1599
+ // csharp-ls loads (design-time-builds) the restored project AFTER
1600
+ // `initialize` returns, so the publish for a seeded CS0029 lands inside
1601
+ // `waitForDiagnostics`, not inside the client wait. MEASURED A/B over two
1602
+ // nightly Tool-smoke runs of the same fixture with `dotnet restore` already
1603
+ // done — the ONLY difference between them was this budget:
1604
+ // * `aggregateWaitMs` 1500 (the default): run 36054901266 →
1605
+ // `[csharp] touched=0`, 4.05s after `Restored …/toolsmoke.csproj`.
1606
+ // A real compiler error read as clean.
1607
+ // * 8000: run 36058292424 → `[csharp] touched=1`, 6.49s after the same
1608
+ // line; gate run 36059988117 → `lsp_diagnostics returned 1 primary
1609
+ // finding`, 4.86s after it.
1610
+ // Both windows INCLUDE workspace bootstrap + spawn + initialize, so they
1611
+ // bound the wait from above: the required budget is in (1500, 4860] ms.
1612
+ // 6000 covers the measured gate window with margin and stays under the
1613
+ // tool-smoke gate's own 8000ms ceiling (that relation is pinned by
1614
+ // tests/config/lsp-gate-population.test.ts), so the gate can still witness
1615
+ // this budget. CONFIRMED at 6000 by run 36064829436: `✓ csharp csharp-ls 1
1616
+ // lsp_diagnostics returned 1 primary finding`, 4.78s after `Restored
1617
+ // …csproj`, census unchanged at gated 31 / handshake-only 8 / unavailable 6
1618
+ // — so 6000 is measured as sufficient, not merely inferred from the 8000
1619
+ // runs above. It is deliberately NOT the ceiling: an `lsp_diagnostics` call
1620
+ // that passes no `waitMs` pays this budget in full on a file the server never
1621
+ // publishes for (`tools/lsp-diagnostics.ts` leaves `maxClientWaitMs`
1622
+ // undefined → `perServerTimeout` has no caller cap), so every 1000ms here
1623
+ // is 1000ms of turn latency on the no-publication path (#3402 review r2).
1624
+ // Every other field is DEFAULT_STRATEGY's value on purpose: csharp-ls is
1625
+ // `mode=pull`/tier-1 authoritative-clean (#3311 investigator table), and
1626
+ // nothing has measured its pull retry, so this entry moves the one field
1627
+ // that was measured and no other (pinned in
1628
+ // tests/clients/lsp/server-strategies.test.ts).
1629
+ // fsharp/expert/vue deliberately have NO entry: the same two runs show
1630
+ // `touched=0` at BOTH 1500 and 8000, so the budget is not what stops them
1631
+ // publishing and an 8000 entry would buy nothing while costing every
1632
+ // uncapped production call 6.5 extra seconds. Their fixture rows carry the
1633
+ // observed-behavior exemption instead (`scripts/smoke-tools.mjs`), and a
1634
+ // probe that wants a long window sets `PI_LENS_LSP_DIAGNOSTICS_MAX_WAIT_MS`
1635
+ // — a flat harness override that needs no production budget.
1636
+ csharp: {
1637
+ seedFirstPush: false,
1638
+ pullRetryBudgetMs: 250,
1639
+ debounceMs: 150,
1640
+ aggregateWaitMs: 6e3,
1641
+ expectSemanticSecondPush: false
1642
+ },
1643
+ cue: {
1644
+ seedFirstPush: true,
1645
+ pullRetryBudgetMs: 0,
1646
+ debounceMs: 150,
1647
+ aggregateWaitMs: 2e3,
1648
+ expectSemanticSecondPush: false,
1649
+ reopenOnResync: false
1650
+ },
1651
+ // lua-language-server is push-only and was silent on clean transitions in
1652
+ // the repaired probe (run 35914033696). Keep the marker on the measured
1653
+ // server id so the cascade can skip its in-lane wait safely.
1654
+ lua: {
1655
+ seedFirstPush: true,
1656
+ pullRetryBudgetMs: 0,
1657
+ debounceMs: 150,
1658
+ aggregateWaitMs: 2e3,
1659
+ expectSemanticSecondPush: false,
1660
+ silentOnClean: true
1661
+ }
1662
+ };
1663
+ var NATIVE_TS7_DIAGNOSTIC_STRATEGY = {
1664
+ ...SERVER_DIAGNOSTIC_STRATEGIES.typescript,
1665
+ seedFirstPush: false,
1666
+ // Native TS7 demonstrably publishes on clean, so the classic-only marker
1667
+ // must not leak through the shared server id.
1668
+ silentOnClean: false
1669
+ };
1670
+ var DEFAULT_STRATEGY = {
1671
+ seedFirstPush: false,
1672
+ pullRetryBudgetMs: 250,
1673
+ debounceMs: 150,
1674
+ aggregateWaitMs: 1500,
1675
+ expectSemanticSecondPush: false
1676
+ };
1677
+ function getStrategy(serverId, launchVariant) {
1678
+ if (serverId === "typescript" && launchVariant === "native-ts7") {
1679
+ return NATIVE_TS7_DIAGNOSTIC_STRATEGY;
1680
+ }
1681
+ return SERVER_DIAGNOSTIC_STRATEGIES[serverId] ?? DEFAULT_STRATEGY;
1682
+ }
1683
+
1684
+ // dist/clients/lsp/wait-policy/classification.js
1685
+ function classifyServerWaitTier(serverId, snapshot) {
1686
+ if (!snapshot)
1687
+ return "waits";
1688
+ const mode = snapshot.workspaceDiagnosticsSupport?.mode;
1689
+ if (mode === "pull")
1690
+ return "pull-capable";
1691
+ if (snapshot.customServer === true && mode === "push-only" && snapshot.diagnosticsUnsupported === true && snapshot.diagnosticsPublished !== true) {
1692
+ return "diagnostics-unsupported";
1693
+ }
1694
+ if (mode !== "push-only")
1695
+ return "waits";
1696
+ const strategy = getStrategy(serverId, snapshot.launchVariant);
1697
+ if (strategy.silentOnClean !== true)
1698
+ return "waits";
1699
+ if (snapshot.launchVariant === "native-ts7")
1700
+ return "waits";
1701
+ return "tier3-silent";
1702
+ }
1703
+ function resolvePrimaryServerForWaitPolicy(filePath, snapshots) {
1704
+ const servers = getServersForFileWithConfig(filePath).filter((s) => s.role !== "auxiliary");
1705
+ const primary = servers[0];
1706
+ if (!primary)
1707
+ return void 0;
1708
+ return {
1709
+ serverId: primary.id,
1710
+ snapshot: snapshots.find((s) => s.serverId === primary.id)
1711
+ };
1712
+ }
1713
+ function classifyCascadeWaitTier(lspService, filePath, snapshots) {
1714
+ void lspService;
1715
+ const primary = resolvePrimaryServerForWaitPolicy(filePath, snapshots);
1716
+ if (!primary)
1717
+ return "waits";
1718
+ return classifyServerWaitTier(primary.serverId, primary.snapshot);
1719
+ }
1720
+
1721
+ // dist/clients/lsp/lombok.js
1722
+ import * as fs4 from "node:fs";
1723
+ import * as os4 from "node:os";
1724
+ import * as path5 from "node:path";
1725
+ var LOMBOK_ENV_KEYS = ["PI_LENS_LOMBOK_JAR", "LOMBOK_JAR"];
1726
+ var LOMBOK_PROJECT_FILES = [
1727
+ "lombok.config",
1728
+ "pom.xml",
1729
+ "build.gradle",
1730
+ "build.gradle.kts",
1731
+ path5.join("gradle", "libs.versions.toml")
1732
+ ];
1733
+ function fileExists(filePath) {
1734
+ if (!filePath)
1735
+ return false;
1736
+ try {
1737
+ return fs4.statSync(filePath).isFile();
1738
+ } catch {
1739
+ return false;
1740
+ }
1741
+ }
1742
+ function readTextIfSmall(filePath, maxBytes = 512 * 1024) {
1743
+ try {
1744
+ const stat2 = fs4.statSync(filePath);
1745
+ if (!stat2.isFile() || stat2.size > maxBytes)
1746
+ return "";
1747
+ return fs4.readFileSync(filePath, "utf-8");
1748
+ } catch {
1749
+ return "";
1750
+ }
1751
+ }
1752
+ function containsLombokDependency(text) {
1753
+ 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);
1754
+ }
1755
+ function hasLombokProject(root) {
1756
+ const lombokConfig = path5.join(root, "lombok.config");
1757
+ if (fileExists(lombokConfig))
1758
+ return true;
1759
+ for (const name of LOMBOK_PROJECT_FILES) {
1760
+ if (name === "lombok.config")
1761
+ continue;
1762
+ const text = readTextIfSmall(path5.join(root, name));
1763
+ if (text && containsLombokDependency(text))
1764
+ return true;
1765
+ }
1766
+ return false;
1767
+ }
1768
+ function envJarCandidate(env) {
1769
+ for (const key of LOMBOK_ENV_KEYS) {
1770
+ const value = env[key]?.trim();
1771
+ if (fileExists(value))
1772
+ return path5.resolve(value);
1773
+ }
1774
+ return void 0;
1775
+ }
1776
+ function localJarCandidates(root) {
1777
+ return [
1778
+ path5.join(root, "lombok.jar"),
1779
+ path5.join(root, ".lombok", "lombok.jar"),
1780
+ path5.join(root, "lib", "lombok.jar"),
1781
+ path5.join(root, "libs", "lombok.jar")
1782
+ ];
1783
+ }
1784
+ function newestExistingJar(candidates) {
1785
+ let best;
1786
+ for (const candidate of candidates) {
1787
+ try {
1788
+ const stat2 = fs4.statSync(candidate);
1789
+ if (!stat2.isFile())
1790
+ continue;
1791
+ if (!best || stat2.mtimeMs > best.mtimeMs) {
1792
+ best = { filePath: candidate, mtimeMs: stat2.mtimeMs };
1793
+ }
1794
+ } catch {
1795
+ }
1796
+ }
1797
+ return best?.filePath;
1798
+ }
1799
+ function mavenLocalLombokJar(home = os4.homedir()) {
1800
+ const base = path5.join(home, ".m2", "repository", "org", "projectlombok", "lombok");
1801
+ let versions = [];
1802
+ try {
1803
+ versions = fs4.readdirSync(base);
1804
+ } catch {
1805
+ return void 0;
1806
+ }
1807
+ return newestExistingJar(versions.map((version) => path5.join(base, version, `lombok-${version}.jar`)));
1808
+ }
1809
+ function gradleCacheLombokJar(home = os4.homedir()) {
1810
+ const base = path5.join(home, ".gradle", "caches", "modules-2", "files-2.1", "org.projectlombok", "lombok");
1811
+ const candidates = [];
1812
+ let versions = [];
1813
+ try {
1814
+ versions = fs4.readdirSync(base);
1815
+ } catch {
1816
+ return void 0;
1817
+ }
1818
+ for (const version of versions) {
1819
+ const versionDir = path5.join(base, version);
1820
+ let hashes = [];
1821
+ try {
1822
+ hashes = fs4.readdirSync(versionDir);
1823
+ } catch {
1824
+ continue;
1825
+ }
1826
+ for (const hash of hashes) {
1827
+ candidates.push(path5.join(versionDir, hash, `lombok-${version}.jar`));
1828
+ }
1829
+ }
1830
+ return newestExistingJar(candidates);
1831
+ }
1832
+ function resolveLombokJar(root, env = process.env) {
1833
+ const explicit = envJarCandidate(env);
1834
+ if (explicit)
1835
+ return explicit;
1836
+ return newestExistingJar(localJarCandidates(root)) ?? mavenLocalLombokJar() ?? gradleCacheLombokJar();
1837
+ }
1838
+ function hasLombokJavaAgent(jvmArgs) {
1839
+ return /(^|\s)-javaagent:(?:"[^"]*lombok[^"]*\.jar"|\S*lombok\S*\.jar)/i.test(jvmArgs ?? "");
1840
+ }
1841
+ function resolveLombokJavaAgentArg(root, baseEnv = process.env) {
1842
+ if (baseEnv.PI_LENS_JAVA_LOMBOK === "0")
1843
+ return void 0;
1844
+ if (hasLombokJavaAgent(baseEnv.JDTLS_JVM_ARGS))
1845
+ return void 0;
1846
+ const explicitJar = envJarCandidate(baseEnv);
1847
+ if (!explicitJar && !hasLombokProject(root))
1848
+ return void 0;
1849
+ const jar = explicitJar ?? resolveLombokJar(root, baseEnv);
1850
+ return jar ? `-javaagent:${jar}` : void 0;
1851
+ }
1852
+ function createLombokJdtlsArgs(root, baseEnv = process.env) {
1853
+ const javaAgent = resolveLombokJavaAgentArg(root, baseEnv);
1854
+ return javaAgent ? [`--jvm-arg=${javaAgent}`] : [];
1855
+ }
1856
+
1857
+ // dist/clients/lsp/jvm-runtime.js
1858
+ import { existsSync as existsSync2, readdirSync as readdirSync4 } from "node:fs";
1859
+ import os5 from "node:os";
1860
+ import path6 from "node:path";
1861
+ var JAVA_EXE = process.platform === "win32" ? "java.exe" : "java";
1862
+ var JAVA_PROBE_TIMEOUT_MS = 5e3;
1863
+ var MIN_JAVA_MAJOR = 17;
1864
+ function jdkHomeFrom(dir) {
1865
+ if (existsSync2(path6.join(dir, "bin", JAVA_EXE)))
1866
+ return dir;
1867
+ const macHome = path6.join(dir, "Contents", "Home");
1868
+ if (existsSync2(path6.join(macHome, "bin", JAVA_EXE)))
1869
+ return macHome;
1870
+ return void 0;
1871
+ }
1872
+ function parseMajorVersion(name) {
1873
+ const legacy = name.match(/(?<!\d)1\.(\d+)/);
1874
+ if (legacy)
1875
+ return Number.parseInt(legacy[1], 10);
1876
+ const modern = name.match(/(?<!\d)(\d{1,2})/);
1877
+ return modern ? Number.parseInt(modern[1], 10) : 0;
1878
+ }
1879
+ function childDirs(base) {
1880
+ try {
1881
+ return readdirSync4(base, { withFileTypes: true }).filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => path6.join(base, e.name));
1882
+ } catch {
1883
+ return [];
1884
+ }
1885
+ }
1886
+ function candidateRoots() {
1887
+ const home = os5.homedir();
1888
+ const roots = [];
1889
+ roots.push(path6.join(home, ".jdks"));
1890
+ roots.push(path6.join(getGlobalPiLensDir(), "tools"));
1891
+ if (process.platform === "win32") {
1892
+ const progFiles = [
1893
+ process.env.ProgramFiles,
1894
+ process.env["ProgramFiles(x86)"],
1895
+ process.env.ProgramW6432,
1896
+ path6.join(process.env.LOCALAPPDATA ?? path6.join(home, "AppData", "Local"), "Programs")
1897
+ ].filter((p) => Boolean(p));
1898
+ for (const base of progFiles) {
1899
+ roots.push(path6.join(base, "Eclipse Adoptium"));
1900
+ roots.push(path6.join(base, "Java"));
1901
+ roots.push(path6.join(base, "Microsoft"));
1902
+ roots.push(path6.join(base, "Zulu"));
1903
+ roots.push(path6.join(base, "Amazon Corretto"));
1904
+ roots.push(path6.join(base, "BellSoft"));
1905
+ }
1906
+ } else if (process.platform === "darwin") {
1907
+ roots.push("/Library/Java/JavaVirtualMachines");
1908
+ roots.push(path6.join(home, "Library", "Java", "JavaVirtualMachines"));
1909
+ roots.push("/opt/homebrew/opt");
1910
+ roots.push("/usr/local/opt");
1911
+ } else {
1912
+ roots.push("/usr/lib/jvm");
1913
+ roots.push("/usr/java");
1914
+ roots.push("/opt/java");
1915
+ }
1916
+ return roots;
1917
+ }
1918
+ function discoverJdkHome(roots = candidateRoots(), javaHome = process.env.JAVA_HOME) {
1919
+ const found = [];
1920
+ if (javaHome) {
1921
+ const resolved = jdkHomeFrom(javaHome);
1922
+ if (resolved)
1923
+ found.push({ home: resolved, major: Number.MAX_SAFE_INTEGER });
1924
+ }
1925
+ for (const root of roots) {
1926
+ for (const dir of childDirs(root)) {
1927
+ const resolved = jdkHomeFrom(dir);
1928
+ if (!resolved)
1929
+ continue;
1930
+ found.push({
1931
+ home: resolved,
1932
+ major: parseMajorVersion(path6.basename(dir))
1933
+ });
1934
+ }
1935
+ }
1936
+ const usable = found.filter((c) => c.major >= MIN_JAVA_MAJOR);
1937
+ if (usable.length === 0)
1938
+ return void 0;
1939
+ usable.sort((a, b) => b.major - a.major);
1940
+ return usable[0].home;
1941
+ }
1942
+ var _cachedEnv;
1943
+ var javaAvailabilityLatch = createAvailabilityLatch();
1944
+ var inFlightJavaProbe = null;
1945
+ function probeJavaOnPath() {
1946
+ const memo = javaAvailabilityLatch.read();
1947
+ if (memo !== null) {
1948
+ if (javaAvailabilityLatch.getOutcome() === "transient") {
1949
+ logAvailabilityDecision({
1950
+ tool: "java",
1951
+ verdict: "unavailable",
1952
+ outcome: "transient",
1953
+ cause: javaAvailabilityLatch.getCause() ?? "probe-timeout",
1954
+ elapsedMs: 0,
1955
+ latched: false,
1956
+ retryAfterMs: Math.max(0, javaAvailabilityLatch.getRetryAtMs() - Date.now()),
1957
+ budgetMs: JAVA_PROBE_TIMEOUT_MS,
1958
+ // No probe ran here: the latch's own remembered cause is replayed
1959
+ // as-is, so the call site is the one asserting it (#2209).
1960
+ classifiedBy: "caller"
1961
+ });
1962
+ return Promise.resolve(void 0);
1963
+ }
1964
+ return Promise.resolve(memo);
1965
+ }
1966
+ if (inFlightJavaProbe)
1967
+ return inFlightJavaProbe;
1968
+ inFlightJavaProbe = runJavaProbe().finally(() => {
1969
+ inFlightJavaProbe = null;
1970
+ });
1971
+ return inFlightJavaProbe;
1972
+ }
1973
+ async function runJavaProbe() {
1974
+ const finder = process.platform === "win32" ? "where" : "which";
1975
+ const startedAt = Date.now();
1976
+ const sampler = startHostStallSampler();
1977
+ let result;
1978
+ let hostStallMs;
1979
+ try {
1980
+ result = await safeSpawnAsync(finder, ["java"], {
1981
+ timeout: JAVA_PROBE_TIMEOUT_MS
1982
+ });
1983
+ } finally {
1984
+ hostStallMs = sampler.stop();
1985
+ }
1986
+ const elapsedMs = Date.now() - startedAt;
1987
+ if (result.status === 0 && !result.error) {
1988
+ javaAvailabilityLatch.noteAvailable();
1989
+ logAvailabilityDecision({
1990
+ tool: "java",
1991
+ verdict: "available",
1992
+ outcome: "success",
1993
+ cause: "ok",
1994
+ elapsedMs,
1995
+ latched: true,
1996
+ hostStallMs,
1997
+ budgetMs: JAVA_PROBE_TIMEOUT_MS,
1998
+ classifiedBy: "probe"
1999
+ });
2000
+ return true;
2001
+ }
2002
+ const { outcome, cause } = classifyProbeFailure(result, {
2003
+ hostStallMs,
2004
+ unclassifiedFailureOutcome: "missing"
2005
+ });
2006
+ const retryAfterMs = javaAvailabilityLatch.noteUnavailable(outcome, cause);
2007
+ logAvailabilityDecision({
2008
+ tool: "java",
2009
+ verdict: "unavailable",
2010
+ outcome,
2011
+ cause,
2012
+ elapsedMs,
2013
+ latched: outcome !== "transient",
2014
+ hostStallMs,
2015
+ ...retryAfterMs > 0 && { retryAfterMs },
2016
+ budgetMs: JAVA_PROBE_TIMEOUT_MS,
2017
+ classifiedBy: "probe"
2018
+ });
2019
+ return outcome === "transient" ? void 0 : false;
2020
+ }
2021
+ async function resolveJavaRuntimeEnv() {
2022
+ if (_cachedEnv)
2023
+ return _cachedEnv.value;
2024
+ const javaOnPath = await probeJavaOnPath();
2025
+ if (javaOnPath === true) {
2026
+ _cachedEnv = { value: void 0 };
2027
+ return void 0;
2028
+ }
2029
+ const home = discoverJdkHome();
2030
+ if (home) {
2031
+ const binDir = path6.join(home, "bin");
2032
+ const currentPath = process.env.PATH ?? process.env.Path ?? "";
2033
+ _cachedEnv = {
2034
+ value: {
2035
+ JAVA_HOME: home,
2036
+ PATH: binDir + path6.delimiter + currentPath
2037
+ }
2038
+ };
2039
+ return _cachedEnv.value;
2040
+ }
2041
+ if (javaOnPath === false) {
2042
+ _cachedEnv = { value: void 0 };
2043
+ }
2044
+ return void 0;
2045
+ }
2046
+
2047
+ // dist/clients/lsp/server-covers.js
2048
+ var BUILTIN_SERVER_RUNNER_COVERS = /* @__PURE__ */ new Map([
2049
+ [
2050
+ "bash",
2051
+ { runnerIds: ["shellcheck"], gateCommands: ["bash-language-server"] }
2052
+ ],
2053
+ ["shuck", { runnerIds: ["shellcheck"], gateCommands: ["shuck"] }],
2054
+ ["toml", { runnerIds: ["taplo"], gateCommands: ["taplo"] }]
2055
+ ]);
2056
+
2057
+ // dist/clients/lsp/server.js
2058
+ function withRootMarkers(root, markers) {
2059
+ root.rootMarkers = markers;
2060
+ return root;
2061
+ }
2062
+ function describeRootFallback(fallback) {
2063
+ const tail = "so pi-lens cannot confirm the server analysed the file";
2064
+ if (fallback.cause === "failed") {
2065
+ return `${fallback.serverName}: resolving the project root for this file failed, ${tail}`;
2066
+ }
2067
+ if (fallback.cause === "unselected") {
2068
+ return `${fallback.serverName}: found ${fallback.marker} for this file but pi-lens did not select it as the project root (a test-fixture or git-ignored directory is never used as one), ${tail}`;
2069
+ }
2070
+ return `${fallback.serverName}: no project root found for this file (looked for ${fallback.rootMarkers.join(" / ")}); the server was started at the file's directory and may not have analysed it`;
2071
+ }
2072
+ async function resolveLspServerCwd(server, filePath, sessionCwd, onRootFailure, onRootFallback) {
2073
+ const stagingRoot = ephemeralStagingRoot(filePath);
2074
+ if (stagingRoot) {
2075
+ recordDegradationOnce({
2076
+ kind: "lsp-root-declined",
2077
+ subject: stagingRoot,
2078
+ reason: "LSP root declined for host pi-agent staging directory"
2079
+ });
2080
+ return void 0;
2081
+ }
2082
+ const rootMarkers = server.rootMarkers ?? server.root.rootMarkers;
2083
+ let serverRoot;
2084
+ let rootFailed = false;
2085
+ try {
2086
+ serverRoot = await server.root(filePath);
2087
+ } catch (error) {
2088
+ const reason = error instanceof Error ? error.message : String(error);
2089
+ rootFailed = true;
2090
+ onRootFailure?.(reason);
2091
+ }
2092
+ const isFileDirFallback = serverRoot !== void 0 && rootMarkers?.length && path7.resolve(serverRoot) === path7.resolve(path7.dirname(filePath));
2093
+ if (!serverRoot || isFileDirFallback) {
2094
+ const probedMarker = onRootFallback && !rootFailed && rootMarkers?.length ? resolveToolCwd("lsp", server.id, filePath, {
2095
+ cwd: sessionCwd,
2096
+ rootMarkers,
2097
+ suppressTelemetry: true
2098
+ }).marker : void 0;
2099
+ const refusedMarker = probedMarker !== void 0 && rootMarkers?.includes(probedMarker) ? probedMarker : void 0;
2100
+ const fallbackCwd = rootMarkers?.length ? resolveToolCwd("lsp", server.id, filePath, {
2101
+ cwd: path7.dirname(path7.resolve(filePath)),
2102
+ rootMarkers
2103
+ }) : void 0;
2104
+ if (!serverRoot) {
2105
+ recordDegradationOnce({
2106
+ kind: "tool-cwd-resolution",
2107
+ subject: server.id,
2108
+ reason: `lsp:server-root-${rootFailed ? "failed" : "fallback"}:${filePath}`
2109
+ });
2110
+ onRootFallback?.({
2111
+ serverId: server.id,
2112
+ serverName: server.name ?? server.id,
2113
+ rootMarkers: rootMarkers ?? [],
2114
+ requiresProjectRoot: server.requiresProjectRoot === true,
2115
+ cause: rootFailed ? "failed" : refusedMarker !== void 0 ? "unselected" : "none",
2116
+ ...refusedMarker !== void 0 && { marker: refusedMarker }
2117
+ });
2118
+ }
2119
+ return fallbackCwd?.cwd;
2120
+ }
2121
+ const boundedServerRoot = enforceLspRootCeiling(serverRoot, sessionCwd, filePath);
2122
+ return resolveToolCwd("lsp", server.id, filePath, {
2123
+ cwd: sessionCwd,
2124
+ rootMarkers,
2125
+ serverRoot: boundedServerRoot
2126
+ }).cwd;
2127
+ }
2128
+ var FIXTURE_ROOT_SEGMENTS = /* @__PURE__ */ new Set(["__fixtures__", "testdata"]);
2129
+ var FALLBACK_PROJECT_MARKERS = [
2130
+ ".git",
2131
+ "package.json",
2132
+ "go.work",
2133
+ "go.mod",
2134
+ "Cargo.toml",
2135
+ "pyproject.toml",
2136
+ "pom.xml",
2137
+ "build.gradle",
2138
+ "build.gradle.kts",
2139
+ "mix.exs",
2140
+ "pubspec.yaml",
2141
+ "Package.swift"
2142
+ ];
2143
+ var PROJECT_BOUNDARY_MARKERS = [
2144
+ "package.json",
2145
+ "package-lock.json",
2146
+ "pnpm-lock.yaml",
2147
+ "yarn.lock",
2148
+ "bun.lock",
2149
+ "bun.lockb",
2150
+ "go.work",
2151
+ "go.mod",
2152
+ "Cargo.toml",
2153
+ "Cargo.lock",
2154
+ "pyproject.toml",
2155
+ "uv.lock",
2156
+ "poetry.lock",
2157
+ "Pipfile",
2158
+ "Pipfile.lock",
2159
+ "pom.xml",
2160
+ "build.gradle",
2161
+ "build.gradle.kts",
2162
+ "settings.gradle",
2163
+ "settings.gradle.kts",
2164
+ "mix.exs",
2165
+ "pubspec.yaml",
2166
+ "Package.swift"
2167
+ ];
2168
+ var loggedRootCeilingClamps = /* @__PURE__ */ new Set();
2169
+ var posixCaseInsensitiveByPath = /* @__PURE__ */ new Map();
2170
+ function posixFilesystemIsCaseInsensitive(root) {
2171
+ const resolved = path7.resolve(root);
2172
+ const cached = posixCaseInsensitiveByPath.get(resolved);
2173
+ if (cached !== void 0)
2174
+ return cached;
2175
+ if (!existsSync3(resolved)) {
2176
+ return false;
2177
+ }
2178
+ const name = path7.basename(resolved);
2179
+ const alternate = name.toLowerCase() === name ? name.toUpperCase() : name.toLowerCase();
2180
+ let insensitive = false;
2181
+ const alternatePath = path7.join(path7.dirname(resolved), alternate);
2182
+ if (alternate !== name && existsSync3(alternatePath)) {
2183
+ try {
2184
+ const actual = statSync3(resolved);
2185
+ const alternateStat = statSync3(alternatePath);
2186
+ insensitive = actual.dev === alternateStat.dev && actual.ino === alternateStat.ino;
2187
+ } catch {
2188
+ insensitive = false;
2189
+ }
2190
+ }
2191
+ posixCaseInsensitiveByPath.set(resolved, insensitive);
2192
+ return insensitive;
2193
+ }
2194
+ function resetLSPCaseSensitivityState() {
2195
+ posixCaseInsensitiveByPath.clear();
2196
+ }
2197
+ function isSameOrWithin(ancestor, candidate, deps = {}) {
2198
+ const windowsShaped = isWindowsPath(ancestor) || isWindowsPath(candidate);
2199
+ const pathApi = windowsShaped ? path7.win32 : path7;
2200
+ const resolvedAncestor = pathApi.resolve(ancestor);
2201
+ const resolvedCandidate = pathApi.resolve(candidate);
2202
+ let caseInsensitive = false;
2203
+ if (!windowsShaped) {
2204
+ if (deps.caseInsensitiveProbe) {
2205
+ const cached = posixCaseInsensitiveByPath.get(resolvedAncestor);
2206
+ caseInsensitive = cached ?? deps.caseInsensitiveProbe(resolvedAncestor);
2207
+ if (cached === void 0) {
2208
+ posixCaseInsensitiveByPath.set(resolvedAncestor, caseInsensitive);
2209
+ }
2210
+ } else {
2211
+ caseInsensitive = posixFilesystemIsCaseInsensitive(resolvedAncestor);
2212
+ }
2213
+ }
2214
+ const relative2 = pathApi.relative(caseInsensitive ? resolvedAncestor.toLowerCase() : resolvedAncestor, caseInsensitive ? resolvedCandidate.toLowerCase() : resolvedCandidate);
2215
+ return relative2 === "" || !relative2.startsWith("..") && !pathApi.isAbsolute(relative2);
2216
+ }
2217
+ function enforceLspRootCeiling(root, sessionCwd, filePath) {
2218
+ const windowsShaped = isWindowsPath(root) || isWindowsPath(sessionCwd);
2219
+ const pathApi = windowsShaped ? path7.win32 : path7;
2220
+ const resolvedRoot = pathApi.resolve(root);
2221
+ const resolvedCwd = pathApi.resolve(sessionCwd);
2222
+ if (filePath && !isSameOrWithin(resolvedCwd, pathApi.resolve(filePath))) {
2223
+ return resolvedRoot;
2224
+ }
2225
+ if (isSameOrWithin(resolvedCwd, resolvedRoot))
2226
+ return resolvedRoot;
2227
+ const logKey = `${normalizeMapKey(resolvedCwd)}:${normalizeMapKey(resolvedRoot)}`;
2228
+ if (!loggedRootCeilingClamps.has(logKey)) {
2229
+ loggedRootCeilingClamps.add(logKey);
2230
+ logSessionStart(`lsp root clamped to session cwd: candidate=${resolvedRoot} cwd=${resolvedCwd}`);
2231
+ }
2232
+ return resolvedCwd;
2233
+ }
2234
+ async function hasProjectBoundaryMarker(dir) {
2235
+ if (await markerExists(dir, ".git"))
2236
+ return true;
2237
+ for (const marker of PROJECT_BOUNDARY_MARKERS) {
2238
+ if (await markerExists(dir, marker))
2239
+ return true;
2240
+ }
2241
+ return false;
2242
+ }
2243
+ function pathSegments(dir) {
2244
+ const parsed = path7.parse(path7.resolve(dir));
2245
+ return path7.relative(parsed.root, path7.resolve(dir)).split(path7.sep).filter(Boolean).map((segment) => segment.toLowerCase());
2246
+ }
2247
+ function hasFixtureConvention(dir) {
2248
+ const segments = pathSegments(dir);
2249
+ if (segments.some((segment) => FIXTURE_ROOT_SEGMENTS.has(segment)))
2250
+ return true;
2251
+ return segments.some((segment, index) => segment === "tests" && segments[index + 1] === "fixtures");
2252
+ }
2253
+ function hasAtomicStageSegment(dir) {
2254
+ return pathSegments(dir).some((segment) => STAGE_TMP_PATTERN.test(segment));
2255
+ }
2256
+ async function findGitBoundary(dir) {
2257
+ let current = path7.resolve(dir);
2258
+ const fsRoot = path7.parse(current).root;
2259
+ while (true) {
2260
+ if (await markerExists(current, ".git"))
2261
+ return current;
2262
+ if (current === fsRoot)
2263
+ return void 0;
2264
+ current = path7.dirname(current);
2265
+ }
2266
+ }
2267
+ async function isExcludedLspRoot(dir) {
2268
+ const candidate = path7.resolve(dir);
2269
+ if (hasFixtureConvention(candidate) || hasAtomicStageSegment(candidate))
2270
+ return true;
2271
+ const gitRoot = await findGitBoundary(candidate);
2272
+ if (!gitRoot || gitRoot === candidate)
2273
+ return false;
2274
+ if (getProjectIgnoreGlobs(gitRoot).length === 0)
2275
+ return false;
2276
+ return isPathIgnoredByProject(candidate, gitRoot, true);
2277
+ }
2278
+ async function nearestNonExcludedFallbackRoot(candidate) {
2279
+ if (!await isExcludedLspRoot(candidate))
2280
+ return path7.resolve(candidate);
2281
+ let current = path7.dirname(path7.resolve(candidate));
2282
+ const fsRoot = path7.parse(current).root;
2283
+ let nearestAllowed;
2284
+ while (true) {
2285
+ if (!await isExcludedLspRoot(current)) {
2286
+ nearestAllowed ??= current;
2287
+ for (const marker of FALLBACK_PROJECT_MARKERS) {
2288
+ if (await markerExists(current, marker))
2289
+ return current;
2290
+ }
2291
+ }
2292
+ if (current === fsRoot)
2293
+ break;
2294
+ current = path7.dirname(current);
2295
+ }
2296
+ return nearestAllowed ?? fsRoot;
2297
+ }
2298
+ function isLspInstallDisabled() {
2299
+ return process.env.PI_LENS_DISABLE_LSP_INSTALL === "1";
2300
+ }
2301
+ function canInstall(allowInstall) {
2302
+ return allowInstall !== false && !isLspInstallDisabled();
2303
+ }
2304
+ var DIRECT_LSP_NEGATIVE_TTL_MS = Math.max(3e4, Number.parseInt(process.env.PI_LENS_DIRECT_LSP_NEGATIVE_TTL_MS ?? "600000", 10) || 6e5);
2305
+ var directLspCommandUnavailableUntil = /* @__PURE__ */ new Map();
2306
+ var directLspCommandSkipLoggedUntil = /* @__PURE__ */ new Map();
2307
+ var LSP_SERVICE_GENERATION_FAMILY = "lsp.service.generation";
2308
+ var LSP_SERVICE_GENERATION_VERSION = 1;
2309
+ function lspServiceGenerationCell() {
2310
+ let seed = 0;
2311
+ return getProcessSingleton(LSP_SERVICE_GENERATION_FAMILY, LSP_SERVICE_GENERATION_VERSION, () => ({ generation: seed }), (previous) => {
2312
+ const value = previous?.generation;
2313
+ seed = typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : 0;
2314
+ });
2315
+ }
2316
+ var lspLaunchAvailabilityGeneration = createGenerationSource("lsp-launch-availability", lspServiceGenerationCell);
2317
+ function resetLspLaunchAvailabilityGeneration() {
2318
+ lspLaunchAvailabilityGeneration.bump();
2319
+ }
2320
+ function staleLaunch(generation, subject, proc) {
2321
+ if (generation.isCurrent())
2322
+ return false;
2323
+ try {
2324
+ proc?.process?.kill();
2325
+ } catch {
2326
+ }
2327
+ generation.guardedWrite(subject, () => void 0);
2328
+ return true;
2329
+ }
2330
+ async function installEvidenceForLaunch(toolId, installed, attempt) {
2331
+ const evidence = describeInstallAttempt(attempt);
2332
+ const confirmedManagedPath = await findManagedToolBinary(toolId);
2333
+ return {
2334
+ ...evidence,
2335
+ binary: path7.basename(installed),
2336
+ ...confirmedManagedPath !== void 0 && pathsEqual(confirmedManagedPath, installed) && {
2337
+ source: "managed-dir"
2338
+ }
2339
+ };
2340
+ }
2341
+ function captureInstallAttempt(toolId) {
2342
+ try {
2343
+ return getInstallAttempt?.(toolId);
2344
+ } catch {
2345
+ }
2346
+ return void 0;
2347
+ }
2348
+ function resetDirectLspCommandAvailability() {
2349
+ directLspCommandUnavailableUntil.clear();
2350
+ directLspCommandSkipLoggedUntil.clear();
2351
+ }
2352
+ function pruneExpiredDirectLspNegativeEntries(now = Date.now()) {
2353
+ for (const [command, until] of directLspCommandUnavailableUntil) {
2354
+ if (until <= now) {
2355
+ directLspCommandUnavailableUntil.delete(command);
2356
+ directLspCommandSkipLoggedUntil.delete(command);
2357
+ }
2358
+ }
2359
+ for (const [command, until] of directLspCommandSkipLoggedUntil) {
2360
+ if (until <= now)
2361
+ directLspCommandSkipLoggedUntil.delete(command);
2362
+ }
2363
+ }
2364
+ function isSimpleCommand(command) {
2365
+ return !isFullyQualified(command) && !command.includes("/") && !command.includes("\\");
2366
+ }
2367
+ function isDirectLspCommandTemporarilyUnavailable(command) {
2368
+ const now = Date.now();
2369
+ pruneExpiredDirectLspNegativeEntries(now);
2370
+ const until = directLspCommandUnavailableUntil.get(command);
2371
+ if (!until || until <= now) {
2372
+ directLspCommandUnavailableUntil.delete(command);
2373
+ return false;
2374
+ }
2375
+ const loggedUntil = directLspCommandSkipLoggedUntil.get(command) ?? 0;
2376
+ if (loggedUntil <= now) {
2377
+ logSessionStart(`lsp direct command ${command}: skipped by negative availability cache (${Math.max(0, until - now)}ms remaining)`);
2378
+ directLspCommandSkipLoggedUntil.set(command, until);
2379
+ }
2380
+ return true;
2381
+ }
2382
+ function markDirectLspCommandUnavailable(command) {
2383
+ if (!isSimpleCommand(command))
2384
+ return;
2385
+ directLspCommandUnavailableUntil.set(command, Date.now() + DIRECT_LSP_NEGATIVE_TTL_MS);
2386
+ directLspCommandSkipLoggedUntil.delete(command);
2387
+ }
2388
+ var PI_LENS_BIN_DIR2 = path7.join(getGlobalPiLensDir(), "bin");
2389
+ async function resolveAndLaunch(spec, allowInstall) {
2390
+ const generation = lspLaunchAvailabilityGeneration.capture();
2391
+ const toolLabel = spec.managedToolId ?? spec.candidates[spec.candidates.length - 1] ?? "unknown";
2392
+ let lastRuntimeFailure;
2393
+ const trackRuntimeFailure = (err) => {
2394
+ const message = err instanceof Error ? err.message : String(err);
2395
+ if (!hasSpawnFailureKind(err, "tool-not-found")) {
2396
+ lastRuntimeFailure = err instanceof Error ? err : new Error(message);
2397
+ }
2398
+ };
2399
+ const managedProbeStartedAt = Date.now();
2400
+ const managedCandidate = spec.managedToolId ? await findManagedToolBinary(spec.managedToolId) : void 0;
2401
+ if (staleLaunch(generation, `${toolLabel}:findManagedToolBinary`)) {
2402
+ return void 0;
2403
+ }
2404
+ const candidates = managedCandidate && !spec.candidates.includes(managedCandidate) ? [managedCandidate, ...spec.candidates] : spec.candidates;
2405
+ const candidateFailures = [];
2406
+ for (const [index, command] of candidates.entries()) {
2407
+ logLatency({
2408
+ type: "phase",
2409
+ phase: "lsp_launch_candidate_attempt",
2410
+ filePath: spec.cwd,
2411
+ durationMs: 0,
2412
+ metadata: {
2413
+ tool: toolLabel,
2414
+ command,
2415
+ index,
2416
+ totalCandidates: candidates.length,
2417
+ allowInstall: canInstall(allowInstall)
2418
+ }
2419
+ });
2420
+ logSessionStart(`lsp launch candidate attempt tool=${toolLabel} idx=${index}/${candidates.length - 1} command=${command} cwd=${spec.cwd}`);
2421
+ try {
2422
+ const proc = await launchLSP(command, spec.args, {
2423
+ cwd: spec.cwd,
2424
+ env: spec.env
2425
+ });
2426
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:${command}`, proc)) {
2427
+ return void 0;
2428
+ }
2429
+ logLatency({
2430
+ type: "phase",
2431
+ phase: "lsp_launch_candidate_success",
2432
+ filePath: spec.cwd,
2433
+ durationMs: 0,
2434
+ metadata: {
2435
+ tool: toolLabel,
2436
+ command,
2437
+ index,
2438
+ source: "direct"
2439
+ }
2440
+ });
2441
+ logSessionStart(`lsp launch candidate success tool=${toolLabel} idx=${index} command=${command} source=direct`);
2442
+ if (managedCandidate !== void 0 && command === managedCandidate) {
2443
+ logAvailabilityDecision({
2444
+ tool: toolLabel,
2445
+ verdict: "available",
2446
+ outcome: "success",
2447
+ cause: "ok",
2448
+ elapsedMs: Date.now() - managedProbeStartedAt,
2449
+ latched: false,
2450
+ producer: "lsp-launch",
2451
+ classifiedBy: "probe",
2452
+ evidence: {
2453
+ binary: path7.basename(managedCandidate),
2454
+ source: "managed-dir",
2455
+ correctsLatchedRow: false
2456
+ }
2457
+ });
2458
+ }
2459
+ return { process: proc, source: "direct" };
2460
+ } catch (err) {
2461
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:${command}`)) {
2462
+ return void 0;
2463
+ }
2464
+ const message = err instanceof Error ? err.message : String(err);
2465
+ candidateFailures.push({ index, command, message, err });
2466
+ }
2467
+ }
2468
+ for (const failure of candidateFailures) {
2469
+ logLatency({
2470
+ type: "phase",
2471
+ phase: "lsp_launch_candidate_failed",
2472
+ filePath: spec.cwd,
2473
+ durationMs: 0,
2474
+ metadata: {
2475
+ tool: toolLabel,
2476
+ command: failure.command,
2477
+ index: failure.index,
2478
+ error: failure.message
2479
+ }
2480
+ });
2481
+ logSessionStart(`lsp launch candidate failed tool=${toolLabel} idx=${failure.index} command=${failure.command} error=${failure.message}`);
2482
+ trackRuntimeFailure(failure.err);
2483
+ }
2484
+ const hasOnlyRepairableCandidateFailures = candidateFailures.every((failure) => hasSpawnFailureKind(failure.err, "tool-not-found"));
2485
+ if (!hasOnlyRepairableCandidateFailures) {
2486
+ if (lastRuntimeFailure)
2487
+ throw lastRuntimeFailure;
2488
+ return void 0;
2489
+ }
2490
+ if (!canInstall(allowInstall)) {
2491
+ logSessionStart(`lsp launch install blocked tool=${toolLabel} cwd=${spec.cwd} allowInstall=${allowInstall !== false} globalDisabled=${isLspInstallDisabled()}`);
2492
+ logLatency({
2493
+ type: "phase",
2494
+ phase: "lsp_launch_install_blocked",
2495
+ filePath: spec.cwd,
2496
+ durationMs: 0,
2497
+ metadata: {
2498
+ tool: toolLabel,
2499
+ allowInstall,
2500
+ globalInstallDisabled: isLspInstallDisabled()
2501
+ }
2502
+ });
2503
+ return void 0;
2504
+ }
2505
+ if (spec.managedToolId) {
2506
+ const failedCandidate = candidateFailures.at(-1);
2507
+ const classifiedFailure = classifyProbeFailure({
2508
+ error: failedCandidate?.err instanceof Error ? failedCandidate.err : void 0,
2509
+ spawnFailure: {
2510
+ kind: hasSpawnFailureKind(failedCandidate?.err, "tool-not-found") ? "tool-not-found" : void 0
2511
+ }
2512
+ }, { command: failedCandidate?.command });
2513
+ logAvailabilityDecision({
2514
+ tool: spec.managedToolId,
2515
+ verdict: "unavailable",
2516
+ outcome: classifiedFailure.outcome,
2517
+ cause: classifiedFailure.cause,
2518
+ elapsedMs: Date.now() - managedProbeStartedAt,
2519
+ latched: false,
2520
+ classifiedBy: "probe",
2521
+ producer: "lsp-launch",
2522
+ evidence: classifiedFailure.evidence
2523
+ });
2524
+ logSessionStart(`lsp launch ensure-tool start tool=${spec.managedToolId} cwd=${spec.cwd}`);
2525
+ const installStartedAt = Date.now();
2526
+ const installed = await ensureTool(spec.managedToolId);
2527
+ const installAttempt = captureInstallAttempt(spec.managedToolId);
2528
+ if (staleLaunch(generation, `${toolLabel}:ensureTool`)) {
2529
+ return void 0;
2530
+ }
2531
+ logSessionStart(`lsp launch ensure-tool result tool=${spec.managedToolId} installed=${installed ? "yes" : "no"} path=${installed ?? ""}`);
2532
+ logLatency({
2533
+ type: "phase",
2534
+ phase: "lsp_launch_ensure_tool_result",
2535
+ filePath: spec.cwd,
2536
+ durationMs: 0,
2537
+ metadata: {
2538
+ tool: spec.managedToolId,
2539
+ installed: Boolean(installed),
2540
+ path: installed
2541
+ }
2542
+ });
2543
+ if (installed) {
2544
+ try {
2545
+ const proc = await launchLSP(installed, spec.args, {
2546
+ cwd: spec.cwd,
2547
+ env: spec.env
2548
+ });
2549
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:managed`, proc)) {
2550
+ return void 0;
2551
+ }
2552
+ logSessionStart(`lsp launch managed success tool=${spec.managedToolId} command=${installed} source=managed`);
2553
+ logLatency({
2554
+ type: "phase",
2555
+ phase: "lsp_launch_managed_success",
2556
+ filePath: spec.cwd,
2557
+ durationMs: 0,
2558
+ metadata: {
2559
+ tool: spec.managedToolId,
2560
+ command: installed
2561
+ }
2562
+ });
2563
+ const evidence = await installEvidenceForLaunch(spec.managedToolId, installed, installAttempt);
2564
+ if (staleLaunch(generation, `${toolLabel}:managed-evidence`, proc)) {
2565
+ return void 0;
2566
+ }
2567
+ logAvailabilityDecision({
2568
+ tool: spec.managedToolId,
2569
+ verdict: "available",
2570
+ outcome: "success",
2571
+ cause: "ok",
2572
+ elapsedMs: Date.now() - installStartedAt,
2573
+ latched: false,
2574
+ classifiedBy: "caller",
2575
+ producer: "lsp-launch",
2576
+ evidence: {
2577
+ ...evidence,
2578
+ correctsLatchedRow: false
2579
+ }
2580
+ });
2581
+ return { process: proc, source: "managed" };
2582
+ } catch (err) {
2583
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:managed-rejection`)) {
2584
+ return void 0;
2585
+ }
2586
+ const message = err instanceof Error ? err.message : String(err);
2587
+ logSessionStart(`lsp launch managed failed tool=${spec.managedToolId} command=${installed} error=${message}`);
2588
+ logLatency({
2589
+ type: "phase",
2590
+ phase: "lsp_launch_managed_failed",
2591
+ filePath: spec.cwd,
2592
+ durationMs: 0,
2593
+ metadata: {
2594
+ tool: spec.managedToolId,
2595
+ command: installed,
2596
+ error: message
2597
+ }
2598
+ });
2599
+ trackRuntimeFailure(err);
2600
+ const looksPathResolved = !installed.includes("/") && !installed.includes("\\");
2601
+ if (looksPathResolved && hasSpawnFailureKind(err, "tool-not-found")) {
2602
+ logSessionStart(`lsp launch managed retry force-reinstall tool=${spec.managedToolId}`);
2603
+ const reinstalled = await ensureTool(spec.managedToolId, {
2604
+ forceReinstall: true
2605
+ });
2606
+ const reinstallAttempt = captureInstallAttempt(spec.managedToolId);
2607
+ if (staleLaunch(generation, `${toolLabel}:forceReinstall`)) {
2608
+ return void 0;
2609
+ }
2610
+ if (reinstalled) {
2611
+ try {
2612
+ const proc = await launchLSP(reinstalled, spec.args, {
2613
+ cwd: spec.cwd,
2614
+ env: spec.env
2615
+ });
2616
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:forceReinstall`, proc)) {
2617
+ return void 0;
2618
+ }
2619
+ logSessionStart(`lsp launch managed force-reinstall success tool=${spec.managedToolId} command=${reinstalled}`);
2620
+ logLatency({
2621
+ type: "phase",
2622
+ phase: "lsp_launch_managed_force_reinstall_success",
2623
+ filePath: spec.cwd,
2624
+ durationMs: 0,
2625
+ metadata: {
2626
+ tool: spec.managedToolId,
2627
+ command: reinstalled
2628
+ }
2629
+ });
2630
+ const evidence = await installEvidenceForLaunch(spec.managedToolId, reinstalled, reinstallAttempt);
2631
+ if (staleLaunch(generation, `${toolLabel}:forceReinstall-evidence`, proc)) {
2632
+ return void 0;
2633
+ }
2634
+ logAvailabilityDecision({
2635
+ tool: spec.managedToolId,
2636
+ verdict: "available",
2637
+ outcome: "success",
2638
+ cause: "ok",
2639
+ elapsedMs: Date.now() - installStartedAt,
2640
+ latched: false,
2641
+ classifiedBy: "caller",
2642
+ producer: "lsp-launch",
2643
+ evidence: {
2644
+ ...evidence,
2645
+ correctsLatchedRow: false
2646
+ }
2647
+ });
2648
+ return { process: proc, source: "managed" };
2649
+ } catch (retryErr) {
2650
+ logSessionStart(`lsp launch managed force-reinstall failed tool=${spec.managedToolId} error=${retryErr instanceof Error ? retryErr.message : String(retryErr)}`);
2651
+ }
2652
+ }
2653
+ }
2654
+ }
2655
+ }
2656
+ }
2657
+ const runtimeInstall = spec.runtimeInstall;
2658
+ const runtimeAvailable = runtimeInstall ? await isOnPath(runtimeInstall.runtimeCommand) : false;
2659
+ if (staleLaunch(generation, `${toolLabel}:runtimeAvailability`)) {
2660
+ return void 0;
2661
+ }
2662
+ if (runtimeInstall && runtimeAvailable) {
2663
+ const ok = await runtimeInstall.install();
2664
+ if (staleLaunch(generation, `${toolLabel}:runtimeInstall`)) {
2665
+ return void 0;
2666
+ }
2667
+ if (ok) {
2668
+ const retry = runtimeInstall.retryCandidates ?? spec.candidates;
2669
+ for (const command of retry) {
2670
+ try {
2671
+ const proc = await launchLSP(command, spec.args, {
2672
+ cwd: spec.cwd,
2673
+ env: spec.env
2674
+ });
2675
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:runtime`, proc)) {
2676
+ return void 0;
2677
+ }
2678
+ return { process: proc, source: "managed" };
2679
+ } catch (err) {
2680
+ if (staleLaunch(generation, `${toolLabel}:launchLSP:runtime`)) {
2681
+ return void 0;
2682
+ }
2683
+ trackRuntimeFailure(err);
2684
+ }
2685
+ }
2686
+ }
2687
+ }
2688
+ if (lastRuntimeFailure) {
2689
+ throw lastRuntimeFailure;
2690
+ }
2691
+ return void 0;
2692
+ }
2693
+ async function resolveAndLaunchBundle(spec, allowInstall) {
2694
+ let runtime;
2695
+ for (const candidate of spec.runtimeCandidates) {
2696
+ if (await isOnPath(candidate)) {
2697
+ runtime = candidate;
2698
+ break;
2699
+ }
2700
+ }
2701
+ if (!runtime) {
2702
+ logSessionStart(`lsp launch bundle skip tool=${spec.bundleToolId}: no runtime on PATH (tried ${spec.runtimeCandidates.join(", ")})`);
2703
+ return void 0;
2704
+ }
2705
+ let bundleDir = await getToolPath(spec.bundleToolId);
2706
+ if (!bundleDir && canInstall(allowInstall)) {
2707
+ bundleDir = await ensureTool(spec.bundleToolId);
2708
+ }
2709
+ if (!bundleDir) {
2710
+ logSessionStart(`lsp launch bundle skip tool=${spec.bundleToolId}: bundle not installed (allowInstall=${allowInstall !== false})`);
2711
+ return void 0;
2712
+ }
2713
+ try {
2714
+ const proc = await launchLSP(runtime, spec.args(bundleDir), {
2715
+ cwd: spec.cwd,
2716
+ env: spec.env
2717
+ });
2718
+ logSessionStart(`lsp launch bundle success tool=${spec.bundleToolId} runtime=${runtime} bundle=${bundleDir}`);
2719
+ return { process: proc, source: "managed" };
2720
+ } catch (err) {
2721
+ const message = err instanceof Error ? err.message : String(err);
2722
+ logSessionStart(`lsp launch bundle failed tool=${spec.bundleToolId} runtime=${runtime} error=${message}`);
2723
+ return void 0;
2724
+ }
2725
+ }
2726
+ async function resolveAndLaunchTreeBinary(spec, allowInstall) {
2727
+ for (const command of spec.candidates) {
2728
+ try {
2729
+ const proc = await launchLSP(command, spec.args, {
2730
+ cwd: spec.cwd,
2731
+ env: spec.env
2732
+ });
2733
+ return { process: proc, source: "direct" };
2734
+ } catch {
2735
+ }
2736
+ }
2737
+ let bundleDir = await getToolPath(spec.bundleToolId);
2738
+ if (!bundleDir && canInstall(allowInstall)) {
2739
+ bundleDir = await ensureTool(spec.bundleToolId);
2740
+ }
2741
+ if (!bundleDir) {
2742
+ logSessionStart(`lsp launch tree-bin skip tool=${spec.bundleToolId}: not on PATH and bundle not installed (allowInstall=${allowInstall !== false})`);
2743
+ return void 0;
2744
+ }
2745
+ const suffix = process.platform === "win32" ? ".exe" : "";
2746
+ const binPath = path7.join(bundleDir, ...spec.binRelPath.split("/")) + suffix;
2747
+ try {
2748
+ const proc = await launchLSP(binPath, spec.args, {
2749
+ cwd: spec.cwd,
2750
+ env: spec.env
2751
+ });
2752
+ logSessionStart(`lsp launch tree-bin success tool=${spec.bundleToolId} bin=${binPath}`);
2753
+ return { process: proc, source: "managed" };
2754
+ } catch (err) {
2755
+ const message = err instanceof Error ? err.message : String(err);
2756
+ logSessionStart(`lsp launch tree-bin failed tool=${spec.bundleToolId} bin=${binPath} error=${message}`);
2757
+ return void 0;
2758
+ }
2759
+ }
2760
+ function nodeBinLocalCandidates(root, baseName) {
2761
+ const localBase = path7.join(root, "node_modules", ".bin", baseName);
2762
+ if (process.platform === "win32") {
2763
+ return [`${localBase}.cmd`, `${localBase}.exe`];
2764
+ }
2765
+ return [localBase];
2766
+ }
2767
+ function nodeBinCandidates(root, baseName) {
2768
+ return [...nodeBinLocalCandidates(root, baseName), baseName];
2769
+ }
2770
+ function piAgentExtensionsRootKey(file) {
2771
+ const dirKey = normalizeEphemeralMapKey(path7.dirname(path7.resolve(file)));
2772
+ const marker = "/.pi/agent/extensions";
2773
+ const index = dirKey.indexOf(marker);
2774
+ if (index === -1)
2775
+ return void 0;
2776
+ return dirKey.slice(0, index + marker.length);
2777
+ }
2778
+ function IgnoreHomeRoot(primary) {
2779
+ const homeKey = normalizeEphemeralMapKey(path7.resolve(os6.homedir()));
2780
+ return withRootMarkers(async (file) => {
2781
+ const root = await primary(file);
2782
+ if (!root)
2783
+ return void 0;
2784
+ return normalizeEphemeralMapKey(path7.resolve(root)) === homeKey ? void 0 : root;
2785
+ }, primary.rootMarkers ?? []);
2786
+ }
2787
+ function rubyBinCandidates(baseName) {
2788
+ const candidates = [];
2789
+ const home = os6.homedir();
2790
+ const isWin = process.platform === "win32";
2791
+ const ext = isWin ? ".bat" : "";
2792
+ candidates.push(path7.join(home, ".local", "share", "mise", "installs", "ruby", "bin", `${baseName}${ext}`));
2793
+ candidates.push(path7.join(home, ".asdf", "installs", "ruby", "bin", `${baseName}${ext}`));
2794
+ if (isWin) {
2795
+ const driveRoot = path7.parse(home).root;
2796
+ for (const entry of getRubyVersionDirNamesSync(driveRoot)) {
2797
+ candidates.push(path7.join(driveRoot, entry, "bin", `${baseName}.bat`));
2798
+ candidates.push(path7.join(driveRoot, entry, "bin", baseName));
2799
+ }
2800
+ }
2801
+ return candidates;
2802
+ }
2803
+ function createInteractiveServer(spec) {
2804
+ return {
2805
+ id: spec.id,
2806
+ name: spec.name,
2807
+ extensions: spec.extensions,
2808
+ idleEviction: "unmeasured",
2809
+ root: spec.root,
2810
+ rootMarkers: spec.root.rootMarkers,
2811
+ fallbackFor: spec.fallbackFor,
2812
+ requiresProjectRoot: spec.requiresProjectRoot,
2813
+ availabilityKey: typeof spec.command === "string" && isSimpleCommand(spec.command) ? spec.command : void 0,
2814
+ async spawn(root) {
2815
+ const command = typeof spec.command === "function" ? spec.command(root) : spec.command;
2816
+ const args = typeof spec.args === "function" ? spec.args(root) : spec.args || [];
2817
+ if (isSimpleCommand(command) && isDirectLspCommandTemporarilyUnavailable(command)) {
2818
+ return void 0;
2819
+ }
2820
+ const runtimeEnv = spec.runtime === "java" ? await resolveJavaRuntimeEnv() : void 0;
2821
+ try {
2822
+ const proc = await launchLSP(command, args, {
2823
+ cwd: root,
2824
+ ...runtimeEnv ? { env: runtimeEnv } : {}
2825
+ });
2826
+ const initialization = typeof spec.initialization === "function" ? spec.initialization(root) : spec.initialization;
2827
+ return { process: proc, source: "direct", initialization };
2828
+ } catch (err) {
2829
+ if (hasSpawnFailureKind(err, "tool-not-found")) {
2830
+ markDirectLspCommandUnavailable(command);
2831
+ }
2832
+ return void 0;
2833
+ }
2834
+ }
2835
+ };
2836
+ }
2837
+ function PriorityRoot(markerGroups, excludePatterns, stopDir) {
2838
+ const resolvers = markerGroups.map((markers) => NearestRoot(markers, excludePatterns, stopDir));
2839
+ return withRootMarkers(async (file) => {
2840
+ for (const resolve3 of resolvers) {
2841
+ const root = await resolve3(file);
2842
+ if (root)
2843
+ return root;
2844
+ }
2845
+ return void 0;
2846
+ }, markerGroups.flat());
2847
+ }
2848
+ var FileDirRoot = async (file) => {
2849
+ const candidate = path7.resolve(path7.dirname(file));
2850
+ return nearestNonExcludedFallbackRoot(candidate);
2851
+ };
2852
+ function RootWithFallback(primary, fallback = FileDirRoot) {
2853
+ return withRootMarkers(async (file) => {
2854
+ const primaryRoot = await primary(file);
2855
+ if (primaryRoot)
2856
+ return primaryRoot;
2857
+ return fallback(file);
2858
+ }, primary.rootMarkers ?? []);
2859
+ }
2860
+ function WorkspacePriorityRoot(markerGroups, excludePatterns) {
2861
+ return withRootMarkers(async (file) => PriorityRoot(markerGroups, excludePatterns, process.cwd())(file), markerGroups.flat());
2862
+ }
2863
+ function isPermissionFsError(err) {
2864
+ const code = err?.code;
2865
+ return code === "EACCES" || code === "EPERM";
2866
+ }
2867
+ function markerProbeDir(dir, pattern) {
2868
+ const normalized = toPosix(pattern);
2869
+ const slash = normalized.lastIndexOf("/");
2870
+ const parentPattern = slash >= 0 ? normalized.slice(0, slash) : "";
2871
+ return parentPattern ? path7.join(dir, ...parentPattern.split("/").filter(Boolean)) : dir;
2872
+ }
2873
+ async function markerExists(dir, pattern) {
2874
+ if (!pattern.includes("*")) {
2875
+ try {
2876
+ await stat(path7.join(dir, pattern));
2877
+ return true;
2878
+ } catch (err) {
2879
+ if (isPermissionFsError(err)) {
2880
+ logSessionStart(`lsp root marker skipped: permission error stat ${path7.join(dir, pattern)}`);
2881
+ }
2882
+ return false;
2883
+ }
2884
+ }
2885
+ const normalized = pattern.replace(/\\/g, "/");
2886
+ const slash = normalized.lastIndexOf("/");
2887
+ const basenamePattern = slash >= 0 ? normalized.slice(slash + 1) : normalized;
2888
+ if (!basenamePattern)
2889
+ return false;
2890
+ const targetDir = markerProbeDir(dir, normalized);
2891
+ try {
2892
+ const entries = await readdir(targetDir, { withFileTypes: true });
2893
+ return direntsHaveMarkerGlobMatch(entries, basenamePattern);
2894
+ } catch (err) {
2895
+ if (isPermissionFsError(err)) {
2896
+ logSessionStart(`lsp root marker skipped: permission error read ${targetDir}`);
2897
+ }
2898
+ return false;
2899
+ }
2900
+ }
2901
+ var rootMtimeBound = (label) => ({
2902
+ ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
2903
+ signal: void 0,
2904
+ hook: "tool_result_edit",
2905
+ label
2906
+ });
2907
+ function NearestRoot(includePatterns, excludePatterns, stopDir) {
2908
+ const cache = /* @__PURE__ */ new Map();
2909
+ const inFlight = /* @__PURE__ */ new Map();
2910
+ const subdirPatterns = [];
2911
+ for (const pattern of [...includePatterns, ...excludePatterns ?? []]) {
2912
+ if (markerProbeDir("", pattern))
2913
+ subdirPatterns.push(pattern);
2914
+ }
2915
+ return withRootMarkers(async (file) => {
2916
+ const startDir = path7.resolve(path7.dirname(file));
2917
+ const dirKey = normalizeMapKey(startDir);
2918
+ const cached = cache.get(dirKey);
2919
+ if (cached !== void 0 && Date.now() - cached.walkedAt < FRESHNESS_CADENCE_MS && await bounded(dirMtimesStillFreshAsync(cached.probedDirs), rootMtimeBound("lsp-root-memo-freshness")) === true)
2920
+ return cached.root;
2921
+ const flying = inFlight.get(dirKey);
2922
+ if (flying)
2923
+ return flying;
2924
+ const probedDirs = [];
2925
+ const walkedAt = Date.now();
2926
+ const promise = (async () => {
2927
+ let currentDir = startDir;
2928
+ const fsRoot = path7.parse(currentDir).root;
2929
+ const stop = stopDir ? path7.resolve(stopDir) : fsRoot;
2930
+ while (true) {
2931
+ if (stop !== fsRoot && currentDir.startsWith(stop + path7.sep) === false && currentDir !== stop) {
2932
+ break;
2933
+ }
2934
+ const stepDirs = [
2935
+ currentDir,
2936
+ ...subdirPatterns.map((pattern) => markerProbeDir(currentDir, pattern))
2937
+ ];
2938
+ const stepRecords = await bounded(dirMtimeRecordsAsync(stepDirs), rootMtimeBound("lsp-root-walk-dir-mtimes"));
2939
+ probedDirs.push(...stepRecords ?? unknownDirMtimeRecords(stepDirs));
2940
+ if (excludePatterns) {
2941
+ let excluded = false;
2942
+ for (const pattern of excludePatterns) {
2943
+ if (await markerExists(currentDir, pattern)) {
2944
+ excluded = true;
2945
+ break;
2946
+ }
2947
+ }
2948
+ if (excluded) {
2949
+ currentDir = path7.dirname(currentDir);
2950
+ continue;
2951
+ }
2952
+ }
2953
+ for (const pattern of includePatterns) {
2954
+ if (await markerExists(currentDir, pattern) && (pattern !== ".git" || currentDir !== os6.tmpdir()) && !await isExcludedLspRoot(currentDir)) {
2955
+ return enforceLspRootCeiling(currentDir, process.cwd(), file);
2956
+ }
2957
+ }
2958
+ if (currentDir === stop || currentDir === fsRoot) {
2959
+ break;
2960
+ }
2961
+ currentDir = path7.dirname(currentDir);
2962
+ }
2963
+ return void 0;
2964
+ })();
2965
+ inFlight.set(dirKey, promise);
2966
+ try {
2967
+ const result = await promise;
2968
+ if (result !== void 0)
2969
+ cache.set(dirKey, { root: result, probedDirs, walkedAt });
2970
+ return result;
2971
+ } finally {
2972
+ inFlight.delete(dirKey);
2973
+ }
2974
+ }, includePatterns);
2975
+ }
2976
+ var createRootDetector = NearestRoot;
2977
+ function isOnPath(command) {
2978
+ return isCommandAvailableAsync(command);
2979
+ }
2980
+ async function tryGoInstallGopls() {
2981
+ const isWindows2 = process.platform === "win32";
2982
+ const result = await safeSpawnAsync(isWindows2 ? "go.exe" : "go", ["install", "golang.org/x/tools/gopls@latest"], { timeout: 18e4, ignoreAmbientSignal: true });
2983
+ return !result.error && result.status === 0;
2984
+ }
2985
+ async function tryDotnetToolInstall(tool) {
2986
+ mkdirSync2(PI_LENS_BIN_DIR2, { recursive: true });
2987
+ const result = await safeSpawnAsync("dotnet", ["tool", "install", "--tool-path", PI_LENS_BIN_DIR2, tool], { timeout: 18e4, ignoreAmbientSignal: true });
2988
+ if (!result.error && result.status === 0)
2989
+ return true;
2990
+ const stderr = result.stderr ?? "";
2991
+ if (stderr.includes("No NuGet sources are defined or enabled")) {
2992
+ logSessionStart(`lsp dotnet-install: NuGet sources missing \u2014 cannot install ${tool}. Run: dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org`);
2993
+ return false;
2994
+ }
2995
+ const updateResult = await safeSpawnAsync("dotnet", ["tool", "update", "--tool-path", PI_LENS_BIN_DIR2, tool], { timeout: 18e4, ignoreAmbientSignal: true });
2996
+ return !updateResult.error && updateResult.status === 0;
2997
+ }
2998
+ async function findAncestorFile(startDir, ...relativeSegments) {
2999
+ return findAncestorFileAmong(startDir, [relativeSegments]);
3000
+ }
3001
+ async function findAncestorFileAmong(startDir, candidateSegmentLists) {
3002
+ const fs5 = await import("node:fs/promises");
3003
+ let currentDir = path7.resolve(startDir);
3004
+ while (!isAtOrAboveHomeDir(currentDir)) {
3005
+ for (const segments of candidateSegmentLists) {
3006
+ const candidate = path7.join(currentDir, ...segments);
3007
+ try {
3008
+ await fs5.access(candidate);
3009
+ return candidate;
3010
+ } catch {
3011
+ }
3012
+ }
3013
+ const parent = path7.dirname(currentDir);
3014
+ if (parent === currentDir)
3015
+ break;
3016
+ currentDir = parent;
3017
+ }
3018
+ return void 0;
3019
+ }
3020
+ var CLASSIC_TS_REPAIR_FAMILY = "lsp.classic-ts-repair-guard";
3021
+ var CLASSIC_TS_REPAIR_VERSION = 1;
3022
+ function classicTsRepairState() {
3023
+ return getProcessSingleton(CLASSIC_TS_REPAIR_FAMILY, CLASSIC_TS_REPAIR_VERSION, () => ({ attempted: false }));
3024
+ }
3025
+ function resetClassicTsRepairGuard() {
3026
+ classicTsRepairState().attempted = false;
3027
+ }
3028
+ function typescriptDirsForTsc(tscPath) {
3029
+ const binDir = path7.dirname(tscPath);
3030
+ return [
3031
+ path7.join(binDir, "..", "typescript"),
3032
+ path7.join(binDir, "..", "..", "typescript")
3033
+ ];
3034
+ }
3035
+ async function typescriptVersionForTsc(tscPath) {
3036
+ if (!path7.isAbsolute(tscPath))
3037
+ return void 0;
3038
+ for (const dir of typescriptDirsForTsc(tscPath)) {
3039
+ let manifest;
3040
+ try {
3041
+ manifest = await readFile(path7.join(dir, "package.json"), "utf8");
3042
+ } catch {
3043
+ continue;
3044
+ }
3045
+ let version;
3046
+ try {
3047
+ const parsed = JSON.parse(manifest);
3048
+ if (typeof parsed !== "object" || parsed === null || !("version" in parsed) || typeof parsed.version !== "string") {
3049
+ return void 0;
3050
+ }
3051
+ version = parsed.version;
3052
+ } catch {
3053
+ return void 0;
3054
+ }
3055
+ const majorText = version.split(".", 1)[0] ?? "";
3056
+ const major = /^\d+$/.test(majorText) ? Number(majorText) : Number.NaN;
3057
+ if (!Number.isFinite(major))
3058
+ return void 0;
3059
+ return { version, major };
3060
+ }
3061
+ return void 0;
3062
+ }
3063
+ async function findTsserverPath(root, allowInstall) {
3064
+ const fs5 = await import("node:fs/promises");
3065
+ const ancestorHit = await findAncestorFile(root, "node_modules", "typescript", "lib", "tsserver.js");
3066
+ if (ancestorHit)
3067
+ return ancestorHit;
3068
+ const cwdCandidate = path7.join(process.cwd(), "node_modules", "typescript", "lib", "tsserver.js");
3069
+ try {
3070
+ await fs5.access(cwdCandidate);
3071
+ return cwdCandidate;
3072
+ } catch {
3073
+ }
3074
+ const tsserverForTsc = async (tscPath) => {
3075
+ if (!tscPath)
3076
+ return void 0;
3077
+ for (const dir of typescriptDirsForTsc(tscPath)) {
3078
+ const candidate = path7.join(dir, "lib", "tsserver.js");
3079
+ try {
3080
+ await fs5.access(candidate);
3081
+ return candidate;
3082
+ } catch {
3083
+ }
3084
+ }
3085
+ return void 0;
3086
+ };
3087
+ const installAllowed = canInstall(allowInstall);
3088
+ const discoveredTsc = await ensureTool("typescript", {
3089
+ allowInstall: installAllowed
3090
+ });
3091
+ const discoveredTsserver = await tsserverForTsc(discoveredTsc);
3092
+ if (discoveredTsserver || !discoveredTsc || !installAllowed || classicTsRepairState().attempted) {
3093
+ return discoveredTsserver;
3094
+ }
3095
+ const discoveredVersion = await typescriptVersionForTsc(discoveredTsc);
3096
+ if (!discoveredVersion || discoveredVersion.major < 7)
3097
+ return void 0;
3098
+ classicTsRepairState().attempted = true;
3099
+ logSessionStart(`lsp typescript: managed compiler resolved to TypeScript ${discoveredVersion.version}, which ships no tsserver.js; reinstalling pinned classic fallback`);
3100
+ const repairedTsc = await ensureTool("typescript", {
3101
+ allowInstall: true,
3102
+ forceReinstall: true
3103
+ });
3104
+ return tsserverForTsc(repairedTsc);
3105
+ }
3106
+ async function findNativeTypeScriptLsp(root) {
3107
+ let currentDir = path7.resolve(root);
3108
+ while (!isAtOrAboveHomeDir(currentDir)) {
3109
+ const typescriptDir = path7.join(currentDir, "node_modules", "typescript");
3110
+ const packageJsonPath = path7.join(typescriptDir, "package.json");
3111
+ let packageJsonText;
3112
+ try {
3113
+ packageJsonText = await readFile(packageJsonPath, "utf8");
3114
+ } catch (error) {
3115
+ if (error.code !== "ENOENT") {
3116
+ return void 0;
3117
+ }
3118
+ try {
3119
+ const dirStat = await stat(typescriptDir);
3120
+ if (dirStat.isDirectory())
3121
+ return void 0;
3122
+ } catch {
3123
+ }
3124
+ const parent = path7.dirname(currentDir);
3125
+ if (parent === currentDir)
3126
+ return void 0;
3127
+ currentDir = parent;
3128
+ continue;
3129
+ }
3130
+ let version;
3131
+ try {
3132
+ const parsed = JSON.parse(packageJsonText);
3133
+ if (typeof parsed !== "object" || parsed === null || !("version" in parsed) || typeof parsed.version !== "string") {
3134
+ return void 0;
3135
+ }
3136
+ version = parsed.version;
3137
+ } catch {
3138
+ return void 0;
3139
+ }
3140
+ const majorText = version.split(".", 1)[0] ?? "";
3141
+ const major = /^\d+$/.test(majorText) ? Number(majorText) : Number.NaN;
3142
+ if (!Number.isFinite(major) || major < 7)
3143
+ return void 0;
3144
+ const localTsc = path7.join(currentDir, "node_modules", ".bin", "tsc");
3145
+ const candidates = process.platform === "win32" ? [`${localTsc}.cmd`, `${localTsc}.exe`, localTsc] : [localTsc];
3146
+ for (const command of candidates) {
3147
+ try {
3148
+ await access(command);
3149
+ return { command, version };
3150
+ } catch {
3151
+ }
3152
+ }
3153
+ return void 0;
3154
+ }
3155
+ return void 0;
3156
+ }
3157
+ function dotnetToolCandidates(tool) {
3158
+ const home = os6.homedir();
3159
+ return [
3160
+ path7.join(PI_LENS_BIN_DIR2, `${tool}.exe`),
3161
+ path7.join(PI_LENS_BIN_DIR2, tool),
3162
+ path7.join(home, ".dotnet", "tools", `${tool}.exe`),
3163
+ path7.join(home, ".dotnet", "tools", tool),
3164
+ tool
3165
+ ].filter(Boolean);
3166
+ }
3167
+ function binExeVariants(dir, tool) {
3168
+ return process.platform === "win32" ? [path7.join(dir, `${tool}.exe`), path7.join(dir, tool)] : [path7.join(dir, tool)];
3169
+ }
3170
+ function goBinCandidates(tool) {
3171
+ const gopath = process.env.GOPATH?.split(path7.delimiter)[0] || path7.join(os6.homedir(), "go");
3172
+ return [tool, ...binExeVariants(path7.join(gopath, "bin"), tool)];
3173
+ }
3174
+ function cargoBinCandidates(tool) {
3175
+ const cargoHome = process.env.CARGO_HOME || path7.join(os6.homedir(), ".cargo");
3176
+ return [tool, ...binExeVariants(path7.join(cargoHome, "bin"), tool)];
3177
+ }
3178
+ async function tryGemInstall(gem) {
3179
+ const { join: join3 } = await import("node:path");
3180
+ const binDir = join3(getGlobalPiLensDir(), "bin");
3181
+ const { mkdir } = await import("node:fs/promises");
3182
+ await mkdir(binDir, { recursive: true });
3183
+ const result = await safeSpawnAsync("gem", ["install", gem, "--bindir", binDir, "--no-document"], { timeout: 18e4, ignoreAmbientSignal: true });
3184
+ const ok = !result.error && result.status === 0;
3185
+ if (ok) {
3186
+ const sep2 = process.platform === "win32" ? ";" : ":";
3187
+ if (!process.env.PATH?.includes(binDir)) {
3188
+ process.env.PATH = `${binDir}${sep2}${process.env.PATH ?? ""}`;
3189
+ }
3190
+ }
3191
+ return ok;
3192
+ }
3193
+ function DenoExcludeRoot(primary) {
3194
+ const denoDetector = createRootDetector(["deno.json", "deno.jsonc"]);
3195
+ return async (file) => {
3196
+ const denoRoot = await denoDetector(file);
3197
+ if (denoRoot)
3198
+ return void 0;
3199
+ return primary(file);
3200
+ };
3201
+ }
3202
+ var JS_TS_LSP_EXTENSIONS = KIND_EXTENSIONS["jsts"].filter((ext) => ext !== ".svelte" && ext !== ".vue");
3203
+ var TS_CONFIG_MARKERS = ["tsconfig.json", "jsconfig.json"];
3204
+ var TS_TOOLING_MARKERS = [
3205
+ "package-lock.json",
3206
+ "bun.lockb",
3207
+ "bun.lock",
3208
+ "pnpm-lock.yaml",
3209
+ "yarn.lock",
3210
+ "package.json"
3211
+ ];
3212
+ var TS_FAMILY_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts"]);
3213
+ function isTsFamilyFile(file) {
3214
+ return TS_FAMILY_EXTENSIONS.has(path7.extname(file).toLowerCase());
3215
+ }
3216
+ function tsConfigMarkersForFile(file) {
3217
+ return isTsFamilyFile(file) ? ["tsconfig.json"] : TS_CONFIG_MARKERS;
3218
+ }
3219
+ var TypeScriptConfigRootTsOnly = IgnoreHomeRoot(createRootDetector(["tsconfig.json"]));
3220
+ var TypeScriptConfigRootEither = IgnoreHomeRoot(createRootDetector([...TS_CONFIG_MARKERS]));
3221
+ var TypeScriptToolingRoot = IgnoreHomeRoot(createRootDetector([...TS_TOOLING_MARKERS]));
3222
+ async function findTypeScriptProjectRoot(file) {
3223
+ const configDetector = isTsFamilyFile(file) ? TypeScriptConfigRootTsOnly : TypeScriptConfigRootEither;
3224
+ const [configRoot, toolingRoot] = await Promise.all([
3225
+ configDetector(file),
3226
+ TypeScriptToolingRoot(file)
3227
+ ]);
3228
+ if (!configRoot)
3229
+ return toolingRoot;
3230
+ if (!toolingRoot)
3231
+ return configRoot;
3232
+ return isSameOrWithin(toolingRoot, configRoot) ? configRoot : toolingRoot;
3233
+ }
3234
+ async function findExtensionBoundedRoot(file, extensionRootKey) {
3235
+ const startDir = path7.resolve(path7.dirname(file));
3236
+ let currentDir = startDir;
3237
+ const configMarkers = tsConfigMarkersForFile(file);
3238
+ while (true) {
3239
+ for (const pattern of configMarkers) {
3240
+ try {
3241
+ await stat(path7.join(currentDir, pattern));
3242
+ return currentDir;
3243
+ } catch {
3244
+ }
3245
+ }
3246
+ for (const pattern of TS_TOOLING_MARKERS) {
3247
+ try {
3248
+ await stat(path7.join(currentDir, pattern));
3249
+ return currentDir;
3250
+ } catch {
3251
+ }
3252
+ }
3253
+ const currentKey = normalizeEphemeralMapKey(path7.resolve(currentDir));
3254
+ if (currentKey === extensionRootKey)
3255
+ return void 0;
3256
+ const parent = path7.dirname(currentDir);
3257
+ if (parent === currentDir)
3258
+ return void 0;
3259
+ currentDir = parent;
3260
+ }
3261
+ }
3262
+ async function hasAgentLevelProjectMarker(extensionRootKey) {
3263
+ const agentDir = path7.dirname(extensionRootKey);
3264
+ if (!agentDir || agentDir === extensionRootKey)
3265
+ return false;
3266
+ for (const pattern of [...TS_CONFIG_MARKERS, ...TS_TOOLING_MARKERS]) {
3267
+ try {
3268
+ await stat(path7.join(agentDir, pattern));
3269
+ return true;
3270
+ } catch {
3271
+ }
3272
+ }
3273
+ return false;
3274
+ }
3275
+ var TypeScriptRoot = withRootMarkers(DenoExcludeRoot(async (file) => {
3276
+ const extensionRootKey = piAgentExtensionsRootKey(file);
3277
+ if (extensionRootKey) {
3278
+ const bounded2 = await findExtensionBoundedRoot(file, extensionRootKey);
3279
+ if (bounded2)
3280
+ return bounded2;
3281
+ if (await hasAgentLevelProjectMarker(extensionRootKey)) {
3282
+ return FileDirRoot(file);
3283
+ }
3284
+ return void 0;
3285
+ }
3286
+ const projectRoot = await findTypeScriptProjectRoot(file);
3287
+ if (projectRoot)
3288
+ return projectRoot;
3289
+ return FileDirRoot(file);
3290
+ }), [...TS_CONFIG_MARKERS, ...TS_TOOLING_MARKERS]);
3291
+ var TypeScriptServer = {
3292
+ id: "typescript",
3293
+ idleEviction: "transparent",
3294
+ name: "TypeScript Language Server",
3295
+ extensions: JS_TS_LSP_EXTENSIONS,
3296
+ autoPropagateDiagnostics: true,
3297
+ root: TypeScriptRoot,
3298
+ rootMarkers: TypeScriptRoot.rootMarkers,
3299
+ async spawn(root, options) {
3300
+ const fs5 = await import("node:fs/promises");
3301
+ const nativeLsp = await findNativeTypeScriptLsp(root);
3302
+ if (nativeLsp) {
3303
+ const env2 = await getToolEnvironment();
3304
+ logSessionStart(`lsp typescript-native: version=${nativeLsp.version} command=${nativeLsp.command}`);
3305
+ const proc2 = await launchLSP(nativeLsp.command, ["--lsp", "--stdio"], {
3306
+ cwd: root,
3307
+ env: env2
3308
+ });
3309
+ return { process: proc2, source: "direct", launchVariant: "native-ts7" };
3310
+ }
3311
+ let source = "direct";
3312
+ let lspPath = await findAncestorFileAmong(root, [
3313
+ ["node_modules", ".bin", "typescript-language-server.cmd"],
3314
+ ["node_modules", ".bin", "typescript-language-server"]
3315
+ ]);
3316
+ if (!lspPath) {
3317
+ lspPath = await ensureTool("typescript-language-server", {
3318
+ allowInstall: canInstall(options?.allowInstall)
3319
+ });
3320
+ if (lspPath)
3321
+ source = "managed";
3322
+ if (!lspPath) {
3323
+ return void 0;
3324
+ }
3325
+ }
3326
+ let tsserverPath = await findTsserverPath(root, options?.allowInstall);
3327
+ if (!tsserverPath) {
3328
+ const localCandidate = path7.join(path7.dirname(lspPath), "..", "typescript", "lib", "tsserver.js");
3329
+ try {
3330
+ await fs5.access(localCandidate);
3331
+ tsserverPath = localCandidate;
3332
+ } catch {
3333
+ }
3334
+ }
3335
+ if (tsserverPath)
3336
+ source = "managed";
3337
+ const env = await getToolEnvironment();
3338
+ const proc = await launchLSP(lspPath, ["--stdio"], {
3339
+ cwd: root,
3340
+ env: {
3341
+ ...env,
3342
+ TSSERVER_PATH: tsserverPath
3343
+ }
3344
+ });
3345
+ return {
3346
+ process: proc,
3347
+ source,
3348
+ initialization: tsserverPath ? { tsserver: { path: tsserverPath } } : void 0,
3349
+ launchVariant: "classic"
3350
+ };
3351
+ }
3352
+ };
3353
+ var DenoServer = {
3354
+ id: "deno",
3355
+ idleEviction: "transparent",
3356
+ name: "Deno Language Server",
3357
+ fallbackFor: "typescript",
3358
+ extensions: JS_TS_LSP_EXTENSIONS,
3359
+ autoPropagateDiagnostics: true,
3360
+ root: createRootDetector(["deno.json", "deno.jsonc"]),
3361
+ async spawn(root, options) {
3362
+ return resolveAndLaunch({
3363
+ candidates: ["deno"],
3364
+ args: ["lsp"],
3365
+ cwd: root,
3366
+ managedToolId: "deno"
3367
+ }, options?.allowInstall);
3368
+ }
3369
+ };
3370
+ var PythonServer = {
3371
+ id: "python",
3372
+ idleEviction: "transparent",
3373
+ name: "Pyright Language Server",
3374
+ extensions: KIND_EXTENSIONS["python"],
3375
+ root: RootWithFallback(createRootDetector([
3376
+ ".git",
3377
+ "pyproject.toml",
3378
+ "setup.py",
3379
+ "setup.cfg",
3380
+ "requirements.txt",
3381
+ "Pipfile",
3382
+ "poetry.lock"
3383
+ ])),
3384
+ async spawn(root, options) {
3385
+ const pythonEnvironment = await detectPythonEnvironment(root);
3386
+ const env = augmentPythonEnvironment(await getToolEnvironment(), pythonEnvironment);
3387
+ let source = "direct";
3388
+ const pyrightInit = (pythonPath) => ({
3389
+ ...pythonPath ? { pythonPath } : {},
3390
+ openFilesOnly: true
3391
+ });
3392
+ const projectPyright = await resolveAndLaunch({
3393
+ candidates: [
3394
+ ...pythonEnvironmentToolCandidates(pythonEnvironment, "pyright-langserver"),
3395
+ ...nodeBinLocalCandidates(root, "pyright-langserver"),
3396
+ ...pythonEnvironmentToolCandidates(pythonEnvironment, "basedpyright-langserver"),
3397
+ ...nodeBinLocalCandidates(root, "basedpyright-langserver")
3398
+ ],
3399
+ args: ["--stdio"],
3400
+ cwd: root,
3401
+ env
3402
+ }, false);
3403
+ if (projectPyright) {
3404
+ return {
3405
+ process: projectPyright.process,
3406
+ source: projectPyright.source,
3407
+ initialization: pyrightInit(pythonEnvironment?.pythonPath)
3408
+ };
3409
+ }
3410
+ const projectTy = await resolveAndLaunch({
3411
+ candidates: pythonEnvironmentToolCandidates(pythonEnvironment, "ty"),
3412
+ args: ["server"],
3413
+ cwd: root,
3414
+ env
3415
+ }, false);
3416
+ if (projectTy) {
3417
+ return { process: projectTy.process, source: projectTy.source };
3418
+ }
3419
+ const pathPyright = await resolveAndLaunch({
3420
+ candidates: ["pyright-langserver", "basedpyright-langserver"],
3421
+ args: ["--stdio"],
3422
+ cwd: root,
3423
+ env
3424
+ }, false);
3425
+ if (pathPyright) {
3426
+ return {
3427
+ process: pathPyright.process,
3428
+ source: pathPyright.source,
3429
+ initialization: pyrightInit(pythonEnvironment?.pythonPath)
3430
+ };
3431
+ }
3432
+ const pathTy = await resolveAndLaunch({
3433
+ candidates: ["ty"],
3434
+ args: ["server"],
3435
+ cwd: root,
3436
+ env
3437
+ }, false);
3438
+ if (pathTy) {
3439
+ return { process: pathTy.process, source: pathTy.source };
3440
+ }
3441
+ const pyrightPath = await ensureTool("pyright", {
3442
+ allowInstall: canInstall(options?.allowInstall)
3443
+ });
3444
+ if (!pyrightPath)
3445
+ return void 0;
3446
+ source = "managed";
3447
+ const binDir = path7.dirname(pyrightPath);
3448
+ const isWindows2 = process.platform === "win32";
3449
+ const managedCandidates = isWindows2 ? [
3450
+ path7.join(binDir, "pyright-langserver.cmd"),
3451
+ path7.join(binDir, "pyright-langserver"),
3452
+ "pyright-langserver"
3453
+ ] : [path7.join(binDir, "pyright-langserver"), "pyright-langserver"];
3454
+ const resolved = await resolveAndLaunch({ candidates: managedCandidates, args: ["--stdio"], cwd: root, env }, false);
3455
+ if (!resolved)
3456
+ return void 0;
3457
+ return {
3458
+ process: resolved.process,
3459
+ source,
3460
+ initialization: pyrightInit(pythonEnvironment?.pythonPath)
3461
+ };
3462
+ }
3463
+ };
3464
+ var PythonJediServer = {
3465
+ id: "python-jedi",
3466
+ idleEviction: "unmeasured",
3467
+ name: "Jedi Language Server",
3468
+ fallbackFor: "python",
3469
+ extensions: KIND_EXTENSIONS["python"],
3470
+ root: RootWithFallback(createRootDetector([
3471
+ ".git",
3472
+ "pyproject.toml",
3473
+ "setup.py",
3474
+ "setup.cfg",
3475
+ "requirements.txt",
3476
+ "Pipfile",
3477
+ "poetry.lock"
3478
+ ])),
3479
+ async spawn(root, options) {
3480
+ const launched = await resolveAndLaunch({
3481
+ candidates: ["jedi-language-server"],
3482
+ args: [],
3483
+ cwd: root,
3484
+ managedToolId: "jedi-language-server"
3485
+ }, options?.allowInstall);
3486
+ if (!launched)
3487
+ return void 0;
3488
+ const pythonPath = await detectPythonVenv(root);
3489
+ return {
3490
+ ...launched,
3491
+ initialization: pythonPath ? { workspace: { environmentPath: pythonPath } } : {}
3492
+ };
3493
+ }
3494
+ };
3495
+ var GoServer = {
3496
+ id: "go",
3497
+ idleEviction: "unmeasured",
3498
+ name: "gopls",
3499
+ extensions: KIND_EXTENSIONS["go"],
3500
+ root: RootWithFallback(WorkspacePriorityRoot([["go.work"], ["go.mod", "go.sum"], [".git"]])),
3501
+ async spawn(root, options) {
3502
+ const result = await resolveAndLaunch({
3503
+ // Canonical-bin discovery (#241): include $GOPATH/bin so a gopls that
3504
+ // `go install` dropped there resolves even when it isn't on PATH —
3505
+ // which is also the retry target after the runtimeInstall below.
3506
+ candidates: goBinCandidates("gopls"),
3507
+ args: [],
3508
+ cwd: root,
3509
+ runtimeInstall: {
3510
+ runtimeCommand: "go",
3511
+ install: tryGoInstallGopls
3512
+ }
3513
+ }, options?.allowInstall);
3514
+ if (!result)
3515
+ return void 0;
3516
+ return { ...result, initialization: { ui: { semanticTokens: true } } };
3517
+ }
3518
+ };
3519
+ function cargoWorkspaceDeclaresMember(workspaceContent, parentDir, childDir) {
3520
+ const relativePath = path7.relative(parentDir, childDir).split(path7.sep).join("/");
3521
+ if (relativePath === "" || relativePath.startsWith(".."))
3522
+ return false;
3523
+ const matches = (pattern) => matchesWorkspaceMemberPattern(pattern, relativePath, CARGO_WORKSPACE_MEMBER_DIALECT, () => recordDegradationOnce({
3524
+ kind: "workspace-glob-cap",
3525
+ subject: String(pattern.length),
3526
+ reason: "workspace glob matcher exceeded its memo-table cell cap"
3527
+ }));
3528
+ const excluded = readCargoWorkspaceExclude(workspaceContent);
3529
+ if (excluded.some(matches))
3530
+ return false;
3531
+ return readCargoWorkspaceMembers(workspaceContent).some(matches);
3532
+ }
3533
+ function sessionHoistCeiling(sessionCwd, file) {
3534
+ return isSameOrWithin(path7.resolve(sessionCwd), path7.resolve(file)) ? path7.resolve(sessionCwd) : void 0;
3535
+ }
3536
+ function RustWorkspaceRoot() {
3537
+ const crateRoot = createRootDetector(["Cargo.toml", "Cargo.lock"]);
3538
+ return withRootMarkers(async (file) => {
3539
+ const root = await crateRoot(file);
3540
+ if (!root)
3541
+ return void 0;
3542
+ const sessionCwd = process.cwd();
3543
+ const stop = sessionHoistCeiling(sessionCwd, file);
3544
+ let current = root;
3545
+ const fsRoot = path7.parse(current).root;
3546
+ while (true) {
3547
+ if (stop !== void 0 && current === stop)
3548
+ break;
3549
+ const parent = path7.dirname(current);
3550
+ if (parent === current || parent === fsRoot)
3551
+ break;
3552
+ const parentCargoPath = path7.join(parent, "Cargo.toml");
3553
+ const parentCargoContent = await readTextFileOrUndefined(parentCargoPath);
3554
+ if (parentCargoContent !== void 0 && hasCargoWorkspaceTable(parentCargoContent)) {
3555
+ if (cargoWorkspaceDeclaresMember(parentCargoContent, parent, root)) {
3556
+ return enforceLspRootCeiling(parent, sessionCwd, file);
3557
+ }
3558
+ break;
3559
+ }
3560
+ current = parent;
3561
+ }
3562
+ return root;
3563
+ }, crateRoot.rootMarkers ?? []);
3564
+ }
3565
+ function stripXmlComments(content) {
3566
+ let result = content;
3567
+ let previous;
3568
+ do {
3569
+ previous = result;
3570
+ result = result.replace(/<!--[\s\S]*?-->/g, "");
3571
+ } while (result !== previous);
3572
+ return result;
3573
+ }
3574
+ async function declaresMavenModule(parentDir, parentPomPath, childDir) {
3575
+ try {
3576
+ const content = stripXmlComments(await readFile(parentPomPath, "utf-8"));
3577
+ const modulesBlock = content.match(/<modules>([\s\S]*?)<\/modules>/);
3578
+ if (!modulesBlock)
3579
+ return false;
3580
+ const resolvedChild = path7.resolve(childDir);
3581
+ for (const match of modulesBlock[1].matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
3582
+ if (pathsEqual(path7.resolve(parentDir, match[1]), resolvedChild))
3583
+ return true;
3584
+ }
3585
+ return false;
3586
+ } catch {
3587
+ return false;
3588
+ }
3589
+ }
3590
+ function JavaWorkspaceRoot() {
3591
+ const moduleRoot = createRootDetector([
3592
+ "pom.xml",
3593
+ "build.gradle",
3594
+ ".classpath"
3595
+ ]);
3596
+ return withRootMarkers(async (file) => {
3597
+ const root = await moduleRoot(file);
3598
+ if (!root)
3599
+ return void 0;
3600
+ if (!await markerExists(root, "pom.xml"))
3601
+ return root;
3602
+ const sessionCwd = process.cwd();
3603
+ const stop = sessionHoistCeiling(sessionCwd, file);
3604
+ let current = root;
3605
+ let lastHop = root;
3606
+ const fsRoot = path7.parse(current).root;
3607
+ while (true) {
3608
+ if (stop !== void 0 && current === stop)
3609
+ break;
3610
+ const parent = path7.dirname(current);
3611
+ if (parent === current || parent === fsRoot)
3612
+ break;
3613
+ if (await markerExists(parent, "pom.xml")) {
3614
+ const parentPom = path7.join(parent, "pom.xml");
3615
+ if (!await declaresMavenModule(parent, parentPom, lastHop))
3616
+ break;
3617
+ current = parent;
3618
+ lastHop = parent;
3619
+ continue;
3620
+ }
3621
+ current = parent;
3622
+ }
3623
+ return enforceLspRootCeiling(lastHop, sessionCwd, file);
3624
+ }, moduleRoot.rootMarkers ?? []);
3625
+ }
3626
+ var RustServer = {
3627
+ id: "rust",
3628
+ idleEviction: "unmeasured",
3629
+ // Measured (#3750): rust-analyzer answers an empty result for a detached file.
3630
+ requiresProjectRoot: true,
3631
+ name: "rust-analyzer",
3632
+ extensions: KIND_EXTENSIONS["rust"],
3633
+ // No FileDirRoot fallback (#201): rust-analyzer is a heavy workspace server
3634
+ // that is useless without a Cargo manifest. With the fallback, every .rs file
3635
+ // written before a Cargo.toml exists resolved to its OWN directory as the
3636
+ // root, and since clients dedup by `${serverId}:${root}`, each directory
3637
+ // spawned a separate rust-analyzer (one per file/dir during scaffolding).
3638
+ // Returning undefined here skips the spawn until a Cargo.toml gives a stable,
3639
+ // shared crate root — then all files share one server.
3640
+ root: RustWorkspaceRoot(),
3641
+ async spawn(root, options) {
3642
+ const result = await resolveAndLaunch({
3643
+ candidates: cargoBinCandidates("rust-analyzer"),
3644
+ args: [],
3645
+ cwd: root,
3646
+ managedToolId: "rust-analyzer"
3647
+ }, options?.allowInstall);
3648
+ if (!result)
3649
+ return void 0;
3650
+ return {
3651
+ ...result,
3652
+ initialization: {
3653
+ cargo: { buildScripts: { enable: true } },
3654
+ procMacro: { enable: true },
3655
+ diagnostics: { enable: true }
3656
+ }
3657
+ };
3658
+ }
3659
+ };
3660
+ var RubyServer = {
3661
+ id: "ruby",
3662
+ idleEviction: "unmeasured",
3663
+ name: "Ruby LSP",
3664
+ extensions: KIND_EXTENSIONS["ruby"],
3665
+ root: RootWithFallback(PriorityRoot([["Gemfile", ".ruby-version"], [".git"]])),
3666
+ // Ruby LSP may need extra time to finish composed-bundle setup before it can
3667
+ // answer initialize/documentSymbol on cold start.
3668
+ initializeTimeoutMs: 3e4,
3669
+ clientWaitTimeoutMs: 3e4,
3670
+ async spawn(root, options) {
3671
+ const rubylsp = await resolveAndLaunch({
3672
+ candidates: ["ruby-lsp", ...rubyBinCandidates("ruby-lsp")],
3673
+ args: [],
3674
+ cwd: root,
3675
+ runtimeInstall: {
3676
+ runtimeCommand: "gem",
3677
+ install: () => tryGemInstall("ruby-lsp"),
3678
+ retryCandidates: ["ruby-lsp", ...rubyBinCandidates("ruby-lsp")]
3679
+ }
3680
+ }, options?.allowInstall);
3681
+ if (rubylsp)
3682
+ return rubylsp;
3683
+ const solargraph = await resolveAndLaunch({
3684
+ candidates: ["solargraph", ...rubyBinCandidates("solargraph")],
3685
+ args: ["stdio"],
3686
+ cwd: root
3687
+ }, false);
3688
+ if (solargraph)
3689
+ return solargraph;
3690
+ return resolveAndLaunch({
3691
+ candidates: ["rubocop", ...rubyBinCandidates("rubocop")],
3692
+ args: ["--lsp"],
3693
+ cwd: root
3694
+ }, false);
3695
+ }
3696
+ };
3697
+ var PHPServer = {
3698
+ id: "php",
3699
+ idleEviction: "transparent",
3700
+ name: "Intelephense",
3701
+ extensions: KIND_EXTENSIONS["php"],
3702
+ root: RootWithFallback(createRootDetector(["composer.json", "composer.lock"])),
3703
+ async spawn(root, options) {
3704
+ const result = await resolveAndLaunch({
3705
+ candidates: nodeBinCandidates(root, "intelephense"),
3706
+ args: ["--stdio"],
3707
+ cwd: root,
3708
+ managedToolId: "intelephense"
3709
+ }, options?.allowInstall);
3710
+ if (!result)
3711
+ return void 0;
3712
+ return {
3713
+ ...result,
3714
+ initialization: {
3715
+ storagePath: path7.join(getGlobalPiLensDir(), "intelephense")
3716
+ }
3717
+ };
3718
+ }
3719
+ };
3720
+ function buildPsesArgs(bundleDir) {
3721
+ const script = path7.join(bundleDir, "PowerShellEditorServices", "Start-EditorServices.ps1");
3722
+ const sessionDir = path7.join(getGlobalPiLensDir(), "pses", `${process.pid}-${Date.now()}`);
3723
+ mkdirSync2(sessionDir, { recursive: true });
3724
+ const logPath = path7.join(sessionDir, "pses.log");
3725
+ const sessionDetailsPath = path7.join(sessionDir, "session.json");
3726
+ return [
3727
+ "-NoLogo",
3728
+ "-NoProfile",
3729
+ "-NonInteractive",
3730
+ // Unsigned bundled script + mark-of-the-web on Windows — Bypass so it runs;
3731
+ // ignored by non-Windows pwsh.
3732
+ "-ExecutionPolicy",
3733
+ "Bypass",
3734
+ "-File",
3735
+ script,
3736
+ "-HostName",
3737
+ "pi-lens",
3738
+ "-HostProfileId",
3739
+ "pi-lens",
3740
+ "-HostVersion",
3741
+ "1.0.0",
3742
+ "-BundledModulesPath",
3743
+ bundleDir,
3744
+ "-LogPath",
3745
+ logPath,
3746
+ "-LogLevel",
3747
+ "Warning",
3748
+ "-SessionDetailsPath",
3749
+ sessionDetailsPath,
3750
+ "-Stdio",
3751
+ "-LanguageServiceOnly"
3752
+ ];
3753
+ }
3754
+ var PowerShellServer = {
3755
+ id: "powershell",
3756
+ idleEviction: "unmeasured",
3757
+ name: "PowerShell Editor Services",
3758
+ extensions: KIND_EXTENSIONS["powershell"],
3759
+ // Index at the workspace (script modules reference siblings); fall back to the
3760
+ // file dir.
3761
+ root: RootWithFallback(createRootDetector([".git"])),
3762
+ spawn(root, options) {
3763
+ return resolveAndLaunchBundle({
3764
+ runtimeCandidates: ["pwsh", "powershell"],
3765
+ bundleToolId: "powershell-editor-services",
3766
+ cwd: root,
3767
+ args: buildPsesArgs
3768
+ }, options?.allowInstall);
3769
+ }
3770
+ };
3771
+ var CSharpServer = {
3772
+ id: "csharp",
3773
+ idleEviction: "unmeasured",
3774
+ // Documented (#3750): csharp-ls needs a solution or project.
3775
+ requiresProjectRoot: true,
3776
+ name: "csharp-ls",
3777
+ extensions: KIND_EXTENSIONS["csharp"],
3778
+ // No FileDirRoot fallback (#201): csharp-ls is a workspace server and should
3779
+ // not spawn once per source directory before a .sln/.csproj exists. Glob root
3780
+ // markers match real project filenames such as `App.csproj` / `App.sln`
3781
+ // (shared marker list — see file-kinds.ts, refs #895).
3782
+ root: createRootDetector([...DOTNET_CSHARP_ROOT_MARKERS]),
3783
+ async spawn(root, options) {
3784
+ const candidates = dotnetToolCandidates("csharp-ls");
3785
+ return resolveAndLaunch({
3786
+ candidates,
3787
+ args: [],
3788
+ cwd: root,
3789
+ runtimeInstall: {
3790
+ runtimeCommand: "dotnet",
3791
+ install: () => tryDotnetToolInstall("csharp-ls"),
3792
+ retryCandidates: candidates
3793
+ }
3794
+ }, options?.allowInstall);
3795
+ }
3796
+ };
3797
+ var OmniSharpServer = createInteractiveServer({
3798
+ id: "omnisharp",
3799
+ name: "OmniSharp",
3800
+ // Documented (#3750): OmniSharp needs a solution or project.
3801
+ requiresProjectRoot: true,
3802
+ fallbackFor: "csharp",
3803
+ extensions: KIND_EXTENSIONS["csharp"],
3804
+ root: createRootDetector([...DOTNET_CSHARP_ROOT_MARKERS]),
3805
+ language: "csharp",
3806
+ command: "OmniSharp",
3807
+ args: ["--languageserver"]
3808
+ });
3809
+ var FSharpServer = {
3810
+ id: "fsharp",
3811
+ idleEviction: "unmeasured",
3812
+ // Documented (#3750): FSAutocomplete needs a project.
3813
+ requiresProjectRoot: true,
3814
+ name: "FSAutocomplete",
3815
+ extensions: KIND_EXTENSIONS["fsharp"],
3816
+ root: createRootDetector([...DOTNET_FSHARP_ROOT_MARKERS]),
3817
+ async spawn(root, options) {
3818
+ const candidates = dotnetToolCandidates("fsautocomplete");
3819
+ return resolveAndLaunch({
3820
+ candidates,
3821
+ args: [],
3822
+ cwd: root,
3823
+ runtimeInstall: {
3824
+ runtimeCommand: "dotnet",
3825
+ install: () => tryDotnetToolInstall("fsautocomplete"),
3826
+ retryCandidates: candidates
3827
+ }
3828
+ }, options?.allowInstall);
3829
+ }
3830
+ };
3831
+ var JavaServer = createInteractiveServer({
3832
+ id: "java",
3833
+ name: "JDT Language Server",
3834
+ extensions: KIND_EXTENSIONS["java"],
3835
+ root: RootWithFallback(JavaWorkspaceRoot()),
3836
+ language: "java",
3837
+ command: () => process.env.JDTLS_PATH || "jdtls",
3838
+ args: (root) => createLombokJdtlsArgs(root),
3839
+ runtime: "java"
3840
+ });
3841
+ var KotlinServer = {
3842
+ id: "kotlin",
3843
+ idleEviction: "unmeasured",
3844
+ name: "Kotlin Language Server",
3845
+ extensions: KIND_EXTENSIONS["kotlin"],
3846
+ root: RootWithFallback(createRootDetector(["build.gradle.kts", "build.gradle", "pom.xml"])),
3847
+ async spawn(root, options) {
3848
+ return resolveAndLaunch({
3849
+ candidates: ["kotlin-lsp", "kotlin-language-server"],
3850
+ args: [],
3851
+ cwd: root,
3852
+ // #3400: a managed fwcd install when no PATH candidate launches. The
3853
+ // managed shim is consulted FIRST, but only exists once no PATH
3854
+ // candidate answered, so a PATH `kotlin-lsp` wins on a box that had
3855
+ // it before the managed install; one added afterwards does not.
3856
+ managedToolId: "kotlin-language-server"
3857
+ }, options?.allowInstall);
3858
+ }
3859
+ };
3860
+ var SwiftServer = createInteractiveServer({
3861
+ id: "swift",
3862
+ name: "SourceKit-LSP",
3863
+ extensions: KIND_EXTENSIONS["swift"],
3864
+ root: createRootDetector(["Package.swift"]),
3865
+ language: "swift",
3866
+ command: "sourcekit-lsp"
3867
+ });
3868
+ var DartServer = createInteractiveServer({
3869
+ id: "dart",
3870
+ name: "Dart Analysis Server",
3871
+ extensions: KIND_EXTENSIONS["dart"],
3872
+ root: RootWithFallback(createRootDetector(["pubspec.yaml"])),
3873
+ language: "dart",
3874
+ command: "dart",
3875
+ args: ["language-server", "--protocol=lsp"]
3876
+ });
3877
+ function createTreeBinaryServer(spec) {
3878
+ return {
3879
+ id: spec.id,
3880
+ name: spec.name,
3881
+ extensions: spec.extensions,
3882
+ idleEviction: spec.idleEviction ?? "unmeasured",
3883
+ root: spec.root,
3884
+ spawn(root, options) {
3885
+ return resolveAndLaunchTreeBinary({
3886
+ candidates: [spec.binaryName],
3887
+ bundleToolId: spec.binaryName,
3888
+ binRelPath: spec.binRelPath,
3889
+ cwd: root,
3890
+ args: spec.args ?? []
3891
+ }, options?.allowInstall);
3892
+ }
3893
+ };
3894
+ }
3895
+ var LuaServer = createTreeBinaryServer({
3896
+ id: "lua",
3897
+ name: "Lua Language Server",
3898
+ extensions: KIND_EXTENSIONS["lua"],
3899
+ root: createRootDetector([".luarc.json", ".luacheckrc"]),
3900
+ binaryName: "lua-language-server",
3901
+ binRelPath: "bin/lua-language-server"
3902
+ });
3903
+ var CppServer = createTreeBinaryServer({
3904
+ id: "cpp",
3905
+ idleEviction: "transparent",
3906
+ name: "clangd",
3907
+ extensions: KIND_EXTENSIONS["cxx"],
3908
+ root: RootWithFallback(createRootDetector([
3909
+ "compile_commands.json",
3910
+ ".clangd",
3911
+ "CMakeLists.txt",
3912
+ "Makefile"
3913
+ ])),
3914
+ binaryName: "clangd",
3915
+ binRelPath: "bin/clangd",
3916
+ args: ["--background-index"]
3917
+ });
3918
+ var ZigServer = {
3919
+ id: "zig",
3920
+ idleEviction: "unmeasured",
3921
+ name: "ZLS",
3922
+ extensions: KIND_EXTENSIONS["zig"],
3923
+ root: RootWithFallback(createRootDetector(["build.zig"])),
3924
+ spawn(root, options) {
3925
+ return resolveAndLaunch({
3926
+ candidates: ["zls"],
3927
+ args: [],
3928
+ cwd: root,
3929
+ managedToolId: "zls"
3930
+ }, options?.allowInstall);
3931
+ }
3932
+ };
3933
+ var HaskellServer = createInteractiveServer({
3934
+ id: "haskell",
3935
+ name: "Haskell Language Server",
3936
+ extensions: KIND_EXTENSIONS["haskell"],
3937
+ root: createRootDetector(["stack.yaml", "cabal.project", "*.cabal"]),
3938
+ language: "haskell",
3939
+ command: "haskell-language-server-wrapper",
3940
+ args: ["--lsp"]
3941
+ });
3942
+ var ElixirServer = createInteractiveServer({
3943
+ id: "elixir",
3944
+ name: "ElixirLS",
3945
+ extensions: KIND_EXTENSIONS["elixir"],
3946
+ root: RootWithFallback(createRootDetector(["mix.exs"])),
3947
+ language: "elixir",
3948
+ command: "elixir-ls"
3949
+ });
3950
+ var ElixirExpertServer = {
3951
+ id: "expert",
3952
+ idleEviction: "unmeasured",
3953
+ name: "Expert",
3954
+ fallbackFor: "elixir",
3955
+ extensions: KIND_EXTENSIONS["elixir"],
3956
+ root: RootWithFallback(createRootDetector(["mix.exs"])),
3957
+ availabilityKey: "expert",
3958
+ async spawn(root, options) {
3959
+ return resolveAndLaunch({
3960
+ candidates: ["expert"],
3961
+ args: ["--stdio"],
3962
+ cwd: root,
3963
+ managedToolId: "expert"
3964
+ }, options?.allowInstall);
3965
+ },
3966
+ autoInstall: async () => Boolean(await ensureTool("expert"))
3967
+ };
3968
+ var GleamServer = {
3969
+ id: "gleam",
3970
+ idleEviction: "unmeasured",
3971
+ name: "Gleam LSP",
3972
+ extensions: KIND_EXTENSIONS["gleam"],
3973
+ root: RootWithFallback(createRootDetector(["gleam.toml"])),
3974
+ async spawn(root, options) {
3975
+ return resolveAndLaunch({
3976
+ candidates: ["gleam"],
3977
+ args: ["lsp"],
3978
+ cwd: root,
3979
+ managedToolId: "gleam"
3980
+ }, options?.allowInstall);
3981
+ }
3982
+ };
3983
+ var TinymistServer = {
3984
+ id: "tinymist",
3985
+ idleEviction: "unmeasured",
3986
+ name: "Tinymist",
3987
+ extensions: extensionsForLanguage("typst"),
3988
+ root: RootWithFallback(createRootDetector(["typst.toml", ".git"])),
3989
+ availabilityKey: "tinymist",
3990
+ async spawn(root, options) {
3991
+ return resolveAndLaunch({
3992
+ candidates: ["tinymist"],
3993
+ args: ["lsp"],
3994
+ cwd: root,
3995
+ managedToolId: "tinymist"
3996
+ }, options?.allowInstall);
3997
+ }
3998
+ };
3999
+ var MarksmanServer = {
4000
+ id: "marksman",
4001
+ idleEviction: "transparent",
4002
+ name: "Marksman",
4003
+ extensions: KIND_EXTENSIONS["markdown"],
4004
+ // Index at the workspace root so cross-file checks (broken intra-repo links,
4005
+ // missing/renamed anchors, heading refs) see the whole tree; fall back to the
4006
+ // file's directory when there's no project marker.
4007
+ root: RootWithFallback(createRootDetector([".marksman.toml", ".git"])),
4008
+ spawn(root, options) {
4009
+ return resolveAndLaunch({
4010
+ candidates: ["marksman"],
4011
+ args: ["server"],
4012
+ cwd: root,
4013
+ managedToolId: "marksman"
4014
+ }, options?.allowInstall);
4015
+ }
4016
+ };
4017
+ var OCamlServer = createInteractiveServer({
4018
+ id: "ocaml",
4019
+ name: "ocamllsp",
4020
+ extensions: KIND_EXTENSIONS["ocaml"],
4021
+ root: createRootDetector(["dune-project", "opam"]),
4022
+ language: "ocaml",
4023
+ command: "ocamllsp"
4024
+ });
4025
+ var ClojureServer = {
4026
+ id: "clojure",
4027
+ idleEviction: "transparent",
4028
+ name: "Clojure LSP",
4029
+ extensions: KIND_EXTENSIONS["clojure"],
4030
+ root: createRootDetector(["deps.edn", "project.clj"]),
4031
+ async spawn(root, options) {
4032
+ return resolveAndLaunch({
4033
+ candidates: ["clojure-lsp"],
4034
+ args: [],
4035
+ cwd: root,
4036
+ managedToolId: "clojure-lsp"
4037
+ }, options?.allowInstall);
4038
+ }
4039
+ };
4040
+ var CueServer = {
4041
+ id: "cue",
4042
+ idleEviction: "unmeasured",
4043
+ name: "CUE Language Server",
4044
+ extensions: KIND_EXTENSIONS["cue"],
4045
+ root: RootWithFallback(createRootDetector(["cue.mod", ".git"])),
4046
+ async spawn(root, options) {
4047
+ return resolveAndLaunch({
4048
+ candidates: ["cue"],
4049
+ args: ["lsp", "serve"],
4050
+ cwd: root,
4051
+ managedToolId: "cue"
4052
+ }, options?.allowInstall);
4053
+ }
4054
+ };
4055
+ var TerraformServer = {
4056
+ id: "terraform",
4057
+ idleEviction: "unmeasured",
4058
+ name: "Terraform LSP",
4059
+ extensions: KIND_EXTENSIONS["terraform"],
4060
+ root: RootWithFallback(createRootDetector([".terraform.lock.hcl", ".terraform"])),
4061
+ spawn(root, options) {
4062
+ return resolveAndLaunch({
4063
+ candidates: ["terraform-ls"],
4064
+ args: ["serve"],
4065
+ cwd: root,
4066
+ managedToolId: "terraform-ls"
4067
+ }, options?.allowInstall);
4068
+ }
4069
+ };
4070
+ var NixServer = createInteractiveServer({
4071
+ id: "nix",
4072
+ name: "nixd",
4073
+ extensions: KIND_EXTENSIONS["nix"],
4074
+ root: createRootDetector(["flake.nix"]),
4075
+ language: "nix",
4076
+ command: "nixd"
4077
+ });
4078
+ var BashServer = {
4079
+ id: "bash",
4080
+ idleEviction: "transparent",
4081
+ name: "Bash Language Server",
4082
+ // #3968: narrowed from [".bash", ".sh", ".zsh"] — bash-language-server does
4083
+ // not support zsh (its own analyzer refuses the dialect), and its ≥5.7.0
4084
+ // lint flow even feeds shebang'd zsh to its embedded shellcheck, importing
4085
+ // SC1071-class noise through the LSP lane. `shuck` owns `.zsh` when
4086
+ // installed; when it is not, the shellcheck runner's dialect gate keeps
4087
+ // zsh quiet instead of falling back to a zsh-illiterate analyzer.
4088
+ extensions: [".bash", ".sh"],
4089
+ root: FileDirRoot,
4090
+ // #2194 bounded the installer's own verification at 20s; the dispatch
4091
+ // touch's client-wait floor stayed at the shared 5s default, so a cold
4092
+ // spawn could still race that budget and read as unavailable even after
4093
+ // installer verification cleared it. Match the installer bound (#2169).
4094
+ // `initializeTimeoutMs` matches it too: the measured cold start
4095
+ // (9,667ms, #2194) has headroom under the unraised 15s default, but
4096
+ // leaving the two fields mismatched is the same latent shape that made
4097
+ // the Prisma/Vue raise a no-op (fix-round F1, #2233) — a slower host
4098
+ // than the one measured would still hit the 15s inner kill despite the
4099
+ // caller being willing to wait 20s. Equalizing costs nothing on the
4100
+ // success path and removes the mismatch outright.
4101
+ clientWaitTimeoutMs: 2e4,
4102
+ initializeTimeoutMs: 2e4,
4103
+ spawn(root, options) {
4104
+ return resolveAndLaunch({
4105
+ candidates: nodeBinCandidates(root, "bash-language-server"),
4106
+ args: ["start"],
4107
+ cwd: root,
4108
+ managedToolId: "bash-language-server"
4109
+ }, options?.allowInstall);
4110
+ }
4111
+ };
4112
+ var ShuckServer = createInteractiveServer({
4113
+ id: "shuck",
4114
+ name: "Shuck",
4115
+ extensions: [".zsh"],
4116
+ root: FileDirRoot,
4117
+ language: "shell",
4118
+ command: "shuck",
4119
+ args: ["server"]
4120
+ });
4121
+ var FishServer = {
4122
+ id: "fish",
4123
+ idleEviction: "transparent",
4124
+ name: "Fish Language Server",
4125
+ extensions: KIND_EXTENSIONS["fish"],
4126
+ root: RootWithFallback(createRootDetector([".git"])),
4127
+ spawn(root, options) {
4128
+ return resolveAndLaunch({
4129
+ candidates: nodeBinCandidates(root, "fish-lsp"),
4130
+ args: ["start", "--stdio"],
4131
+ cwd: root,
4132
+ managedToolId: "fish-lsp"
4133
+ }, options?.allowInstall);
4134
+ }
4135
+ };
4136
+ var CMakeServer = {
4137
+ id: "cmake",
4138
+ idleEviction: "unmeasured",
4139
+ name: "CMake Language Server",
4140
+ // CMake's canonical project file has no .cmake suffix. The configured-server
4141
+ // matcher supports exact basenames as well as extensions.
4142
+ extensions: [...KIND_EXTENSIONS["cmake"], "CMakeLists.txt"],
4143
+ root: RootWithFallback(createRootDetector(["CMakeLists.txt", ".git"])),
4144
+ spawn(root, options) {
4145
+ return resolveAndLaunch({
4146
+ candidates: ["cmake-language-server"],
4147
+ args: [],
4148
+ cwd: root,
4149
+ managedToolId: "cmake-language-server"
4150
+ }, options?.allowInstall);
4151
+ }
4152
+ };
4153
+ var DockerServer = {
4154
+ id: "docker",
4155
+ idleEviction: "unmeasured",
4156
+ name: "Dockerfile Language Server",
4157
+ extensions: [".dockerfile", "Dockerfile"],
4158
+ root: RootWithFallback(PriorityRoot([
4159
+ [
4160
+ "docker-compose.yml",
4161
+ "docker-compose.yaml",
4162
+ "compose.yml",
4163
+ "compose.yaml"
4164
+ ],
4165
+ [".git"]
4166
+ ])),
4167
+ spawn(root, options) {
4168
+ return resolveAndLaunch({
4169
+ candidates: nodeBinCandidates(root, "docker-langserver"),
4170
+ args: ["--stdio"],
4171
+ cwd: root,
4172
+ managedToolId: "dockerfile-language-server-nodejs"
4173
+ }, options?.allowInstall);
4174
+ }
4175
+ };
4176
+ var DockerOfficialServer = {
4177
+ id: "docker-official",
4178
+ idleEviction: "unmeasured",
4179
+ name: "Docker Language Server (official)",
4180
+ fallbackFor: "docker",
4181
+ extensions: [".dockerfile", "Dockerfile"],
4182
+ root: RootWithFallback(PriorityRoot([
4183
+ [
4184
+ "docker-compose.yml",
4185
+ "docker-compose.yaml",
4186
+ "compose.yml",
4187
+ "compose.yaml"
4188
+ ],
4189
+ [".git"]
4190
+ ])),
4191
+ spawn(root, options) {
4192
+ return resolveAndLaunch({
4193
+ candidates: nodeBinCandidates(root, "docker-language-server"),
4194
+ args: ["start", "--stdio"],
4195
+ cwd: root
4196
+ }, options?.allowInstall);
4197
+ }
4198
+ };
4199
+ var YamlServer = {
4200
+ id: "yaml",
4201
+ idleEviction: "transparent",
4202
+ name: "YAML Language Server",
4203
+ extensions: KIND_EXTENSIONS["yaml"],
4204
+ root: RootWithFallback(PriorityRoot([
4205
+ [".yamllint", "yamllint.yml", "yamllint.yaml", "pyproject.toml"],
4206
+ [".git"]
4207
+ ])),
4208
+ spawn(root, options) {
4209
+ return resolveAndLaunch({
4210
+ candidates: nodeBinCandidates(root, "yaml-language-server"),
4211
+ args: ["--stdio"],
4212
+ cwd: root,
4213
+ managedToolId: "yaml-language-server"
4214
+ }, options?.allowInstall);
4215
+ }
4216
+ };
4217
+ var JsonServer = {
4218
+ id: "json",
4219
+ idleEviction: "unmeasured",
4220
+ name: "VSCode JSON Language Server",
4221
+ extensions: KIND_EXTENSIONS["json"],
4222
+ root: RootWithFallback(WorkspacePriorityRoot([
4223
+ ["package.json", "tsconfig.json", "jsconfig.json"],
4224
+ [".git"]
4225
+ ])),
4226
+ // See BashServer above: the installer's 20s verification bound (#2194)
4227
+ // does not, on its own, raise the dispatch touch's cold-spawn wait floor.
4228
+ // Mirror it here so a cold spawn cannot lose that race either (#2169).
4229
+ // `initializeTimeoutMs` matches it for the same reason as BashServer
4230
+ // above (fix-round F1, #2233).
4231
+ clientWaitTimeoutMs: 2e4,
4232
+ initializeTimeoutMs: 2e4,
4233
+ spawn(root, options) {
4234
+ return resolveAndLaunch({
4235
+ candidates: ["vscode-json-language-server"],
4236
+ args: ["--stdio"],
4237
+ cwd: root,
4238
+ managedToolId: "vscode-json-language-server"
4239
+ }, options?.allowInstall);
4240
+ }
4241
+ };
4242
+ var HtmlServer = {
4243
+ id: "html",
4244
+ idleEviction: "transparent",
4245
+ name: "VSCode HTML Language Server",
4246
+ extensions: KIND_EXTENSIONS["html"],
4247
+ root: RootWithFallback(IgnoreHomeRoot(PriorityRoot([["package.json", "index.html", "vite.config.ts"]]))),
4248
+ spawn(root, options) {
4249
+ return resolveAndLaunch({
4250
+ candidates: nodeBinCandidates(root, "vscode-html-language-server"),
4251
+ args: ["--stdio"],
4252
+ cwd: root,
4253
+ managedToolId: "vscode-html-languageserver-bin"
4254
+ }, options?.allowInstall);
4255
+ }
4256
+ };
4257
+ var TomlServer = {
4258
+ id: "toml",
4259
+ idleEviction: "unmeasured",
4260
+ name: "Taplo",
4261
+ extensions: KIND_EXTENSIONS["toml"],
4262
+ root: RootWithFallback(PriorityRoot([["pyproject.toml", "Cargo.toml", "taplo.toml"], [".git"]])),
4263
+ spawn(root, options) {
4264
+ return resolveAndLaunch({
4265
+ candidates: ["taplo"],
4266
+ args: ["lsp", "stdio"],
4267
+ cwd: root,
4268
+ managedToolId: "taplo"
4269
+ }, options?.allowInstall);
4270
+ }
4271
+ };
4272
+ var PrismaServer = {
4273
+ id: "prisma",
4274
+ idleEviction: "transparent",
4275
+ name: "Prisma Language Server",
4276
+ extensions: KIND_EXTENSIONS["prisma"],
4277
+ root: RootWithFallback(createRootDetector(["prisma/schema.prisma", "schema.prisma"])),
4278
+ // Matches the installer's 40s verification bound above (#2169): the
4279
+ // dispatch touch's cold-spawn wait floor defaults to 5s and would
4280
+ // otherwise time the client out well before the binary answers.
4281
+ // `initializeTimeoutMs` MUST be set alongside it (RubyServer's own
4282
+ // precedent below): unset, it falls back to the 15s
4283
+ // `INITIALIZE_TIMEOUT_MS` default in `clients/lsp/client.ts`, which
4284
+ // hard-kills the child mid-handshake — a real cold Prisma run measured
4285
+ // up to 27.3s, so the spawn would die there before this wait ever gets
4286
+ // a chance to matter (fix-round F1, #2233).
4287
+ clientWaitTimeoutMs: 4e4,
4288
+ initializeTimeoutMs: 4e4,
4289
+ spawn(root, options) {
4290
+ return resolveAndLaunch({
4291
+ candidates: nodeBinCandidates(root, "prisma-language-server"),
4292
+ args: ["--stdio"],
4293
+ cwd: root,
4294
+ managedToolId: "@prisma/language-server"
4295
+ }, options?.allowInstall);
4296
+ }
4297
+ };
4298
+ var VueServer = {
4299
+ id: "vue",
4300
+ idleEviction: "unmeasured",
4301
+ name: "Vue Language Server",
4302
+ extensions: [".vue"],
4303
+ root: RootWithFallback(IgnoreHomeRoot(createRootDetector([
4304
+ "package.json",
4305
+ "package-lock.json",
4306
+ "bun.lockb",
4307
+ "bun.lock",
4308
+ "pnpm-lock.yaml",
4309
+ "yarn.lock"
4310
+ ]))),
4311
+ // Vue's launcher loads the full language-service bundle before answering,
4312
+ // matching the installer's 30s verification bound (#2176). The dispatch
4313
+ // touch's cold-spawn wait floor defaults to 5s and needs the same raise so
4314
+ // a cold spawn cannot time out there instead. `initializeTimeoutMs` MUST
4315
+ // match: unset, it falls back to the 15s default in `clients/lsp/client.ts`
4316
+ // and hard-kills a cold spawn (measured up to 22.6s in #2188, 16.2s here)
4317
+ // mid-handshake before this wait can matter (fix-round F1, #2233).
4318
+ clientWaitTimeoutMs: 3e4,
4319
+ initializeTimeoutMs: 3e4,
4320
+ async spawn(root, options) {
4321
+ const tsserverPath = await findTsserverPath(root, options?.allowInstall);
4322
+ const hasPackageJson = existsSync3(path7.join(root, "package.json"));
4323
+ const hasNodeModules = existsSync3(path7.join(root, "node_modules"));
4324
+ if (hasPackageJson && !hasNodeModules) {
4325
+ logSessionStart(`lsp vue: node_modules missing in ${root} \u2014 Vue navigation may be limited. Run: npm install (or pnpm/yarn install) in this project.`);
4326
+ }
4327
+ const proc = await resolveAndLaunch({
4328
+ candidates: nodeBinCandidates(root, "vue-language-server"),
4329
+ args: ["--stdio"],
4330
+ cwd: root,
4331
+ managedToolId: "@vue/language-server"
4332
+ }, options?.allowInstall);
4333
+ if (!proc)
4334
+ return void 0;
4335
+ return {
4336
+ process: proc.process,
4337
+ source: proc.source,
4338
+ initialization: tsserverPath ? { typescript: { tsdk: path7.dirname(tsserverPath) } } : void 0
4339
+ };
4340
+ }
4341
+ };
4342
+ var SvelteServer = {
4343
+ id: "svelte",
4344
+ idleEviction: "unmeasured",
4345
+ name: "Svelte Language Server",
4346
+ extensions: [".svelte"],
4347
+ root: RootWithFallback(IgnoreHomeRoot(createRootDetector([
4348
+ "package.json",
4349
+ "package-lock.json",
4350
+ "bun.lockb",
4351
+ "bun.lock",
4352
+ "pnpm-lock.yaml",
4353
+ "yarn.lock"
4354
+ ]))),
4355
+ // Matches the installer's 20s verification bound above (#2169): the
4356
+ // dispatch touch's cold-spawn wait floor defaults to 5s and would
4357
+ // otherwise time the client out well before the binary answers.
4358
+ // `initializeTimeoutMs` matches it for the same reason as BashServer
4359
+ // above (fix-round F1, #2233).
4360
+ clientWaitTimeoutMs: 2e4,
4361
+ initializeTimeoutMs: 2e4,
4362
+ async spawn(root, options) {
4363
+ const tsserverPath = await findTsserverPath(root, options?.allowInstall);
4364
+ const proc = await resolveAndLaunch({
4365
+ candidates: [
4366
+ ...nodeBinCandidates(root, "svelteserver"),
4367
+ ...nodeBinCandidates(root, "svelte-language-server")
4368
+ ],
4369
+ args: ["--stdio"],
4370
+ cwd: root,
4371
+ managedToolId: "svelte-language-server"
4372
+ }, options?.allowInstall);
4373
+ if (!proc)
4374
+ return void 0;
4375
+ return {
4376
+ process: proc.process,
4377
+ source: proc.source,
4378
+ initialization: tsserverPath ? { typescript: { tsdk: path7.dirname(tsserverPath) } } : void 0
4379
+ };
4380
+ }
4381
+ };
4382
+ var CssServer = {
4383
+ id: "css",
4384
+ idleEviction: "transparent",
4385
+ name: "CSS Language Server",
4386
+ extensions: KIND_EXTENSIONS["css"],
4387
+ root: RootWithFallback(IgnoreHomeRoot(PriorityRoot([
4388
+ [
4389
+ "package.json",
4390
+ "postcss.config.js",
4391
+ "tailwind.config.js",
4392
+ "vite.config.ts"
4393
+ ]
4394
+ ]))),
4395
+ spawn(root, options) {
4396
+ return resolveAndLaunch({
4397
+ candidates: nodeBinCandidates(root, "vscode-css-language-server"),
4398
+ args: ["--stdio"],
4399
+ cwd: root,
4400
+ managedToolId: "vscode-css-languageserver"
4401
+ }, options?.allowInstall);
4402
+ }
4403
+ };
4404
+ var OPENGREP_KINDS = [
4405
+ "csharp",
4406
+ "css",
4407
+ "cxx",
4408
+ "dart",
4409
+ "docker",
4410
+ "go",
4411
+ "html",
4412
+ "java",
4413
+ "json",
4414
+ "jsts",
4415
+ "kotlin",
4416
+ "lua",
4417
+ "php",
4418
+ "python",
4419
+ "ruby",
4420
+ "rust",
4421
+ "shell",
4422
+ "swift",
4423
+ "terraform",
4424
+ "yaml"
4425
+ ];
4426
+ var OPENGREP_EXTENSIONS = Array.from(new Set(OPENGREP_KINDS.flatMap((k) => KIND_EXTENSIONS[k] ?? [])));
4427
+ function opengrepInitialization(root) {
4428
+ const resolved = resolveOpengrepConfig(root, { enabled: true });
4429
+ return {
4430
+ scan: {
4431
+ configuration: [resolved.configArg ?? "auto"],
4432
+ onlyGitDirty: false,
4433
+ jobs: 16
4434
+ },
4435
+ metrics: { enabled: false },
4436
+ doHover: false
4437
+ };
4438
+ }
4439
+ var OpengrepServer = {
4440
+ id: "opengrep",
4441
+ idleEviction: "transparent",
4442
+ name: "Opengrep Security Scanner",
4443
+ role: "auxiliary",
4444
+ extensions: OPENGREP_EXTENSIONS,
4445
+ // Stable per-repo root so ONE warm server serves the whole project (a
4446
+ // per-directory root would spawn a fresh server — and re-pay rule load —
4447
+ // for every folder).
4448
+ root: RootWithFallback(NearestRoot([".git"]), async () => process.cwd()),
4449
+ availabilityKey: "opengrep",
4450
+ // Rule compilation can take a few seconds on the first scan of a session.
4451
+ initializeTimeoutMs: 15e3,
4452
+ async spawn(root, options) {
4453
+ const launched = await resolveAndLaunch({
4454
+ candidates: ["opengrep"],
4455
+ args: ["lsp", "--experimental"],
4456
+ cwd: root,
4457
+ managedToolId: "opengrep"
4458
+ }, options?.allowInstall);
4459
+ if (!launched)
4460
+ return void 0;
4461
+ return { ...launched, initialization: opengrepInitialization(root) };
4462
+ },
4463
+ autoInstall: async () => Boolean(await ensureTool("opengrep"))
4464
+ };
4465
+ var AST_GREP_KINDS = [
4466
+ "csharp",
4467
+ "cxx",
4468
+ "css",
4469
+ "elixir",
4470
+ "go",
4471
+ "haskell",
4472
+ "html",
4473
+ "java",
4474
+ "json",
4475
+ "jsts",
4476
+ "kotlin",
4477
+ "lua",
4478
+ "nix",
4479
+ "php",
4480
+ "python",
4481
+ "ruby",
4482
+ "rust",
4483
+ "scala",
4484
+ "shell",
4485
+ "swift",
4486
+ "yaml"
4487
+ ];
4488
+ var AST_GREP_EXTENSIONS = Array.from(new Set(AST_GREP_KINDS.flatMap((k) => KIND_EXTENSIONS[k] ?? [])));
4489
+ var AstGrepServer = {
4490
+ id: "ast-grep",
4491
+ idleEviction: "unmeasured",
4492
+ name: "ast-grep structural linter",
4493
+ role: "auxiliary",
4494
+ extensions: AST_GREP_EXTENSIONS,
4495
+ // Attaches everywhere (#239 Phase 2): prefer a project `sgconfig.y[a]ml` root,
4496
+ // else the repo root (.git) or cwd — like Opengrep. When there's no project
4497
+ // sgconfig the spawn launches with `--config <shipped baseline>` so the team's
4498
+ // rules still run; the napi runner steps aside when this server is available
4499
+ // (it falls back to napi when the ast-grep binary is absent — Gate B).
4500
+ root: RootWithFallback(createRootDetector(["sgconfig.yml", "sgconfig.yaml"]), RootWithFallback(NearestRoot([".git"]), async () => process.cwd())),
4501
+ availabilityKey: "ast-grep",
4502
+ // #1714: the one auxiliary with a measured wedge ceiling. A `lens_diagnostics
4503
+ // mode=full` sweep of 225 files drove this server into an unrecoverable stall
4504
+ // twice in two exposures (writes outstanding 5.9 s and 9.4 s, then a forced
4505
+ // shutdown that timed out both the request and the exit notify). It re-parses
4506
+ // the whole file on every didOpen, so it absorbs a sweep more slowly than the
4507
+ // other scanners — hold it to half the shared default.
4508
+ notifyInflightLimit: 4,
4509
+ // First scan of a session compiles the rules.
4510
+ initializeTimeoutMs: 15e3,
4511
+ async spawn(root, options) {
4512
+ const projectSgconfig = findLocalSgconfig(root);
4513
+ let args = ["lsp"];
4514
+ if (!projectSgconfig) {
4515
+ const baseline = resolveBaselineSgconfig(root);
4516
+ if (baseline)
4517
+ args = ["lsp", "--config", baseline];
4518
+ }
4519
+ const nativeExe = resolveAstGrepNativeExe();
4520
+ const candidates = nativeExe ? [nativeExe, "ast-grep"] : ["ast-grep"];
4521
+ return resolveAndLaunch({
4522
+ candidates,
4523
+ args,
4524
+ cwd: root,
4525
+ managedToolId: "ast-grep"
4526
+ }, options?.allowInstall);
4527
+ },
4528
+ autoInstall: async () => Boolean(await ensureTool("ast-grep"))
4529
+ };
4530
+ var ZIZMOR_EXTENSIONS = KIND_EXTENSIONS["yaml"];
4531
+ var ZizmorServer = {
4532
+ id: "zizmor",
4533
+ idleEviction: "unmeasured",
4534
+ name: "zizmor Actions Security Scanner",
4535
+ role: "auxiliary",
4536
+ extensions: ZIZMOR_EXTENSIONS,
4537
+ pathFilter: isZizmorAuditTarget,
4538
+ // Stable per-repo root so ONE warm server serves the whole project (like
4539
+ // Opengrep) — config + workflow discovery is repo-relative.
4540
+ root: RootWithFallback(NearestRoot([".git"]), async () => process.cwd()),
4541
+ availabilityKey: "zizmor",
4542
+ async spawn(root, options) {
4543
+ const ghToken = await resolveZizmorGitHubToken();
4544
+ return resolveAndLaunch({
4545
+ candidates: ["zizmor"],
4546
+ args: ["--lsp"],
4547
+ cwd: root,
4548
+ managedToolId: "zizmor",
4549
+ ...ghToken ? { env: { GH_TOKEN: ghToken } } : {}
4550
+ }, options?.allowInstall);
4551
+ },
4552
+ autoInstall: async () => Boolean(await ensureTool("zizmor"))
4553
+ };
4554
+ var TYPOS_EXTENSIONS = Array.from(/* @__PURE__ */ new Set([...OPENGREP_EXTENSIONS, ...KIND_EXTENSIONS["markdown"]]));
4555
+ function typosInitialization(root) {
4556
+ const localConfig = findLocalTyposConfig(root);
4557
+ if (localConfig) {
4558
+ logLatency({
4559
+ type: "phase",
4560
+ phase: "typos_config_resolved",
4561
+ filePath: root,
4562
+ durationMs: 0,
4563
+ metadata: { mode: "project_config", configPath: localConfig }
4564
+ });
4565
+ logSessionStart(`typos config resolved mode=project_config configPath=${localConfig}`);
4566
+ return void 0;
4567
+ }
4568
+ const configPath = resolvePackagePath(import.meta.url, "rules", "typos", "_typos.toml");
4569
+ logLatency({
4570
+ type: "phase",
4571
+ phase: "typos_config_resolved",
4572
+ filePath: root,
4573
+ durationMs: 0,
4574
+ metadata: { mode: "injected_default", configPath }
4575
+ });
4576
+ logSessionStart(`typos config resolved mode=injected_default configPath=${configPath}`);
4577
+ return { config: configPath };
4578
+ }
4579
+ var TyposServer = {
4580
+ id: "typos",
4581
+ idleEviction: "unmeasured",
4582
+ name: "typos Spell Checker",
4583
+ role: "auxiliary",
4584
+ extensions: TYPOS_EXTENSIONS,
4585
+ // Stable per-repo root so ONE warm server serves the whole project (like the
4586
+ // other auxiliaries) — typos.toml discovery is repo-relative.
4587
+ root: RootWithFallback(NearestRoot([".git"]), async () => process.cwd()),
4588
+ availabilityKey: "typos-lsp",
4589
+ async spawn(root, options) {
4590
+ const launched = await resolveAndLaunch({
4591
+ candidates: ["typos-lsp"],
4592
+ args: [],
4593
+ cwd: root,
4594
+ managedToolId: "typos-lsp"
4595
+ }, options?.allowInstall);
4596
+ if (!launched)
4597
+ return void 0;
4598
+ const initialization = typosInitialization(root);
4599
+ return initialization ? { ...launched, initialization } : launched;
4600
+ },
4601
+ autoInstall: async () => Boolean(await ensureTool("typos-lsp"))
4602
+ };
4603
+ var LSP_SERVERS = [
4604
+ TypeScriptServer,
4605
+ DenoServer,
4606
+ PythonServer,
4607
+ // pyright / basedpyright — preferred; openFilesOnly avoids cold-start; ty (#717) is a local-only opt-in fallback
4608
+ PythonJediServer,
4609
+ // fallback when neither pyright nor basedpyright is available
4610
+ GoServer,
4611
+ RustServer,
4612
+ RubyServer,
4613
+ PHPServer,
4614
+ PowerShellServer,
4615
+ // PowerShell Editor Services — pwsh-bootstrapped module bundle (#278)
4616
+ CSharpServer,
4617
+ OmniSharpServer,
4618
+ FSharpServer,
4619
+ JavaServer,
4620
+ KotlinServer,
4621
+ SwiftServer,
4622
+ DartServer,
4623
+ LuaServer,
4624
+ CppServer,
4625
+ ZigServer,
4626
+ HaskellServer,
4627
+ ElixirServer,
4628
+ ElixirExpertServer,
4629
+ GleamServer,
4630
+ TinymistServer,
4631
+ MarksmanServer,
4632
+ OCamlServer,
4633
+ ClojureServer,
4634
+ CueServer,
4635
+ TerraformServer,
4636
+ NixServer,
4637
+ BashServer,
4638
+ ShuckServer,
4639
+ FishServer,
4640
+ CMakeServer,
4641
+ DockerServer,
4642
+ DockerOfficialServer,
4643
+ // alternate of docker; acquired only when docker declines (#3939)
4644
+ YamlServer,
4645
+ JsonServer,
4646
+ HtmlServer,
4647
+ TomlServer,
4648
+ PrismaServer,
4649
+ // Web frameworks & styling
4650
+ VueServer,
4651
+ SvelteServer,
4652
+ CssServer,
4653
+ // Auxiliary (cross-cutting, diagnostic-only) servers go last — never primary.
4654
+ OpengrepServer,
4655
+ AstGrepServer,
4656
+ ZizmorServer,
4657
+ TyposServer
4658
+ ];
4659
+
4660
+ export {
4661
+ findLocalTyposConfig,
4662
+ getAstGrepRuleSources,
4663
+ registerRunnerId,
4664
+ BUILTIN_SERVER_RUNNER_COVERS,
4665
+ describeRootFallback,
4666
+ resolveLspServerCwd,
4667
+ resetLSPCaseSensitivityState,
4668
+ isSameOrWithin,
4669
+ enforceLspRootCeiling,
4670
+ hasProjectBoundaryMarker,
4671
+ resetLspLaunchAvailabilityGeneration,
4672
+ resetDirectLspCommandAvailability,
4673
+ isDirectLspCommandTemporarilyUnavailable,
4674
+ resetClassicTsRepairGuard,
4675
+ LSP_SERVERS,
4676
+ shouldInitializeSessionRoot,
4677
+ isOutsideAllSessionRoots,
4678
+ getSessionRootsForTelemetry,
4679
+ loadLSPConfig,
4680
+ customServerSpecsOf,
4681
+ lspConfigOf,
4682
+ registerLSPConfig,
4683
+ initLSPConfig,
4684
+ explainServersForFile,
4685
+ getServersForFileWithConfig,
4686
+ primaryServerId,
4687
+ resolveLspCwdForFile,
4688
+ getServerInitOverride,
4689
+ getStrategy,
4690
+ classifyServerWaitTier,
4691
+ classifyCascadeWaitTier
4692
+ };