@herbertgao/pi-extensions 2026.10.1 → 2026.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (934) hide show
  1. package/README.md +14 -17
  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/{remote-pi → @herbertgao/pi-agency}/LICENSE +1 -1
  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/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  34. package/node_modules/@herbertgao/pi-subagents/README.md +1 -1
  35. package/node_modules/@herbertgao/pi-subagents/package.json +4 -5
  36. package/node_modules/@herbertgao/pi-subagents/src/index.ts +1 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +1 -1
  38. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +48 -72
  39. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +1 -1
  40. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +15 -6
  41. package/node_modules/@herbertgao/pi-subagents/src/workflow/collisions.ts +4 -1
  42. package/node_modules/@herbertgao/pi-subagents/src/workflow/json-schema.ts +9 -8
  43. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +6 -1
  44. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +2 -2
  45. package/node_modules/@narumitw/pi-caffeinate/package.json +3 -3
  46. package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +13 -1
  47. package/node_modules/@tifan/pi-mermaid-open/package.json +5 -1
  48. package/node_modules/@tifan/pi-mermaid-open/src/index.ts +26 -9
  49. package/node_modules/@tifan/pi-recap/package.json +1 -1
  50. package/node_modules/@tifan/pi-recap/src/index.ts +104 -20
  51. package/node_modules/@tifan/pi-recap/src/models.ts +46 -4
  52. package/node_modules/pi-antigravity/README.md +23 -2
  53. package/node_modules/pi-antigravity/package.json +5 -3
  54. package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +3 -2
  55. package/node_modules/pi-antigravity/src/features/generate-image.ts +72 -0
  56. package/node_modules/pi-antigravity/src/features/google-search.ts +71 -0
  57. package/node_modules/pi-antigravity/src/image/image.ts +86 -47
  58. package/node_modules/pi-antigravity/src/image/native.ts +69 -0
  59. package/node_modules/pi-antigravity/src/index.ts +52 -137
  60. package/node_modules/pi-antigravity/src/search/search.ts +130 -31
  61. package/node_modules/pi-antigravity/src/stream/stream.ts +162 -113
  62. package/node_modules/pi-antigravity/src/types/enums.ts +1 -0
  63. package/node_modules/pi-antigravity/src/types/types.ts +1 -1
  64. package/node_modules/pi-antigravity/src/utils/security.ts +47 -1
  65. package/node_modules/pi-antigravity/src/utils/util.ts +38 -6
  66. package/node_modules/pi-lens/CHANGELOG.md +1159 -0
  67. package/node_modules/pi-lens/README.md +116 -25
  68. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +6 -2
  69. package/node_modules/pi-lens/dist/chunk-2BEMIWEW.js +51 -0
  70. package/node_modules/pi-lens/dist/chunk-2EECBNC5.js +89 -0
  71. package/node_modules/pi-lens/dist/chunk-2FQ62SPM.js +83 -0
  72. package/node_modules/pi-lens/dist/chunk-2UMYMRI3.js +118 -0
  73. package/node_modules/pi-lens/dist/chunk-34OCDWOS.js +48 -0
  74. package/node_modules/pi-lens/dist/chunk-3FERWMCH.js +144 -0
  75. package/node_modules/pi-lens/dist/chunk-3JL6IFD7.js +97 -0
  76. package/node_modules/pi-lens/dist/chunk-3JSEWUWI.js +327 -0
  77. package/node_modules/pi-lens/dist/chunk-3MED75HT.js +37 -0
  78. package/node_modules/pi-lens/dist/chunk-3MRXIJ6I.js +79 -0
  79. package/node_modules/pi-lens/dist/chunk-3P4PF2BX.js +2250 -0
  80. package/node_modules/pi-lens/dist/chunk-3PNFWVHT.js +201 -0
  81. package/node_modules/pi-lens/dist/chunk-3TTPKMEF.js +162 -0
  82. package/node_modules/pi-lens/dist/chunk-5JHXUETW.js +326 -0
  83. package/node_modules/pi-lens/dist/chunk-5W3R6LFT.js +24 -0
  84. package/node_modules/pi-lens/dist/chunk-64LU2OVH.js +341 -0
  85. package/node_modules/pi-lens/dist/chunk-6B5I6ICN.js +44 -0
  86. package/node_modules/pi-lens/dist/chunk-6P54TMWL.js +274 -0
  87. package/node_modules/pi-lens/dist/chunk-6UYA642J.js +145 -0
  88. package/node_modules/pi-lens/dist/chunk-6XX5HCLK.js +398 -0
  89. package/node_modules/pi-lens/dist/chunk-7AXO3ZDF.js +30 -0
  90. package/node_modules/pi-lens/dist/chunk-7BX5DWSA.js +1907 -0
  91. package/node_modules/pi-lens/dist/chunk-7ELY2CSM.js +902 -0
  92. package/node_modules/pi-lens/dist/chunk-7M4T5N3V.js +38 -0
  93. package/node_modules/pi-lens/dist/chunk-7U2IDNXN.js +37 -0
  94. package/node_modules/pi-lens/dist/chunk-ABBOA7UD.js +157 -0
  95. package/node_modules/pi-lens/dist/chunk-AFZYMAIV.js +756 -0
  96. package/node_modules/pi-lens/dist/chunk-ALQRYH6O.js +112 -0
  97. package/node_modules/pi-lens/dist/chunk-AXKPQ6ZI.js +1610 -0
  98. package/node_modules/pi-lens/dist/chunk-BHWHXMQ2.js +62 -0
  99. package/node_modules/pi-lens/dist/chunk-BJF25SUG.js +22 -0
  100. package/node_modules/pi-lens/dist/chunk-BNKLYOOO.js +18 -0
  101. package/node_modules/pi-lens/dist/chunk-BW5KFIQC.js +59 -0
  102. package/node_modules/pi-lens/dist/chunk-CBD2B5CP.js +599 -0
  103. package/node_modules/pi-lens/dist/chunk-CFYISHUW.js +42 -0
  104. package/node_modules/pi-lens/dist/chunk-CMU4RMJB.js +30 -0
  105. package/node_modules/pi-lens/dist/chunk-CULQYFLU.js +14 -0
  106. package/node_modules/pi-lens/dist/chunk-D65GOCJB.js +289 -0
  107. package/node_modules/pi-lens/dist/chunk-D6YF5HKX.js +59 -0
  108. package/node_modules/pi-lens/dist/chunk-DMS52BEP.js +342 -0
  109. package/node_modules/pi-lens/dist/chunk-ELVWJYRV.js +211 -0
  110. package/node_modules/pi-lens/dist/chunk-EUT3B22Y.js +27 -0
  111. package/node_modules/pi-lens/dist/chunk-F5VLZHUW.js +146 -0
  112. package/node_modules/pi-lens/dist/chunk-FC4RP4I2.js +12 -0
  113. package/node_modules/pi-lens/dist/chunk-FGALODG3.js +55 -0
  114. package/node_modules/pi-lens/dist/chunk-G3RLJYA2.js +2358 -0
  115. package/node_modules/pi-lens/dist/chunk-GAYGGICG.js +32 -0
  116. package/node_modules/pi-lens/dist/chunk-H2W2AXD3.js +419 -0
  117. package/node_modules/pi-lens/dist/chunk-H5EV3VMF.js +114 -0
  118. package/node_modules/pi-lens/dist/chunk-HREZQCT3.js +106 -0
  119. package/node_modules/pi-lens/dist/chunk-HSIRMK2D.js +517 -0
  120. package/node_modules/pi-lens/dist/chunk-IMSQR4WO.js +184 -0
  121. package/node_modules/pi-lens/dist/chunk-IQZXOZ7S.js +4816 -0
  122. package/node_modules/pi-lens/dist/chunk-IR6XFA5P.js +37 -0
  123. package/node_modules/pi-lens/dist/chunk-IUKPRZER.js +78 -0
  124. package/node_modules/pi-lens/dist/chunk-IUR76K6A.js +262 -0
  125. package/node_modules/pi-lens/dist/chunk-J3FZR3YY.js +98 -0
  126. package/node_modules/pi-lens/dist/chunk-J6DFZDFA.js +562 -0
  127. package/node_modules/pi-lens/dist/chunk-J7WJZ6W7.js +50 -0
  128. package/node_modules/pi-lens/dist/chunk-JONGANYH.js +202 -0
  129. package/node_modules/pi-lens/dist/chunk-KJCWXUUS.js +425 -0
  130. package/node_modules/pi-lens/dist/chunk-KJN4IOEJ.js +17 -0
  131. package/node_modules/pi-lens/dist/chunk-KMGPUKFD.js +25 -0
  132. package/node_modules/pi-lens/dist/chunk-LD7WFTRX.js +4533 -0
  133. package/node_modules/pi-lens/dist/chunk-LJDODBBZ.js +78 -0
  134. package/node_modules/pi-lens/dist/chunk-LNOMA3MP.js +169 -0
  135. package/node_modules/pi-lens/dist/chunk-MGIWSROG.js +2334 -0
  136. package/node_modules/pi-lens/dist/chunk-MQA2YBAH.js +308 -0
  137. package/node_modules/pi-lens/dist/chunk-MTDRLSI7.js +21720 -0
  138. package/node_modules/pi-lens/dist/chunk-N2IRDBZI.js +2355 -0
  139. package/node_modules/pi-lens/dist/chunk-N77WFUL7.js +50 -0
  140. package/node_modules/pi-lens/dist/chunk-N7YNJE5R.js +466 -0
  141. package/node_modules/pi-lens/dist/chunk-NABLC7W3.js +148 -0
  142. package/node_modules/pi-lens/dist/chunk-NFXP47RV.js +999 -0
  143. package/node_modules/pi-lens/dist/chunk-NJF2X5XF.js +45 -0
  144. package/node_modules/pi-lens/dist/chunk-NXL4FFQQ.js +47 -0
  145. package/node_modules/pi-lens/dist/chunk-O7HZX7CA.js +309 -0
  146. package/node_modules/pi-lens/dist/chunk-OC7LYAU5.js +708 -0
  147. package/node_modules/pi-lens/dist/chunk-OEX24ECI.js +348 -0
  148. package/node_modules/pi-lens/dist/chunk-OYOB3ZFG.js +78 -0
  149. package/node_modules/pi-lens/dist/chunk-OYTMZXRF.js +41 -0
  150. package/node_modules/pi-lens/dist/chunk-OZJINN4O.js +84 -0
  151. package/node_modules/pi-lens/dist/chunk-PCHDGUKT.js +23 -0
  152. package/node_modules/pi-lens/dist/chunk-QOZXJ4NA.js +3364 -0
  153. package/node_modules/pi-lens/dist/chunk-QYF5S6P6.js +45 -0
  154. package/node_modules/pi-lens/dist/chunk-RJFED73B.js +79 -0
  155. package/node_modules/pi-lens/dist/chunk-RTQNRM5X.js +27 -0
  156. package/node_modules/pi-lens/dist/chunk-S6AMWKPC.js +189 -0
  157. package/node_modules/pi-lens/dist/chunk-T4QZ6FEH.js +308 -0
  158. package/node_modules/pi-lens/dist/chunk-T54VJRAD.js +5456 -0
  159. package/node_modules/pi-lens/dist/chunk-TA5L5KWQ.js +167 -0
  160. package/node_modules/pi-lens/dist/chunk-TQFBZVCG.js +27 -0
  161. package/node_modules/pi-lens/dist/chunk-U52SAGRM.js +62 -0
  162. package/node_modules/pi-lens/dist/chunk-UEAHAMEI.js +5814 -0
  163. package/node_modules/pi-lens/dist/chunk-UGSMCQ4D.js +327 -0
  164. package/node_modules/pi-lens/dist/chunk-UOPVJQ4N.js +103 -0
  165. package/node_modules/pi-lens/dist/chunk-USHG4DLH.js +459 -0
  166. package/node_modules/pi-lens/dist/chunk-UXVNL3D7.js +23 -0
  167. package/node_modules/pi-lens/dist/chunk-V5MEBST3.js +4139 -0
  168. package/node_modules/pi-lens/dist/chunk-VGEVL5EQ.js +29 -0
  169. package/node_modules/pi-lens/dist/chunk-VPWKF3GN.js +87 -0
  170. package/node_modules/pi-lens/dist/chunk-VSMJK3ZJ.js +1250 -0
  171. package/node_modules/pi-lens/dist/chunk-VYKKMYVT.js +560 -0
  172. package/node_modules/pi-lens/dist/chunk-VZHJS6DR.js +442 -0
  173. package/node_modules/pi-lens/dist/chunk-WATC3IQR.js +213 -0
  174. package/node_modules/pi-lens/dist/chunk-WPE5FPGR.js +54 -0
  175. package/node_modules/pi-lens/dist/chunk-WSEWKCXU.js +188 -0
  176. package/node_modules/pi-lens/dist/chunk-WW5BLB74.js +659 -0
  177. package/node_modules/pi-lens/dist/chunk-XGUL4SLQ.js +406 -0
  178. package/node_modules/pi-lens/dist/chunk-XHSCVSOL.js +170 -0
  179. package/node_modules/pi-lens/dist/chunk-XIMYZ3JA.js +27 -0
  180. package/node_modules/pi-lens/dist/chunk-YLN4K6WD.js +385 -0
  181. package/node_modules/pi-lens/dist/chunk-Z3CCVDUB.js +76 -0
  182. package/node_modules/pi-lens/dist/chunk-Z54ZSOBZ.js +61 -0
  183. package/node_modules/pi-lens/dist/chunk-Z6BB4JLQ.js +478 -0
  184. package/node_modules/pi-lens/dist/chunk-Z7QQA2KT.js +27 -0
  185. package/node_modules/pi-lens/dist/chunk-ZETYB3XG.js +2626 -0
  186. package/node_modules/pi-lens/dist/chunk-ZMOMPX2Z.js +87 -0
  187. package/node_modules/pi-lens/dist/chunk-ZOEYVXSV.js +149 -0
  188. package/node_modules/pi-lens/dist/chunk-ZZUFZUQZ.js +12120 -0
  189. package/node_modules/pi-lens/dist/index.js +39712 -29876
  190. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +186 -232
  191. package/node_modules/pi-lens/dist/mcp/cli.js +137 -98
  192. package/node_modules/pi-lens/dist/mcp/server.js +22688 -1573
  193. package/node_modules/pi-lens/dist/mcp/worker.js +97 -38
  194. package/node_modules/pi-lens/dist/probes/installer.js +135 -0
  195. package/node_modules/pi-lens/dist/workers/project-snapshot-persist-worker.js +22 -0
  196. package/node_modules/pi-lens/dist/workers/review-graph-persist-worker.js +15 -0
  197. package/node_modules/pi-lens/docs/agent-guide.md +13 -4
  198. package/node_modules/pi-lens/docs/agent-tools.md +42 -0
  199. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -4
  200. package/node_modules/pi-lens/docs/configuration.md +28 -2
  201. package/node_modules/pi-lens/docs/custom-rules.md +25 -2
  202. package/node_modules/pi-lens/docs/environment-variables.md +86 -8
  203. package/node_modules/pi-lens/docs/features.md +45 -5
  204. package/node_modules/pi-lens/docs/globalconfig.md +2 -1
  205. package/node_modules/pi-lens/docs/io-bridge-v2-migration.md +94 -0
  206. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +37 -4
  207. package/node_modules/pi-lens/docs/lsp-idle-eviction.md +124 -0
  208. package/node_modules/pi-lens/docs/mcp.md +21 -5
  209. package/node_modules/pi-lens/docs/merge-queue-rollout.md +77 -0
  210. package/node_modules/pi-lens/docs/pi-lens-fixer.md +160 -88
  211. package/node_modules/pi-lens/docs/pi-lens-investigator.md +74 -26
  212. package/node_modules/pi-lens/docs/pi-lens-merge-policy.md +736 -0
  213. package/node_modules/pi-lens/docs/pi-lens-monitor.md +75 -7
  214. package/node_modules/pi-lens/docs/pi-lens-retro.md +6 -4
  215. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +189 -48
  216. package/node_modules/pi-lens/docs/pi-lens-subagent.md +246 -45
  217. package/node_modules/pi-lens/docs/pi-lens-warden.md +18 -7
  218. package/node_modules/pi-lens/docs/public-api-stability.md +55 -0
  219. package/node_modules/pi-lens/docs/release-qa-baseline.md +84 -17
  220. package/node_modules/pi-lens/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  221. package/node_modules/pi-lens/docs/schema/pi-lens-config-v1.json +530 -0
  222. package/node_modules/pi-lens/docs/servercapabilities.md +56 -49
  223. package/node_modules/pi-lens/docs/settings.md +1 -0
  224. package/node_modules/pi-lens/docs/usage.md +5 -1
  225. package/node_modules/pi-lens/docs/word-index.md +6 -0
  226. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm +0 -0
  227. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm.json +3 -3
  228. package/node_modules/pi-lens/package.json +18 -6
  229. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  230. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-identity-operator-on-literals-test.yml +12 -2
  231. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/throw-new-error-js-test.yml +2 -0
  232. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/throw-new-error-test.yml +2 -0
  233. package/node_modules/pi-lens/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  234. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-identity-operator-on-literals.yml +20 -12
  235. package/node_modules/pi-lens/rules/ast-grep-rules/rules/throw-new-error-js.yml +2 -2
  236. package/node_modules/pi-lens/rules/ast-grep-rules/rules/throw-new-error.yml +2 -2
  237. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +1275 -62
  238. package/node_modules/pi-lens/scripts/download-grammars.js +5 -0
  239. package/node_modules/pi-lens/scripts/grammars.lock.json +6 -1
  240. package/node_modules/pi-lens/scripts/install-selftest.mjs +33 -34
  241. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +13 -4
  242. package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +18 -0
  243. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  244. package/node_modules/pi-web-access/README.md +10 -6
  245. package/node_modules/pi-web-access/ceramic.ts +219 -0
  246. package/node_modules/pi-web-access/curator-page.ts +3 -1
  247. package/node_modules/pi-web-access/curator-server.ts +1 -0
  248. package/node_modules/pi-web-access/dist/index.js +846 -588
  249. package/node_modules/pi-web-access/dist/mcp-cli.js +725 -516
  250. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  251. package/node_modules/pi-web-access/github-extract.ts +34 -2
  252. package/node_modules/pi-web-access/index.ts +72 -30
  253. package/node_modules/pi-web-access/openai-search.ts +3 -3
  254. package/node_modules/pi-web-access/package.json +2 -2
  255. package/node_modules/pi-web-access/page-query.ts +6 -9
  256. package/node_modules/pi-web-access/parallel-mcp.ts +2 -0
  257. package/node_modules/pi-web-access/query-rewrite.ts +2 -2
  258. package/node_modules/pi-web-access/storage.ts +49 -0
  259. package/node_modules/pi-web-access/summary-review.ts +7 -6
  260. package/node_modules/pi-web-access/utils.ts +21 -6
  261. package/node_modules/pi-web-access/web-tool-core.ts +1 -0
  262. package/package.json +19 -19
  263. package/node_modules/@dietrichgebert/ponytail/README.es.md +0 -212
  264. package/node_modules/@dietrichgebert/ponytail/README.ja.md +0 -212
  265. package/node_modules/@dietrichgebert/ponytail/README.ko.md +0 -212
  266. package/node_modules/@dietrichgebert/ponytail/README.zh-CN.md +0 -212
  267. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -35
  268. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +0 -1610
  269. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +0 -593
  270. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +0 -147
  271. package/node_modules/pi-lens/dist/clients/agent-nudge.js +0 -325
  272. package/node_modules/pi-lens/dist/clients/analysed-root.js +0 -1
  273. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +0 -731
  274. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +0 -146
  275. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +0 -118
  276. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -10
  277. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +0 -154
  278. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +0 -75
  279. package/node_modules/pi-lens/dist/clients/atomic-write.js +0 -189
  280. package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +0 -12
  281. package/node_modules/pi-lens/dist/clients/bash-file-access.js +0 -1056
  282. package/node_modules/pi-lens/dist/clients/biome-client.js +0 -357
  283. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -837
  284. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +0 -129
  285. package/node_modules/pi-lens/dist/clients/bootstrap.js +0 -569
  286. package/node_modules/pi-lens/dist/clients/bounded-cache.js +0 -190
  287. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +0 -202
  288. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +0 -295
  289. package/node_modules/pi-lens/dist/clients/build-identity.js +0 -95
  290. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +0 -113
  291. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +0 -105
  292. package/node_modules/pi-lens/dist/clients/bus-publish.js +0 -171
  293. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +0 -190
  294. package/node_modules/pi-lens/dist/clients/cache-manager.js +0 -524
  295. package/node_modules/pi-lens/dist/clients/cache-observability.js +0 -1313
  296. package/node_modules/pi-lens/dist/clients/call-graph.js +0 -852
  297. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +0 -422
  298. package/node_modules/pi-lens/dist/clients/cascade-budget.js +0 -196
  299. package/node_modules/pi-lens/dist/clients/cascade-format.js +0 -315
  300. package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -31
  301. package/node_modules/pi-lens/dist/clients/cascade-types.js +0 -9
  302. package/node_modules/pi-lens/dist/clients/child-unref.js +0 -124
  303. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +0 -286
  304. package/node_modules/pi-lens/dist/clients/codebase-model.js +0 -173
  305. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +0 -40
  306. package/node_modules/pi-lens/dist/clients/complexity-client.js +0 -462
  307. package/node_modules/pi-lens/dist/clients/config-core/deny.js +0 -221
  308. package/node_modules/pi-lens/dist/clients/config-core/index.js +0 -50
  309. package/node_modules/pi-lens/dist/clients/config-core/merge.js +0 -357
  310. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +0 -340
  311. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +0 -248
  312. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +0 -164
  313. package/node_modules/pi-lens/dist/clients/config-core/records.js +0 -218
  314. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +0 -125
  315. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +0 -78
  316. package/node_modules/pi-lens/dist/clients/config-core/schema.js +0 -165
  317. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +0 -285
  318. package/node_modules/pi-lens/dist/clients/config-locations.js +0 -388
  319. package/node_modules/pi-lens/dist/clients/config-resolve.js +0 -798
  320. package/node_modules/pi-lens/dist/clients/config-schema.js +0 -251
  321. package/node_modules/pi-lens/dist/clients/config-warn.js +0 -407
  322. package/node_modules/pi-lens/dist/clients/console-guard-install.js +0 -26
  323. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +0 -42
  324. package/node_modules/pi-lens/dist/clients/dead-code-client.js +0 -510
  325. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -30
  326. package/node_modules/pi-lens/dist/clients/deadline-utils.js +0 -280
  327. package/node_modules/pi-lens/dist/clients/debug-handles.js +0 -211
  328. package/node_modules/pi-lens/dist/clients/debug-heap.js +0 -174
  329. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +0 -106
  330. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +0 -426
  331. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +0 -169
  332. package/node_modules/pi-lens/dist/clients/dependency-checker.js +0 -885
  333. package/node_modules/pi-lens/dist/clients/deps/ast-grep-napi.js +0 -22
  334. package/node_modules/pi-lens/dist/clients/deps/js-yaml.js +0 -9
  335. package/node_modules/pi-lens/dist/clients/deps/minimatch.js +0 -4
  336. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +0 -14
  337. package/node_modules/pi-lens/dist/clients/deps/typebox.js +0 -14
  338. package/node_modules/pi-lens/dist/clients/deps/vscode-jsonrpc.js +0 -1
  339. package/node_modules/pi-lens/dist/clients/deps/web-tree-sitter.js +0 -24
  340. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +0 -630
  341. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +0 -305
  342. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +0 -73
  343. package/node_modules/pi-lens/dist/clients/diagnostic-tracker.js +0 -105
  344. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +0 -230
  345. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  346. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  347. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -35
  348. package/node_modules/pi-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  349. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +0 -1269
  350. package/node_modules/pi-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
  351. package/node_modules/pi-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
  352. package/node_modules/pi-lens/dist/clients/dispatch/fact-runner.js +0 -30
  353. package/node_modules/pi-lens/dist/clients/dispatch/fact-scheduler.js +0 -68
  354. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +0 -377
  355. package/node_modules/pi-lens/dist/clients/dispatch/facts/comment-facts.js +0 -22
  356. package/node_modules/pi-lens/dist/clients/dispatch/facts/file-content.js +0 -19
  357. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +0 -348
  358. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +0 -204
  359. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  360. package/node_modules/pi-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  361. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +0 -339
  362. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +0 -417
  363. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +0 -89
  364. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +0 -2377
  365. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -11
  366. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +0 -87
  367. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -278
  368. package/node_modules/pi-lens/dist/clients/dispatch/priorities.js +0 -20
  369. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +0 -50
  370. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +0 -69
  371. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +0 -135
  372. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-noise.js +0 -40
  373. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  374. package/node_modules/pi-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  375. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  376. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  377. package/node_modules/pi-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  378. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +0 -72
  379. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  380. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  381. package/node_modules/pi-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  382. package/node_modules/pi-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  383. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  384. package/node_modules/pi-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  385. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  386. package/node_modules/pi-lens/dist/clients/dispatch/runner-context.js +0 -52
  387. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -111
  388. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  389. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -296
  390. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -219
  391. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -82
  392. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -416
  393. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -183
  394. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -176
  395. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -164
  396. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -195
  397. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -137
  398. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -29
  399. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -69
  400. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -167
  401. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +0 -104
  402. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -135
  403. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -91
  404. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -171
  405. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -940
  406. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -117
  407. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +0 -108
  408. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -99
  409. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -110
  410. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -379
  411. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -167
  412. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -102
  413. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +0 -414
  414. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -85
  415. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -120
  416. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  417. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  418. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +0 -169
  419. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -99
  420. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -88
  421. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -256
  422. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -173
  423. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -102
  424. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -128
  425. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -259
  426. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -183
  427. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -166
  428. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -163
  429. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -174
  430. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -168
  431. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -125
  432. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -643
  433. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -253
  434. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  435. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  436. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
  437. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  438. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  439. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  440. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  441. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  442. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -15
  443. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -128
  444. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  445. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -95
  446. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -79
  447. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +0 -79
  448. package/node_modules/pi-lens/dist/clients/dispatch/tool-profile.js +0 -30
  449. package/node_modules/pi-lens/dist/clients/dispatch/types.js +0 -21
  450. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
  451. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  452. package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -32
  453. package/node_modules/pi-lens/dist/clients/disposition-publish.js +0 -124
  454. package/node_modules/pi-lens/dist/clients/durable-store.js +0 -97
  455. package/node_modules/pi-lens/dist/clients/effective-config.js +0 -415
  456. package/node_modules/pi-lens/dist/clients/env-utils.js +0 -83
  457. package/node_modules/pi-lens/dist/clients/error-class.js +0 -23
  458. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +0 -17
  459. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +0 -274
  460. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +0 -250
  461. package/node_modules/pi-lens/dist/clients/extension-log.js +0 -504
  462. package/node_modules/pi-lens/dist/clients/extension-mode.js +0 -73
  463. package/node_modules/pi-lens/dist/clients/feature-hints.js +0 -103
  464. package/node_modules/pi-lens/dist/clients/file-kinds.js +0 -412
  465. package/node_modules/pi-lens/dist/clients/file-role.js +0 -134
  466. package/node_modules/pi-lens/dist/clients/file-time.js +0 -160
  467. package/node_modules/pi-lens/dist/clients/file-utils.js +0 -1032
  468. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +0 -494
  469. package/node_modules/pi-lens/dist/clients/finding-identity.js +0 -88
  470. package/node_modules/pi-lens/dist/clients/fix-worklog.js +0 -103
  471. package/node_modules/pi-lens/dist/clients/format-events-publish.js +0 -343
  472. package/node_modules/pi-lens/dist/clients/format-service.js +0 -222
  473. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +0 -9
  474. package/node_modules/pi-lens/dist/clients/formatters.js +0 -2032
  475. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +0 -17
  476. package/node_modules/pi-lens/dist/clients/freshness.js +0 -38
  477. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +0 -394
  478. package/node_modules/pi-lens/dist/clients/generation-guard.js +0 -215
  479. package/node_modules/pi-lens/dist/clients/git-guard.js +0 -1136
  480. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +0 -243
  481. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +0 -509
  482. package/node_modules/pi-lens/dist/clients/go-client.js +0 -104
  483. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +0 -605
  484. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +0 -348
  485. package/node_modules/pi-lens/dist/clients/grammar-source.js +0 -465
  486. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +0 -135
  487. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +0 -424
  488. package/node_modules/pi-lens/dist/clients/hook-budgets.js +0 -76
  489. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +0 -140
  490. package/node_modules/pi-lens/dist/clients/host-ports.js +0 -39
  491. package/node_modules/pi-lens/dist/clients/indent-retarget.js +0 -154
  492. package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +0 -186
  493. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +0 -156
  494. package/node_modules/pi-lens/dist/clients/installer/index.js +0 -5416
  495. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  496. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +0 -783
  497. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +0 -7
  498. package/node_modules/pi-lens/dist/clients/instance-reaper.js +0 -1137
  499. package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +0 -145
  500. package/node_modules/pi-lens/dist/clients/instance-registry.js +0 -773
  501. package/node_modules/pi-lens/dist/clients/jscpd-client.js +0 -378
  502. package/node_modules/pi-lens/dist/clients/json-cache-read.js +0 -65
  503. package/node_modules/pi-lens/dist/clients/knip-client.js +0 -788
  504. package/node_modules/pi-lens/dist/clients/language-policy.js +0 -252
  505. package/node_modules/pi-lens/dist/clients/language-profile.js +0 -361
  506. package/node_modules/pi-lens/dist/clients/language-registry.js +0 -603
  507. package/node_modules/pi-lens/dist/clients/latency-logger.js +0 -727
  508. package/node_modules/pi-lens/dist/clients/lazy-import.js +0 -21
  509. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +0 -54
  510. package/node_modules/pi-lens/dist/clients/lens-config.js +0 -404
  511. package/node_modules/pi-lens/dist/clients/lens-engine.js +0 -358
  512. package/node_modules/pi-lens/dist/clients/lens-events.js +0 -125
  513. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +0 -467
  514. package/node_modules/pi-lens/dist/clients/lens-map.js +0 -1156
  515. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +0 -74
  516. package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -222
  517. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +0 -178
  518. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +0 -421
  519. package/node_modules/pi-lens/dist/clients/lsp/client.js +0 -4593
  520. package/node_modules/pi-lens/dist/clients/lsp/config.js +0 -691
  521. package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +0 -41
  522. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +0 -225
  523. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +0 -467
  524. package/node_modules/pi-lens/dist/clients/lsp/edits.js +0 -1219
  525. package/node_modules/pi-lens/dist/clients/lsp/index.js +0 -8305
  526. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +0 -216
  527. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +0 -298
  528. package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -63
  529. package/node_modules/pi-lens/dist/clients/lsp/launch.js +0 -746
  530. package/node_modules/pi-lens/dist/clients/lsp/lombok.js +0 -158
  531. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +0 -5
  532. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -251
  533. package/node_modules/pi-lens/dist/clients/lsp/position-encoding.js +0 -61
  534. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  535. package/node_modules/pi-lens/dist/clients/lsp/server.js +0 -3290
  536. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +0 -192
  537. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +0 -17
  538. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -56
  539. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +0 -332
  540. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  541. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +0 -85
  542. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/index.js +0 -10
  543. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +0 -392
  544. package/node_modules/pi-lens/dist/clients/lsp/watch-queue.js +0 -61
  545. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  546. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  547. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  548. package/node_modules/pi-lens/dist/clients/lsp-budget.js +0 -186
  549. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +0 -110
  550. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +0 -9
  551. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +0 -396
  552. package/node_modules/pi-lens/dist/clients/lsp-status.js +0 -59
  553. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +0 -40
  554. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +0 -420
  555. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +0 -31
  556. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +0 -523
  557. package/node_modules/pi-lens/dist/clients/mcp/review.js +0 -197
  558. package/node_modules/pi-lens/dist/clients/mcp/session.js +0 -412
  559. package/node_modules/pi-lens/dist/clients/memory-sampler.js +0 -208
  560. package/node_modules/pi-lens/dist/clients/message-end-attribution.js +0 -30
  561. package/node_modules/pi-lens/dist/clients/metrics-client.js +0 -107
  562. package/node_modules/pi-lens/dist/clients/metrics-history.js +0 -327
  563. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +0 -263
  564. package/node_modules/pi-lens/dist/clients/model-provider.js +0 -53
  565. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +0 -189
  566. package/node_modules/pi-lens/dist/clients/module-report.js +0 -2150
  567. package/node_modules/pi-lens/dist/clients/mutating-tool.js +0 -651
  568. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +0 -368
  569. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +0 -240
  570. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -734
  571. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +0 -101
  572. package/node_modules/pi-lens/dist/clients/observed-mutation.js +0 -1253
  573. package/node_modules/pi-lens/dist/clients/oldtext-autopatch.js +0 -128
  574. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +0 -496
  575. package/node_modules/pi-lens/dist/clients/opengrep-client.js +0 -333
  576. package/node_modules/pi-lens/dist/clients/opengrep-config.js +0 -76
  577. package/node_modules/pi-lens/dist/clients/package-manager.js +0 -607
  578. package/node_modules/pi-lens/dist/clients/package-root.js +0 -38
  579. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +0 -439
  580. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +0 -43
  581. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +0 -108
  582. package/node_modules/pi-lens/dist/clients/path-utils.js +0 -1244
  583. package/node_modules/pi-lens/dist/clients/performance-report.js +0 -331
  584. package/node_modules/pi-lens/dist/clients/persist-debounce.js +0 -70
  585. package/node_modules/pi-lens/dist/clients/persistent-reverify.js +0 -271
  586. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +0 -119
  587. package/node_modules/pi-lens/dist/clients/pipeline.js +0 -1480
  588. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +0 -37
  589. package/node_modules/pi-lens/dist/clients/print-mode.js +0 -21
  590. package/node_modules/pi-lens/dist/clients/probe-home-state.js +0 -228
  591. package/node_modules/pi-lens/dist/clients/process-bridge.js +0 -66
  592. package/node_modules/pi-lens/dist/clients/process-singletons.js +0 -210
  593. package/node_modules/pi-lens/dist/clients/process-snapshot.js +0 -68
  594. package/node_modules/pi-lens/dist/clients/project-changes.js +0 -181
  595. package/node_modules/pi-lens/dist/clients/project-conventions.js +0 -171
  596. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +0 -137
  597. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +0 -109
  598. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
  599. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  600. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  601. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  602. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  603. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  604. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  605. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  606. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  607. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  608. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  609. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +0 -520
  610. package/node_modules/pi-lens/dist/clients/project-diagnostics/types.js +0 -1
  611. package/node_modules/pi-lens/dist/clients/project-lens-config.js +0 -807
  612. package/node_modules/pi-lens/dist/clients/project-report.js +0 -701
  613. package/node_modules/pi-lens/dist/clients/project-scale.js +0 -237
  614. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +0 -11
  615. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +0 -48
  616. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +0 -20
  617. package/node_modules/pi-lens/dist/clients/project-snapshot.js +0 -1653
  618. package/node_modules/pi-lens/dist/clients/project-trust.js +0 -181
  619. package/node_modules/pi-lens/dist/clients/python-environment.js +0 -217
  620. package/node_modules/pi-lens/dist/clients/python-provenance.js +0 -639
  621. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +0 -47
  622. package/node_modules/pi-lens/dist/clients/quiet-window.js +0 -236
  623. package/node_modules/pi-lens/dist/clients/read-bridge.js +0 -139
  624. package/node_modules/pi-lens/dist/clients/read-expansion.js +0 -266
  625. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +0 -251
  626. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +0 -1306
  627. package/node_modules/pi-lens/dist/clients/read-guard.js +0 -1561
  628. package/node_modules/pi-lens/dist/clients/recent-touches.js +0 -240
  629. package/node_modules/pi-lens/dist/clients/redact/secrets.js +0 -449
  630. package/node_modules/pi-lens/dist/clients/resource-sampler.js +0 -628
  631. package/node_modules/pi-lens/dist/clients/reverse-deps.js +0 -270
  632. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +0 -5126
  633. package/node_modules/pi-lens/dist/clients/review-graph/format.js +0 -33
  634. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +0 -163
  635. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +0 -481
  636. package/node_modules/pi-lens/dist/clients/review-graph/persist-worker.js +0 -10
  637. package/node_modules/pi-lens/dist/clients/review-graph/query.js +0 -244
  638. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +0 -21
  639. package/node_modules/pi-lens/dist/clients/review-graph/service.js +0 -96
  640. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  641. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +0 -103
  642. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +0 -299
  643. package/node_modules/pi-lens/dist/clients/review-graph/types.js +0 -1
  644. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +0 -449
  645. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +0 -81
  646. package/node_modules/pi-lens/dist/clients/ruff-client.js +0 -179
  647. package/node_modules/pi-lens/dist/clients/rules-scanner.js +0 -131
  648. package/node_modules/pi-lens/dist/clients/run-duration.js +0 -55
  649. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +0 -746
  650. package/node_modules/pi-lens/dist/clients/runtime-config.js +0 -77
  651. package/node_modules/pi-lens/dist/clients/runtime-context.js +0 -211
  652. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +0 -1324
  653. package/node_modules/pi-lens/dist/clients/runtime-session.js +0 -2485
  654. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +0 -1295
  655. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +0 -2049
  656. package/node_modules/pi-lens/dist/clients/runtime-turn.js +0 -3767
  657. package/node_modules/pi-lens/dist/clients/rust-client.js +0 -97
  658. package/node_modules/pi-lens/dist/clients/safe-spawn.js +0 -2357
  659. package/node_modules/pi-lens/dist/clients/sanitize.js +0 -286
  660. package/node_modules/pi-lens/dist/clients/scan-utils.js +0 -25
  661. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +0 -165
  662. package/node_modules/pi-lens/dist/clients/search-read-registration.js +0 -94
  663. package/node_modules/pi-lens/dist/clients/secret-findings.js +0 -114
  664. package/node_modules/pi-lens/dist/clients/security-scan-client.js +0 -352
  665. package/node_modules/pi-lens/dist/clients/session-event-guard.js +0 -297
  666. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +0 -484
  667. package/node_modules/pi-lens/dist/clients/session-start-observability.js +0 -94
  668. package/node_modules/pi-lens/dist/clients/session-state-store.js +0 -101
  669. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -15
  670. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +0 -27
  671. package/node_modules/pi-lens/dist/clients/sg-runner.js +0 -876
  672. package/node_modules/pi-lens/dist/clients/sgconfig.js +0 -347
  673. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +0 -338
  674. package/node_modules/pi-lens/dist/clients/single-flight.js +0 -158
  675. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +0 -108
  676. package/node_modules/pi-lens/dist/clients/skills-resolver.js +0 -141
  677. package/node_modules/pi-lens/dist/clients/slow-fs.js +0 -138
  678. package/node_modules/pi-lens/dist/clients/smells-rollup.js +0 -231
  679. package/node_modules/pi-lens/dist/clients/source-filter.js +0 -596
  680. package/node_modules/pi-lens/dist/clients/source-walker.js +0 -211
  681. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +0 -120
  682. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +0 -110
  683. package/node_modules/pi-lens/dist/clients/stale-marker.js +0 -17
  684. package/node_modules/pi-lens/dist/clients/startup-scan.js +0 -400
  685. package/node_modules/pi-lens/dist/clients/startup-timing.js +0 -130
  686. package/node_modules/pi-lens/dist/clients/string-utils.js +0 -33
  687. package/node_modules/pi-lens/dist/clients/subagent-mode.js +0 -111
  688. package/node_modules/pi-lens/dist/clients/symbol-containment.js +0 -24
  689. package/node_modules/pi-lens/dist/clients/symbol-types.js +0 -5
  690. package/node_modules/pi-lens/dist/clients/test-runner-client.js +0 -2507
  691. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +0 -287
  692. package/node_modules/pi-lens/dist/clients/todo-scanner.js +0 -229
  693. package/node_modules/pi-lens/dist/clients/tool-agreement.js +0 -423
  694. package/node_modules/pi-lens/dist/clients/tool-config.js +0 -249
  695. package/node_modules/pi-lens/dist/clients/tool-cwd.js +0 -270
  696. package/node_modules/pi-lens/dist/clients/tool-definition.js +0 -47
  697. package/node_modules/pi-lens/dist/clients/tool-event.js +0 -105
  698. package/node_modules/pi-lens/dist/clients/tool-policy.js +0 -2755
  699. package/node_modules/pi-lens/dist/clients/tool-probe.js +0 -53
  700. package/node_modules/pi-lens/dist/clients/tool-render.js +0 -156
  701. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +0 -118
  702. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +0 -364
  703. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +0 -4195
  704. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +0 -100
  705. package/node_modules/pi-lens/dist/clients/tree-sitter-navigator.js +0 -269
  706. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +0 -569
  707. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +0 -158
  708. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  709. package/node_modules/pi-lens/dist/clients/trivy-client.js +0 -467
  710. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -50
  711. package/node_modules/pi-lens/dist/clients/turn-context.js +0 -52
  712. package/node_modules/pi-lens/dist/clients/turn-end/lane.js +0 -51
  713. package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -112
  714. package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +0 -204
  715. package/node_modules/pi-lens/dist/clients/turn-summary-render.js +0 -72
  716. package/node_modules/pi-lens/dist/clients/turn-summary.js +0 -132
  717. package/node_modules/pi-lens/dist/clients/typos-config.js +0 -29
  718. package/node_modules/pi-lens/dist/clients/user-notify.js +0 -51
  719. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +0 -57
  720. package/node_modules/pi-lens/dist/clients/warm-attach.js +0 -305
  721. package/node_modules/pi-lens/dist/clients/widget-state.js +0 -1808
  722. package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -49
  723. package/node_modules/pi-lens/dist/clients/word-index-store.js +0 -459
  724. package/node_modules/pi-lens/dist/clients/word-index.js +0 -2080
  725. package/node_modules/pi-lens/dist/clients/workspace-topology.js +0 -443
  726. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +0 -65
  727. package/node_modules/pi-lens/dist/clients/zizmor-config.js +0 -340
  728. package/node_modules/pi-lens/dist/i18n.js +0 -69
  729. package/node_modules/pi-lens/dist/mcp/build-staleness.js +0 -124
  730. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +0 -583
  731. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +0 -129
  732. package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
  733. package/node_modules/pi-lens/dist/tools/activate-tools.js +0 -87
  734. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +0 -137
  735. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +0 -244
  736. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +0 -762
  737. package/node_modules/pi-lens/dist/tools/effective-config.js +0 -90
  738. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +0 -375
  739. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +0 -2571
  740. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +0 -1745
  741. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +0 -1367
  742. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +0 -294
  743. package/node_modules/pi-lens/dist/tools/module-report.js +0 -382
  744. package/node_modules/pi-lens/dist/tools/project-report.js +0 -86
  745. package/node_modules/pi-lens/dist/tools/render-compact.js +0 -374
  746. package/node_modules/pi-lens/dist/tools/scan-progress.js +0 -53
  747. package/node_modules/pi-lens/dist/tools/shared.js +0 -29
  748. package/node_modules/pi-lens/dist/tools/symbol-search.js +0 -155
  749. package/node_modules/pi-web-access/opencode-session-headers.ts +0 -24
  750. package/node_modules/remote-pi/README.md +0 -675
  751. package/node_modules/remote-pi/dist/actions/handlers.d.ts +0 -122
  752. package/node_modules/remote-pi/dist/actions/handlers.js +0 -160
  753. package/node_modules/remote-pi/dist/actions/handlers.js.map +0 -1
  754. package/node_modules/remote-pi/dist/actions/registry.d.ts +0 -39
  755. package/node_modules/remote-pi/dist/actions/registry.js +0 -58
  756. package/node_modules/remote-pi/dist/actions/registry.js.map +0 -1
  757. package/node_modules/remote-pi/dist/bin/supervisord.d.ts +0 -2
  758. package/node_modules/remote-pi/dist/bin/supervisord.js +0 -86
  759. package/node_modules/remote-pi/dist/bin/supervisord.js.map +0 -1
  760. package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +0 -58
  761. package/node_modules/remote-pi/dist/commands/builtin_mirror.js +0 -71
  762. package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +0 -1
  763. package/node_modules/remote-pi/dist/commands/list_commands.d.ts +0 -60
  764. package/node_modules/remote-pi/dist/commands/list_commands.js +0 -73
  765. package/node_modules/remote-pi/dist/commands/list_commands.js.map +0 -1
  766. package/node_modules/remote-pi/dist/config.d.ts +0 -62
  767. package/node_modules/remote-pi/dist/config.js +0 -115
  768. package/node_modules/remote-pi/dist/config.js.map +0 -1
  769. package/node_modules/remote-pi/dist/daemon/client.d.ts +0 -20
  770. package/node_modules/remote-pi/dist/daemon/client.js +0 -131
  771. package/node_modules/remote-pi/dist/daemon/client.js.map +0 -1
  772. package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +0 -176
  773. package/node_modules/remote-pi/dist/daemon/control_protocol.js +0 -63
  774. package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +0 -1
  775. package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +0 -45
  776. package/node_modules/remote-pi/dist/daemon/cron_log.js +0 -72
  777. package/node_modules/remote-pi/dist/daemon/cron_log.js.map +0 -1
  778. package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +0 -80
  779. package/node_modules/remote-pi/dist/daemon/cron_registry.js +0 -194
  780. package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +0 -1
  781. package/node_modules/remote-pi/dist/daemon/id.d.ts +0 -24
  782. package/node_modules/remote-pi/dist/daemon/id.js +0 -36
  783. package/node_modules/remote-pi/dist/daemon/id.js.map +0 -1
  784. package/node_modules/remote-pi/dist/daemon/install.d.ts +0 -170
  785. package/node_modules/remote-pi/dist/daemon/install.js +0 -547
  786. package/node_modules/remote-pi/dist/daemon/install.js.map +0 -1
  787. package/node_modules/remote-pi/dist/daemon/registry.d.ts +0 -63
  788. package/node_modules/remote-pi/dist/daemon/registry.js +0 -153
  789. package/node_modules/remote-pi/dist/daemon/registry.js.map +0 -1
  790. package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +0 -194
  791. package/node_modules/remote-pi/dist/daemon/rpc_child.js +0 -389
  792. package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +0 -1
  793. package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +0 -93
  794. package/node_modules/remote-pi/dist/daemon/supervisor.js +0 -596
  795. package/node_modules/remote-pi/dist/daemon/supervisor.js.map +0 -1
  796. package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +0 -26
  797. package/node_modules/remote-pi/dist/extension_ui_bridge.js +0 -341
  798. package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +0 -1
  799. package/node_modules/remote-pi/dist/index.d.ts +0 -213
  800. package/node_modules/remote-pi/dist/index.js +0 -4996
  801. package/node_modules/remote-pi/dist/index.js.map +0 -1
  802. package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +0 -10
  803. package/node_modules/remote-pi/dist/mcp/mesh_result.js +0 -42
  804. package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +0 -1
  805. package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +0 -16
  806. package/node_modules/remote-pi/dist/mcp/mesh_server.js +0 -327
  807. package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +0 -1
  808. package/node_modules/remote-pi/dist/mesh/canonical.d.ts +0 -30
  809. package/node_modules/remote-pi/dist/mesh/canonical.js +0 -61
  810. package/node_modules/remote-pi/dist/mesh/canonical.js.map +0 -1
  811. package/node_modules/remote-pi/dist/mesh/client.d.ts +0 -18
  812. package/node_modules/remote-pi/dist/mesh/client.js +0 -125
  813. package/node_modules/remote-pi/dist/mesh/client.js.map +0 -1
  814. package/node_modules/remote-pi/dist/mesh/encoding.d.ts +0 -38
  815. package/node_modules/remote-pi/dist/mesh/encoding.js +0 -216
  816. package/node_modules/remote-pi/dist/mesh/encoding.js.map +0 -1
  817. package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +0 -73
  818. package/node_modules/remote-pi/dist/mesh/self_revoke.js +0 -401
  819. package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +0 -1
  820. package/node_modules/remote-pi/dist/mesh/siblings.d.ts +0 -49
  821. package/node_modules/remote-pi/dist/mesh/siblings.js +0 -159
  822. package/node_modules/remote-pi/dist/mesh/siblings.js.map +0 -1
  823. package/node_modules/remote-pi/dist/mesh/types.d.ts +0 -34
  824. package/node_modules/remote-pi/dist/mesh/types.js +0 -11
  825. package/node_modules/remote-pi/dist/mesh/types.js.map +0 -1
  826. package/node_modules/remote-pi/dist/mesh/verify.d.ts +0 -17
  827. package/node_modules/remote-pi/dist/mesh/verify.js +0 -86
  828. package/node_modules/remote-pi/dist/mesh/verify.js.map +0 -1
  829. package/node_modules/remote-pi/dist/pairing/crypto.d.ts +0 -8
  830. package/node_modules/remote-pi/dist/pairing/crypto.js +0 -22
  831. package/node_modules/remote-pi/dist/pairing/crypto.js.map +0 -1
  832. package/node_modules/remote-pi/dist/pairing/handshake.d.ts +0 -28
  833. package/node_modules/remote-pi/dist/pairing/handshake.js +0 -113
  834. package/node_modules/remote-pi/dist/pairing/handshake.js.map +0 -1
  835. package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +0 -16
  836. package/node_modules/remote-pi/dist/pairing/noise-sha256.js +0 -103
  837. package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +0 -1
  838. package/node_modules/remote-pi/dist/pairing/qr.d.ts +0 -59
  839. package/node_modules/remote-pi/dist/pairing/qr.js +0 -125
  840. package/node_modules/remote-pi/dist/pairing/qr.js.map +0 -1
  841. package/node_modules/remote-pi/dist/pairing/storage.d.ts +0 -120
  842. package/node_modules/remote-pi/dist/pairing/storage.js +0 -604
  843. package/node_modules/remote-pi/dist/pairing/storage.js.map +0 -1
  844. package/node_modules/remote-pi/dist/protocol/codec.d.ts +0 -7
  845. package/node_modules/remote-pi/dist/protocol/codec.js +0 -49
  846. package/node_modules/remote-pi/dist/protocol/codec.js.map +0 -1
  847. package/node_modules/remote-pi/dist/protocol/types.d.ts +0 -393
  848. package/node_modules/remote-pi/dist/protocol/types.js +0 -2
  849. package/node_modules/remote-pi/dist/protocol/types.js.map +0 -1
  850. package/node_modules/remote-pi/dist/rooms.d.ts +0 -29
  851. package/node_modules/remote-pi/dist/rooms.js +0 -57
  852. package/node_modules/remote-pi/dist/rooms.js.map +0 -1
  853. package/node_modules/remote-pi/dist/session/address.d.ts +0 -49
  854. package/node_modules/remote-pi/dist/session/address.js +0 -58
  855. package/node_modules/remote-pi/dist/session/address.js.map +0 -1
  856. package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +0 -55
  857. package/node_modules/remote-pi/dist/session/agent_bridge.js +0 -146
  858. package/node_modules/remote-pi/dist/session/agent_bridge.js.map +0 -1
  859. package/node_modules/remote-pi/dist/session/bridge.d.ts +0 -37
  860. package/node_modules/remote-pi/dist/session/bridge.js +0 -130
  861. package/node_modules/remote-pi/dist/session/bridge.js.map +0 -1
  862. package/node_modules/remote-pi/dist/session/broker.d.ts +0 -189
  863. package/node_modules/remote-pi/dist/session/broker.js +0 -507
  864. package/node_modules/remote-pi/dist/session/broker.js.map +0 -1
  865. package/node_modules/remote-pi/dist/session/broker_remote.d.ts +0 -74
  866. package/node_modules/remote-pi/dist/session/broker_remote.js +0 -583
  867. package/node_modules/remote-pi/dist/session/broker_remote.js.map +0 -1
  868. package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +0 -33
  869. package/node_modules/remote-pi/dist/session/cwd_lock.js +0 -126
  870. package/node_modules/remote-pi/dist/session/cwd_lock.js.map +0 -1
  871. package/node_modules/remote-pi/dist/session/envelope.d.ts +0 -33
  872. package/node_modules/remote-pi/dist/session/envelope.js +0 -117
  873. package/node_modules/remote-pi/dist/session/envelope.js.map +0 -1
  874. package/node_modules/remote-pi/dist/session/global_config.d.ts +0 -33
  875. package/node_modules/remote-pi/dist/session/global_config.js +0 -73
  876. package/node_modules/remote-pi/dist/session/global_config.js.map +0 -1
  877. package/node_modules/remote-pi/dist/session/ipc.d.ts +0 -27
  878. package/node_modules/remote-pi/dist/session/ipc.js +0 -22
  879. package/node_modules/remote-pi/dist/session/ipc.js.map +0 -1
  880. package/node_modules/remote-pi/dist/session/leader_election.d.ts +0 -32
  881. package/node_modules/remote-pi/dist/session/leader_election.js +0 -106
  882. package/node_modules/remote-pi/dist/session/leader_election.js.map +0 -1
  883. package/node_modules/remote-pi/dist/session/local_config.d.ts +0 -55
  884. package/node_modules/remote-pi/dist/session/local_config.js +0 -157
  885. package/node_modules/remote-pi/dist/session/local_config.js.map +0 -1
  886. package/node_modules/remote-pi/dist/session/mesh_message.d.ts +0 -20
  887. package/node_modules/remote-pi/dist/session/mesh_message.js +0 -28
  888. package/node_modules/remote-pi/dist/session/mesh_message.js.map +0 -1
  889. package/node_modules/remote-pi/dist/session/mesh_node.d.ts +0 -116
  890. package/node_modules/remote-pi/dist/session/mesh_node.js +0 -573
  891. package/node_modules/remote-pi/dist/session/mesh_node.js.map +0 -1
  892. package/node_modules/remote-pi/dist/session/peer.d.ts +0 -139
  893. package/node_modules/remote-pi/dist/session/peer.js +0 -451
  894. package/node_modules/remote-pi/dist/session/peer.js.map +0 -1
  895. package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +0 -13
  896. package/node_modules/remote-pi/dist/session/peer_inventory.js +0 -48
  897. package/node_modules/remote-pi/dist/session/peer_inventory.js.map +0 -1
  898. package/node_modules/remote-pi/dist/session/peer_limits.d.ts +0 -9
  899. package/node_modules/remote-pi/dist/session/peer_limits.js +0 -21
  900. package/node_modules/remote-pi/dist/session/peer_limits.js.map +0 -1
  901. package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +0 -39
  902. package/node_modules/remote-pi/dist/session/setup_wizard.js +0 -63
  903. package/node_modules/remote-pi/dist/session/setup_wizard.js.map +0 -1
  904. package/node_modules/remote-pi/dist/session/tool_gate.d.ts +0 -5
  905. package/node_modules/remote-pi/dist/session/tool_gate.js +0 -11
  906. package/node_modules/remote-pi/dist/session/tool_gate.js.map +0 -1
  907. package/node_modules/remote-pi/dist/session/tools.d.ts +0 -24
  908. package/node_modules/remote-pi/dist/session/tools.js +0 -252
  909. package/node_modules/remote-pi/dist/session/tools.js.map +0 -1
  910. package/node_modules/remote-pi/dist/session/wizard.d.ts +0 -13
  911. package/node_modules/remote-pi/dist/session/wizard.js +0 -20
  912. package/node_modules/remote-pi/dist/session/wizard.js.map +0 -1
  913. package/node_modules/remote-pi/dist/settings.d.ts +0 -15
  914. package/node_modules/remote-pi/dist/settings.js +0 -52
  915. package/node_modules/remote-pi/dist/settings.js.map +0 -1
  916. package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +0 -37
  917. package/node_modules/remote-pi/dist/transport/peer_channel.js +0 -98
  918. package/node_modules/remote-pi/dist/transport/peer_channel.js.map +0 -1
  919. package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +0 -29
  920. package/node_modules/remote-pi/dist/transport/pi_forward_client.js +0 -62
  921. package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +0 -1
  922. package/node_modules/remote-pi/dist/transport/relay_client.d.ts +0 -91
  923. package/node_modules/remote-pi/dist/transport/relay_client.js +0 -206
  924. package/node_modules/remote-pi/dist/transport/relay_client.js.map +0 -1
  925. package/node_modules/remote-pi/dist/ui/footer.d.ts +0 -32
  926. package/node_modules/remote-pi/dist/ui/footer.js +0 -34
  927. package/node_modules/remote-pi/dist/ui/footer.js.map +0 -1
  928. package/node_modules/remote-pi/docs/daemon.md +0 -289
  929. package/node_modules/remote-pi/package.json +0 -92
  930. package/node_modules/remote-pi/service-templates/launchd.plist.template +0 -35
  931. package/node_modules/remote-pi/service-templates/systemd.service.template +0 -19
  932. package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +0 -10
  933. package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +0 -38
  934. package/node_modules/remote-pi/skills/agent-network/SKILL.md +0 -310
@@ -0,0 +1,4533 @@
1
+ import { createRequire as __pilensCreateRequire } from "node:module"; const require = __pilensCreateRequire(import.meta.url);
2
+ import {
3
+ resolveToolCwd
4
+ } from "./chunk-IUR76K6A.js";
5
+ import {
6
+ allAvailableGlobalBinDirs,
7
+ installArgs,
8
+ pmBinary,
9
+ resolveNodePackageManager
10
+ } from "./chunk-T4QZ6FEH.js";
11
+ import {
12
+ assertInstallAllowed,
13
+ projectTrustDenialReason
14
+ } from "./chunk-D6YF5HKX.js";
15
+ import {
16
+ probeToolAsync
17
+ } from "./chunk-CMU4RMJB.js";
18
+ import {
19
+ TRANSIENT_MAX_COOLDOWN_MS,
20
+ classifyProbeFailure,
21
+ createAvailabilityLatch,
22
+ logAvailabilityDecision,
23
+ startHostStallSampler
24
+ } from "./chunk-O7HZX7CA.js";
25
+ import {
26
+ acquireBoundedPidFileLock,
27
+ acquireQuarantinePidFileLock,
28
+ createGenerationMap,
29
+ getGlobalPiLensDir,
30
+ heartbeatIntervalMs,
31
+ isLockContention,
32
+ ownsTopGeneration,
33
+ recordGenerationTakeover,
34
+ recordLegacyLockHeld,
35
+ releaseGeneration,
36
+ resetSafeSpawnWindowsCommandCache,
37
+ safeSpawnAsync,
38
+ startGenerationHeartbeat,
39
+ tryAcquireGeneration
40
+ } from "./chunk-T54VJRAD.js";
41
+ import {
42
+ DEFAULT_MAX_OUTPUT_BYTES,
43
+ createBoundedOutputSink,
44
+ writeFileAtomic,
45
+ writeFileAtomicAsync
46
+ } from "./chunk-2EECBNC5.js";
47
+ import {
48
+ getDegradationLedgerGeneration,
49
+ incrementDegradationCount,
50
+ recordDegradationOnce
51
+ } from "./chunk-7ELY2CSM.js";
52
+ import {
53
+ logExtension
54
+ } from "./chunk-34OCDWOS.js";
55
+ import {
56
+ createNdjsonLogger,
57
+ getGlobalPiLensLogDir,
58
+ getMaxLogSizeMB,
59
+ isTestMode
60
+ } from "./chunk-VSMJK3ZJ.js";
61
+ import {
62
+ BoundedLruCache
63
+ } from "./chunk-ABBOA7UD.js";
64
+ import {
65
+ findLocalToolConfig,
66
+ isFullyQualified
67
+ } from "./chunk-G3RLJYA2.js";
68
+ import {
69
+ __require
70
+ } from "./chunk-NXL4FFQQ.js";
71
+
72
+ // dist/clients/installer/index.js
73
+ import { spawn } from "node:child_process";
74
+ import { existsSync, readFileSync as readFileSync2, statSync, unlinkSync, writeFileSync } from "node:fs";
75
+ import fs2 from "node:fs/promises";
76
+ import { createHash, randomUUID } from "node:crypto";
77
+ import https from "node:https";
78
+ import { createRequire } from "node:module";
79
+ import os from "node:os";
80
+ import path3 from "node:path";
81
+ import { createGunzip } from "node:zlib";
82
+
83
+ // dist/clients/durable-store.js
84
+ import * as fs from "node:fs";
85
+ import fsp from "node:fs/promises";
86
+ function readLocked(path4) {
87
+ try {
88
+ return fs.readFileSync(path4, "utf8");
89
+ } catch {
90
+ return void 0;
91
+ }
92
+ }
93
+ function commitDurableStore(options) {
94
+ const release = options.onContention === "skip-log" ? acquireBoundedPidFileLock(`${options.path}.lock`, {
95
+ waitMs: options.waitMs,
96
+ retryMs: options.retryMs,
97
+ timeoutMessage: options.timeoutMessage,
98
+ onContention: "skip-log",
99
+ logContention: options.logContention
100
+ }) : acquireBoundedPidFileLock(`${options.path}.lock`, {
101
+ waitMs: options.waitMs,
102
+ retryMs: options.retryMs,
103
+ timeoutMessage: options.timeoutMessage,
104
+ onContention: "throw"
105
+ });
106
+ if (!release)
107
+ return void 0;
108
+ let committed;
109
+ try {
110
+ const current = options.deserialize(readLocked(options.path));
111
+ committed = options.merge(current);
112
+ writeFileAtomic(options.path, options.serialize(committed), {
113
+ bestEffort: false
114
+ });
115
+ options.afterWriteLocked?.(committed);
116
+ } finally {
117
+ release();
118
+ }
119
+ return committed;
120
+ }
121
+ async function readLockedAsync(path4) {
122
+ try {
123
+ return await fsp.readFile(path4, "utf8");
124
+ } catch (error) {
125
+ if (error.code === "ENOENT")
126
+ return void 0;
127
+ throw error;
128
+ }
129
+ }
130
+ async function commitDurableStoreAsync(options) {
131
+ const release = options.onContention === "skip-log" ? await acquireQuarantinePidFileLock(`${options.path}.lock`, {
132
+ waitMs: options.waitMs,
133
+ retryMs: options.retryMs,
134
+ staleMs: options.staleMs,
135
+ timeoutMessage: options.timeoutMessage,
136
+ onContention: "skip-log",
137
+ logContention: options.logContention
138
+ }) : await acquireQuarantinePidFileLock(`${options.path}.lock`, {
139
+ waitMs: options.waitMs,
140
+ retryMs: options.retryMs,
141
+ staleMs: options.staleMs,
142
+ timeoutMessage: options.timeoutMessage,
143
+ onContention: "throw"
144
+ });
145
+ if (!release)
146
+ return void 0;
147
+ try {
148
+ const current = options.deserialize(await readLockedAsync(options.path));
149
+ const committed = options.merge(current);
150
+ await writeFileAtomicAsync(options.path, options.serialize(committed), {
151
+ bestEffort: false
152
+ });
153
+ await options.afterWriteLocked?.(committed);
154
+ return committed;
155
+ } finally {
156
+ await release();
157
+ }
158
+ }
159
+
160
+ // dist/clients/sessionstart-logger.js
161
+ import * as path from "node:path";
162
+ var SESSIONSTART_LOG_FILE = path.join(getGlobalPiLensLogDir(), "sessionstart.log");
163
+ var writer = createNdjsonLogger({
164
+ filePath: SESSIONSTART_LOG_FILE,
165
+ maxBytes: getMaxLogSizeMB() * 1024 * 1024,
166
+ backupPath: `${SESSIONSTART_LOG_FILE}.1`
167
+ });
168
+ function logSessionStart(message) {
169
+ if (isTestMode())
170
+ return;
171
+ writer.append(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}`);
172
+ }
173
+
174
+ // dist/clients/zizmor-config.js
175
+ import * as path2 from "node:path";
176
+ var LOCAL_ZIZMOR_CONFIG_NAMES = [
177
+ path2.join(".github", "zizmor.yml"),
178
+ path2.join(".github", "zizmor.yaml"),
179
+ "zizmor.yml",
180
+ "zizmor.yaml"
181
+ ];
182
+ function findLocalZizmorConfig(startDir) {
183
+ return findLocalToolConfig(startDir, LOCAL_ZIZMOR_CONFIG_NAMES);
184
+ }
185
+ function isZizmorAuditTarget(filePath) {
186
+ const normalized = filePath.replace(/\\/g, "/");
187
+ const base = path2.basename(normalized).toLowerCase();
188
+ if (/(^|\/)\.github\/workflows\/[^/]+\.ya?ml$/i.test(normalized))
189
+ return true;
190
+ if (base === "action.yml" || base === "action.yaml")
191
+ return true;
192
+ if (/(^|\/)\.github\/dependabot\.ya?ml$/i.test(normalized))
193
+ return true;
194
+ return false;
195
+ }
196
+ var ZIZMOR_TOKEN_MAX_COOLDOWN_MS = 12e4;
197
+ var ghTokenLatch = createAvailabilityLatch({
198
+ maxCooldownMs: ZIZMOR_TOKEN_MAX_COOLDOWN_MS
199
+ });
200
+ var cachedToken;
201
+ var GH_TOKEN_PROBE_TIMEOUT_MS = 5e3;
202
+ function resetZizmorTokenAvailability() {
203
+ ghTokenLatch.reset();
204
+ cachedToken = void 0;
205
+ }
206
+ function classifyGhTokenFailure(res, hostStallMs) {
207
+ const neverAnswered = res.status === null || (res.status ?? 0) < 0;
208
+ if (!res.error && !neverAnswered) {
209
+ return {
210
+ outcome: "non-installable",
211
+ cause: "probe-rejected",
212
+ classifiedBy: "caller"
213
+ };
214
+ }
215
+ if (res.spawnFailure?.kind === "tool-not-found") {
216
+ return { outcome: "missing", cause: "not-found", classifiedBy: "caller" };
217
+ }
218
+ const classified = classifyProbeFailure(res, { hostStallMs });
219
+ if (classified.outcome === "transient" || classified.outcome === "missing") {
220
+ return { ...classified, classifiedBy: "probe" };
221
+ }
222
+ return {
223
+ outcome: "transient",
224
+ cause: classified.cause,
225
+ classifiedBy: "caller"
226
+ };
227
+ }
228
+ async function deriveGhCliToken(consumer) {
229
+ const sampler = startHostStallSampler();
230
+ const startedAt = Date.now();
231
+ const res = await safeSpawnAsync("gh", ["auth", "token"], {
232
+ timeout: GH_TOKEN_PROBE_TIMEOUT_MS,
233
+ ignoreAmbientSignal: true
234
+ });
235
+ const hostStallMs = sampler.stop();
236
+ const elapsedMs = Date.now() - startedAt;
237
+ if (!res.error && res.status === 0) {
238
+ const token = res.stdout.trim();
239
+ if (token.length > 0) {
240
+ ghTokenLatch.noteAvailable();
241
+ logAvailabilityDecision({
242
+ tool: consumer === "zizmor" ? "zizmor-gh-token" : "github-token",
243
+ verdict: "available",
244
+ outcome: "success",
245
+ cause: "ok",
246
+ elapsedMs,
247
+ latched: true,
248
+ hostStallMs,
249
+ budgetMs: GH_TOKEN_PROBE_TIMEOUT_MS,
250
+ classifiedBy: "probe"
251
+ });
252
+ return token;
253
+ }
254
+ return recordGhTokenUnavailable(consumer, {
255
+ outcome: "non-installable",
256
+ cause: "empty-result",
257
+ classifiedBy: "caller"
258
+ }, elapsedMs, hostStallMs);
259
+ }
260
+ return recordGhTokenUnavailable(consumer, classifyGhTokenFailure(res, hostStallMs), elapsedMs, hostStallMs);
261
+ }
262
+ function recordGhTokenUnavailable(consumer, { outcome, cause, classifiedBy }, elapsedMs, hostStallMs) {
263
+ const retryAfterMs = ghTokenLatch.noteUnavailable(outcome, cause);
264
+ if (consumer === "zizmor" && outcome === "transient") {
265
+ recordZizmorOfflineDegradation(`gh auth token probe ${cause}; running offline until the next zizmor start (retry allowed in ${Math.round(retryAfterMs / 1e3)}s)`);
266
+ }
267
+ logAvailabilityDecision({
268
+ tool: consumer === "zizmor" ? "zizmor-gh-token" : "github-token",
269
+ verdict: "unavailable",
270
+ outcome,
271
+ cause,
272
+ elapsedMs,
273
+ latched: outcome !== "transient",
274
+ hostStallMs,
275
+ ...retryAfterMs > 0 && { retryAfterMs },
276
+ budgetMs: GH_TOKEN_PROBE_TIMEOUT_MS,
277
+ // Shared tail for both call paths; the caller carries whether ITS
278
+ // own verdict was a `classifyProbeFailure` passthrough or one of
279
+ // this module's own assertions (#2226 review F2).
280
+ classifiedBy
281
+ });
282
+ return void 0;
283
+ }
284
+ function recordZizmorOfflineDegradation(reason) {
285
+ incrementDegradationCount({
286
+ kind: "mode-suppression",
287
+ subject: "zizmor",
288
+ reason
289
+ });
290
+ }
291
+ async function resolveZizmorGitHubToken() {
292
+ if (process.env.ZIZMOR_OFFLINE)
293
+ return void 0;
294
+ return resolveGitHubToken(["ZIZMOR_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"], { consumer: "zizmor" });
295
+ }
296
+ async function resolveGitHubToken(envKeys = ["GITHUB_TOKEN", "GH_TOKEN"], options = {}) {
297
+ const consumer = options.consumer ?? "github-api";
298
+ const fromEnv = envKeys.map((key) => process.env[key]).find(Boolean);
299
+ if (fromEnv)
300
+ return fromEnv;
301
+ const memo = ghTokenLatch.read();
302
+ if (memo !== null) {
303
+ if (consumer === "zizmor" && memo === false && ghTokenLatch.getOutcome() === "transient") {
304
+ const cause = ghTokenLatch.getCause();
305
+ if (cause === null) {
306
+ throw new Error("zizmor gh-token latch: transient outcome with no cause (invariant violated)");
307
+ }
308
+ const retryAfterMs = Math.max(0, ghTokenLatch.getRetryAtMs() - Date.now());
309
+ recordZizmorOfflineDegradation(`gh auth token still cooling down (${cause}); serving cached offline verdict, retry allowed in ${Math.round(retryAfterMs / 1e3)}s`);
310
+ logAvailabilityDecision({
311
+ tool: "zizmor-gh-token",
312
+ verdict: "unavailable",
313
+ outcome: "transient",
314
+ cause,
315
+ elapsedMs: 0,
316
+ latched: false,
317
+ hostStallMs: 0,
318
+ ...retryAfterMs > 0 && { retryAfterMs },
319
+ budgetMs: GH_TOKEN_PROBE_TIMEOUT_MS,
320
+ // No probe ran here: the latch's own remembered cause is replayed
321
+ // as-is, so the call site is the one asserting it (#2209).
322
+ classifiedBy: "caller"
323
+ });
324
+ }
325
+ return memo ? cachedToken : void 0;
326
+ }
327
+ cachedToken = await deriveGhCliToken(consumer);
328
+ return cachedToken;
329
+ }
330
+
331
+ // dist/clients/installer/index.js
332
+ var _installerRequire = createRequire(import.meta.url);
333
+ var TOOLS_DIR = path3.join(getGlobalPiLensDir(), "tools");
334
+ var INSTALL_LOCK_PATH = path3.join(TOOLS_DIR, ".install.lock");
335
+ var INSTALL_LOCK_GENERATIONS = `${INSTALL_LOCK_PATH}s`;
336
+ var activeInstallLocks = /* @__PURE__ */ new Set();
337
+ var installLockExitCleanupRegistered = false;
338
+ function getManagedToolsDir() {
339
+ return TOOLS_DIR;
340
+ }
341
+ function isProcessAlive(pid) {
342
+ try {
343
+ process.kill(pid, 0);
344
+ return true;
345
+ } catch (error) {
346
+ return error.code === "EPERM";
347
+ }
348
+ }
349
+ function installLockMaxAgeMs() {
350
+ return (Number(process.env.PI_LENS_INSTALL_TIMEOUT_MS) || 12e4) + 6e4;
351
+ }
352
+ function legacyInstallLockIsStale(maxAgeMs) {
353
+ try {
354
+ const owner = JSON.parse(readFileSync2(INSTALL_LOCK_PATH, "utf8"));
355
+ const expired = Number.isFinite(owner.createdAt) && Date.now() - owner.createdAt > maxAgeMs;
356
+ return expired || Number.isInteger(owner.pid) && owner.pid > 0 && !isProcessAlive(owner.pid);
357
+ } catch {
358
+ try {
359
+ return Date.now() - statSync(INSTALL_LOCK_PATH).mtimeMs > maxAgeMs;
360
+ } catch {
361
+ return false;
362
+ }
363
+ }
364
+ }
365
+ function createLegacyInstallLock(token) {
366
+ try {
367
+ writeFileSync(INSTALL_LOCK_PATH, token, { flag: "wx" });
368
+ return true;
369
+ } catch (cause) {
370
+ if (isLockContention(cause))
371
+ return false;
372
+ throw cause;
373
+ }
374
+ }
375
+ function takeLegacyInstallLock(maxAgeMs, token) {
376
+ if (createLegacyInstallLock(token))
377
+ return true;
378
+ if (!legacyInstallLockIsStale(maxAgeMs))
379
+ return false;
380
+ try {
381
+ unlinkSync(INSTALL_LOCK_PATH);
382
+ } catch {
383
+ return false;
384
+ }
385
+ return createLegacyInstallLock(token);
386
+ }
387
+ function installLockOwner() {
388
+ try {
389
+ const owner = JSON.parse(readFileSync2(INSTALL_LOCK_PATH, "utf8"));
390
+ return `pid=${owner.pid} createdAt=${owner.createdAt}`;
391
+ } catch {
392
+ return "unknown owner";
393
+ }
394
+ }
395
+ function tryAcquireInstallLock(maxAgeMs) {
396
+ const hold = tryAcquireGeneration(INSTALL_LOCK_GENERATIONS, maxAgeMs);
397
+ if (!hold)
398
+ return "busy";
399
+ if (hold.tookOverStale)
400
+ recordGenerationTakeover(hold);
401
+ const heartbeat = startGenerationHeartbeat(hold, heartbeatIntervalMs(maxAgeMs));
402
+ const token = JSON.stringify({
403
+ pid: process.pid,
404
+ createdAt: Date.now(),
405
+ nonce: randomUUID()
406
+ });
407
+ let took;
408
+ try {
409
+ took = takeLegacyInstallLock(maxAgeMs, token);
410
+ } catch (cause) {
411
+ heartbeat.stop();
412
+ releaseGeneration(hold);
413
+ throw cause;
414
+ }
415
+ if (took)
416
+ return { generation: hold, token, heartbeat };
417
+ heartbeat.stop();
418
+ releaseGeneration(hold);
419
+ return "legacy-held";
420
+ }
421
+ function releaseInstallLock(hold) {
422
+ activeInstallLocks.delete(hold);
423
+ hold.heartbeat.stop();
424
+ try {
425
+ if (readFileSync2(INSTALL_LOCK_PATH, "utf8") === hold.token)
426
+ unlinkSync(INSTALL_LOCK_PATH);
427
+ } catch {
428
+ }
429
+ releaseGeneration(hold.generation);
430
+ }
431
+ async function acquireInstallLock() {
432
+ const timeoutMs = Number(process.env.PI_LENS_INSTALL_LOCK_TIMEOUT_MS) || 15e4;
433
+ const deadline = Date.now() + timeoutMs;
434
+ const maxAgeMs = installLockMaxAgeMs();
435
+ let legacyHeldRecorded = false;
436
+ while (Date.now() < deadline) {
437
+ const hold = tryAcquireInstallLock(maxAgeMs);
438
+ if (hold === "legacy-held" && !legacyHeldRecorded) {
439
+ legacyHeldRecorded = true;
440
+ recordLegacyLockHeld(INSTALL_LOCK_PATH);
441
+ }
442
+ if (typeof hold === "object") {
443
+ activeInstallLocks.add(hold);
444
+ if (!installLockExitCleanupRegistered) {
445
+ installLockExitCleanupRegistered = true;
446
+ process.once("exit", () => {
447
+ for (const held of activeInstallLocks)
448
+ releaseInstallLock(held);
449
+ });
450
+ }
451
+ let released = false;
452
+ return {
453
+ release: async () => {
454
+ if (released)
455
+ return;
456
+ released = true;
457
+ releaseInstallLock(hold);
458
+ },
459
+ ownsLock: () => ownsTopGeneration(hold.generation)
460
+ };
461
+ }
462
+ await new Promise((resolve) => setTimeout(resolve, 100));
463
+ }
464
+ return {
465
+ reason: `timed out after ${timeoutMs}ms waiting for shared tools install lock (${installLockOwner()})`
466
+ };
467
+ }
468
+ var GITHUB_BIN_DIR = path3.join(getGlobalPiLensDir(), "bin");
469
+ var DEBUG = process.env.PI_LENS_DEBUG === "1" || process.argv.includes("--debug");
470
+ function installerPlatform() {
471
+ const override = process.env.PI_LENS_TEST_PLATFORM;
472
+ if (override === "win32" || override === "linux") {
473
+ return override;
474
+ }
475
+ return process.platform;
476
+ }
477
+ function debugLog(...args) {
478
+ if (DEBUG) {
479
+ logExtension({
480
+ subsystem: "auto-install",
481
+ level: "debug",
482
+ message: args.map((arg) => typeof arg === "string" ? arg : JSON.stringify(arg)).join(" ")
483
+ });
484
+ }
485
+ }
486
+ function archAssetMatch(table) {
487
+ return (platform, arch) => {
488
+ if (arch !== "x64" && arch !== "arm64")
489
+ return void 0;
490
+ return table[platform]?.[arch];
491
+ };
492
+ }
493
+ var OS_ARCH_ZIP_ASSETS = {
494
+ linux: { x64: "linux_amd64.zip", arm64: "linux_arm64.zip" },
495
+ darwin: { x64: "darwin_amd64.zip", arm64: "darwin_arm64.zip" },
496
+ win32: { x64: "windows_amd64.zip", arm64: "windows_arm64.zip" }
497
+ };
498
+ function managedPackageFormatterTool(spec) {
499
+ return {
500
+ id: spec.id,
501
+ name: spec.name,
502
+ checkCommand: spec.id,
503
+ checkArgs: ["--version"],
504
+ installStrategy: spec.installStrategy,
505
+ packageName: spec.packageName,
506
+ binaryName: spec.id
507
+ };
508
+ }
509
+ var MANAGED_PACKAGE_FORMATTERS = [
510
+ { id: "black", name: "Black", installStrategy: "pip", packageName: "black" },
511
+ {
512
+ id: "cmake-format",
513
+ name: "cmake-format",
514
+ installStrategy: "pip",
515
+ // The `yaml` EXTRA, never the bare distribution (#3312). cmakelang reads a
516
+ // `.cmake-format.yaml` project config through `import yaml`, and upstream
517
+ // puts PyYAML behind an extra: cmakelang 0.6.13's PyPI metadata declares
518
+ // `pyyaml (>=5.3) ; extra == 'yaml'`. A bare install still answers
519
+ // `cmake-format --version` with status 0 and then dies with
520
+ // `ModuleNotFoundError: No module named 'yaml'` on the first YAML config —
521
+ // the nightly's red cmake row. Every rung of the pip ladder passes this
522
+ // string verbatim to pip/pipx, which both accept the `pkg[extra]` spec.
523
+ packageName: "cmakelang[yaml]"
524
+ },
525
+ { id: "oxfmt", name: "oxfmt", installStrategy: "npm", packageName: "oxfmt" }
526
+ ];
527
+ function managedGitHubFormatterTool(spec) {
528
+ return {
529
+ id: spec.id,
530
+ name: spec.name,
531
+ checkCommand: spec.id,
532
+ checkArgs: ["--version"],
533
+ installStrategy: "github",
534
+ binaryName: spec.id,
535
+ github: {
536
+ repo: `${spec.owner}/${spec.repo}`,
537
+ assetMatch: spec.assetPattern,
538
+ ...spec.binaryInArchive && { binaryInArchive: spec.binaryInArchive },
539
+ ...spec.kind === "phar" && { launcher: "php" },
540
+ ...spec.kind === "jar" && { launcher: "java" }
541
+ }
542
+ };
543
+ }
544
+ var MANAGED_GITHUB_FORMATTERS = [
545
+ {
546
+ id: "typstyle",
547
+ name: "typstyle",
548
+ owner: "typstyle-rs",
549
+ repo: "typstyle",
550
+ assetPattern: archAssetMatch({
551
+ linux: {
552
+ x64: "typstyle-x86_64-unknown-linux-gnu",
553
+ arm64: "typstyle-aarch64-unknown-linux-gnu"
554
+ },
555
+ darwin: {
556
+ x64: "typstyle-x86_64-apple-darwin",
557
+ arm64: "typstyle-aarch64-apple-darwin"
558
+ },
559
+ win32: {
560
+ x64: "typstyle-x86_64-pc-windows-msvc.exe",
561
+ arm64: "typstyle-aarch64-pc-windows-msvc.exe"
562
+ }
563
+ }),
564
+ kind: "binary"
565
+ },
566
+ {
567
+ id: "stylua",
568
+ name: "StyLua",
569
+ owner: "JohnnyMorganz",
570
+ repo: "StyLua",
571
+ assetPattern: archAssetMatch({
572
+ linux: { x64: "linux-x86_64.zip", arm64: "linux-aarch64.zip" },
573
+ darwin: { x64: "macos-x86_64.zip", arm64: "macos-aarch64.zip" },
574
+ win32: { x64: "windows-x86_64.zip" }
575
+ }),
576
+ kind: "binary",
577
+ binaryInArchive: "stylua"
578
+ },
579
+ {
580
+ id: "php-cs-fixer",
581
+ name: "PHP CS Fixer",
582
+ owner: "PHP-CS-Fixer",
583
+ repo: "PHP-CS-Fixer",
584
+ assetPattern: (platform) => platform === "linux" || platform === "darwin" || platform === "win32" ? "php-cs-fixer.phar" : void 0,
585
+ kind: "phar"
586
+ },
587
+ {
588
+ id: "cljfmt",
589
+ name: "cljfmt",
590
+ owner: "weavejester",
591
+ repo: "cljfmt",
592
+ assetPattern: (platform, arch) => {
593
+ if (platform === "linux")
594
+ return arch === "arm64" ? "standalone.jar" : "linux-amd64-static.tar.gz";
595
+ if (platform === "darwin")
596
+ return "standalone.jar";
597
+ if (platform === "win32")
598
+ return "win-amd64.zip";
599
+ return void 0;
600
+ },
601
+ kind: "jar",
602
+ binaryInArchive: "cljfmt"
603
+ }
604
+ ];
605
+ var MANAGED_MAVEN_FORMATTERS = [
606
+ {
607
+ id: "google-java-format",
608
+ name: "google-java-format",
609
+ groupId: "com.google.googlejavaformat",
610
+ artifactId: "google-java-format",
611
+ version: "1.27.0",
612
+ classifier: "all-deps"
613
+ }
614
+ ];
615
+ function managedMavenFormatterTool(spec) {
616
+ return {
617
+ id: spec.id,
618
+ name: spec.name,
619
+ checkCommand: spec.id,
620
+ checkArgs: ["--version"],
621
+ installStrategy: "maven",
622
+ binaryName: spec.id,
623
+ maven: {
624
+ groupId: spec.groupId,
625
+ artifactId: spec.artifactId,
626
+ version: spec.version,
627
+ classifier: spec.classifier
628
+ }
629
+ };
630
+ }
631
+ var TOOLS = [
632
+ // Core LSP servers
633
+ {
634
+ id: "typescript-language-server",
635
+ name: "TypeScript Language Server",
636
+ checkCommand: "typescript-language-server",
637
+ checkArgs: ["--version"],
638
+ installStrategy: "npm",
639
+ // Pinned below the package's own floor: 6.0.0 declares
640
+ // engines.node >=22.22.2, above the pi host's own floor (pi-lens
641
+ // must never require more than pi does — #2633) — an unpinned
642
+ // install here resolves latest and prints EBADENGINE on any pi
643
+ // host's supported Node. 5.3.0's own floor is engines.node >=20.
644
+ packageName: "typescript-language-server@5.3.0",
645
+ binaryName: "typescript-language-server"
646
+ },
647
+ {
648
+ id: "typescript",
649
+ name: "TypeScript",
650
+ checkCommand: "tsc",
651
+ checkArgs: ["--version"],
652
+ installStrategy: "npm",
653
+ // The managed compiler serves the classic typescript-language-server
654
+ // fallback. TypeScript 7 removed lib/tsserver.js and is selected only from
655
+ // project-local installs through the native `tsc --lsp --stdio` path.
656
+ // Revisit when typescript-language-server supports TS 7 — refs #1436.
657
+ packageName: "typescript@5.9.3",
658
+ binaryName: "tsc"
659
+ },
660
+ {
661
+ id: "pyright",
662
+ name: "Pyright",
663
+ checkCommand: "pyright",
664
+ checkArgs: ["--version"],
665
+ installStrategy: "npm",
666
+ packageName: "pyright",
667
+ binaryName: "pyright"
668
+ },
669
+ // Linting/formatting tools
670
+ {
671
+ id: "prettier",
672
+ name: "Prettier",
673
+ checkCommand: "prettier",
674
+ checkArgs: ["--version"],
675
+ installStrategy: "npm",
676
+ packageName: "prettier",
677
+ binaryName: "prettier"
678
+ },
679
+ ...MANAGED_PACKAGE_FORMATTERS.map(managedPackageFormatterTool),
680
+ {
681
+ id: "ruff",
682
+ name: "Ruff",
683
+ checkCommand: "ruff",
684
+ checkArgs: ["--version"],
685
+ installStrategy: "pip",
686
+ packageName: "ruff",
687
+ binaryName: "ruff"
688
+ },
689
+ {
690
+ // Alternate Python LSP (fallback when pyright/the `python` server is
691
+ // unavailable or disabled). Used as a managedToolId by PythonJediServer.
692
+ id: "jedi-language-server",
693
+ name: "Jedi Language Server",
694
+ checkCommand: "jedi-language-server",
695
+ checkArgs: ["--version"],
696
+ installStrategy: "pip",
697
+ packageName: "jedi-language-server",
698
+ binaryName: "jedi-language-server"
699
+ },
700
+ {
701
+ id: "biome",
702
+ name: "Biome",
703
+ checkCommand: "biome",
704
+ checkArgs: ["--version"],
705
+ installStrategy: "npm",
706
+ packageName: "@biomejs/biome",
707
+ binaryName: "biome",
708
+ platformPackage: {
709
+ base: "@biomejs/cli",
710
+ suffixes: {
711
+ "linux-x64": "linux-x64",
712
+ "linux-arm64": "linux-arm64",
713
+ "darwin-x64": "darwin-x64",
714
+ "darwin-arm64": "darwin-arm64",
715
+ "win32-x64": "win32-x64",
716
+ "win32-arm64": "win32-arm64"
717
+ },
718
+ binaries: ["biome"]
719
+ }
720
+ },
721
+ // Analysis tools (run at session start / turn end)
722
+ {
723
+ id: "madge",
724
+ name: "Madge",
725
+ checkCommand: "madge",
726
+ checkArgs: ["--version"],
727
+ installStrategy: "npm",
728
+ packageName: "madge",
729
+ binaryName: "madge"
730
+ },
731
+ {
732
+ id: "jscpd",
733
+ name: "jscpd",
734
+ checkCommand: "jscpd",
735
+ checkArgs: ["--version"],
736
+ installStrategy: "npm",
737
+ packageName: "jscpd@5.4.0",
738
+ // v5.4.0 is the repository's exact devDependency; the v4 packaging defect that required the older v5.0.12 pin is gone, and parseReport() reads the unchanged clone-report fields.
739
+ binaryName: "jscpd"
740
+ },
741
+ // Structural search and dead code detection
742
+ {
743
+ id: "ast-grep",
744
+ name: "ast-grep CLI",
745
+ checkCommand: "ast-grep",
746
+ checkArgs: ["--version"],
747
+ installStrategy: "npm",
748
+ packageName: "@ast-grep/cli",
749
+ binaryName: "ast-grep",
750
+ platformPackage: {
751
+ suffixes: {
752
+ "linux-x64": "linux-x64-gnu",
753
+ "linux-arm64": "linux-arm64-gnu",
754
+ "darwin-x64": "darwin-x64",
755
+ "darwin-arm64": "darwin-arm64",
756
+ "win32-x64": "win32-x64-msvc",
757
+ "win32-arm64": "win32-arm64-msvc",
758
+ "win32-ia32": "win32-ia32-msvc"
759
+ },
760
+ binaries: ["ast-grep", "sg"]
761
+ }
762
+ },
763
+ {
764
+ id: "knip",
765
+ name: "Knip",
766
+ checkCommand: "knip",
767
+ checkArgs: ["--version"],
768
+ installStrategy: "npm",
769
+ packageName: "knip",
770
+ binaryName: "knip"
771
+ },
772
+ {
773
+ id: "yamllint",
774
+ name: "yamllint",
775
+ checkCommand: "yamllint",
776
+ checkArgs: ["--version"],
777
+ installStrategy: "pip",
778
+ packageName: "yamllint",
779
+ binaryName: "yamllint"
780
+ },
781
+ {
782
+ id: "sqlfluff",
783
+ name: "sqlfluff",
784
+ checkCommand: "sqlfluff",
785
+ checkArgs: ["--version"],
786
+ installStrategy: "pip",
787
+ packageName: "sqlfluff",
788
+ binaryName: "sqlfluff"
789
+ },
790
+ {
791
+ id: "bash-language-server",
792
+ name: "Bash Language Server",
793
+ checkCommand: "bash-language-server",
794
+ checkArgs: ["--version"],
795
+ // The #2188 sweep measured a 9,667ms cold `--version` start with closed
796
+ // stdin — close enough to the 10s installer default that modest host
797
+ // contention pushes it over and emits a false verification degradation.
798
+ // 20s gives the same kind of headroom Vue's 30s bound gives its own
799
+ // slower cold start (#2176), without inventing a shared literal (#2194).
800
+ verificationTimeoutMs: 2e4,
801
+ installStrategy: "npm",
802
+ packageName: "bash-language-server",
803
+ binaryName: "bash-language-server"
804
+ },
805
+ {
806
+ id: "fish-lsp",
807
+ name: "Fish Language Server",
808
+ checkCommand: "fish-lsp",
809
+ checkArgs: ["--version"],
810
+ installStrategy: "npm",
811
+ packageName: "fish-lsp",
812
+ binaryName: "fish-lsp"
813
+ },
814
+ {
815
+ id: "cmake-language-server",
816
+ name: "CMake Language Server",
817
+ checkCommand: "cmake-language-server",
818
+ checkArgs: ["--version"],
819
+ installStrategy: "pip",
820
+ packageName: "cmake-language-server",
821
+ binaryName: "cmake-language-server",
822
+ // Upstream 0.1.11 (the latest release) imports `LanguageServer` from
823
+ // `pygls.server`, a symbol pygls 2 removed, while declaring only
824
+ // `pygls>=1.1.1` — so an unconstrained install resolves pygls 2.1.1 and
825
+ // produces a launcher that cannot start. Measured against PyPI for the
826
+ // nightly's interpreter (#3311): `pip download --python-version 3.12
827
+ // cmake-language-server` → `pygls-2.1.1`; with this constraint →
828
+ // `pygls-1.3.1` + `lsprotocol-2023.0.1`, and `cmake-language-server
829
+ // --version` then prints `cmake-language-server 0.1.11` and exits 0.
830
+ pipConstraints: ["pygls<2"]
831
+ },
832
+ {
833
+ id: "yaml-language-server",
834
+ name: "YAML Language Server",
835
+ checkCommand: "yaml-language-server",
836
+ checkArgs: ["--version"],
837
+ installStrategy: "npm",
838
+ packageName: "yaml-language-server",
839
+ binaryName: "yaml-language-server"
840
+ },
841
+ {
842
+ id: "vscode-json-language-server",
843
+ name: "VSCode JSON Language Server",
844
+ checkCommand: "vscode-json-language-server",
845
+ checkArgs: ["--version"],
846
+ // The #2188 sweep measured an 11,047ms cold `--version` start with closed
847
+ // stdin — over the 10s installer default, so a cold or contended host can
848
+ // see a false verification degradation before the binary ever answers.
849
+ // 20s mirrors the bash-language-server bound above (#2194).
850
+ verificationTimeoutMs: 2e4,
851
+ installStrategy: "npm",
852
+ packageName: "vscode-langservers-extracted",
853
+ binaryName: "vscode-json-language-server"
854
+ },
855
+ {
856
+ id: "vscode-html-languageserver-bin",
857
+ name: "VSCode HTML Language Server",
858
+ checkCommand: "vscode-html-language-server",
859
+ checkArgs: ["--version"],
860
+ installStrategy: "npm",
861
+ packageName: "vscode-langservers-extracted",
862
+ binaryName: "vscode-html-language-server"
863
+ },
864
+ {
865
+ id: "htmlhint",
866
+ name: "HTMLHint",
867
+ checkCommand: "htmlhint",
868
+ checkArgs: ["--version"],
869
+ installStrategy: "npm",
870
+ packageName: "htmlhint",
871
+ binaryName: "htmlhint"
872
+ },
873
+ {
874
+ id: "hadolint",
875
+ name: "Hadolint",
876
+ checkCommand: "hadolint",
877
+ checkArgs: ["--version"],
878
+ installStrategy: "github",
879
+ binaryName: "hadolint",
880
+ github: {
881
+ repo: "hadolint/hadolint",
882
+ assetMatch: (platform, arch) => {
883
+ if (platform === "linux")
884
+ return arch === "arm64" ? "linux.aarch64" : "linux.x86_64";
885
+ if (platform === "darwin")
886
+ return arch === "arm64" ? "macos-arm64" : "macos-x86_64";
887
+ if (platform === "win32")
888
+ return "windows-x86_64.exe";
889
+ return void 0;
890
+ }
891
+ }
892
+ },
893
+ {
894
+ id: "helm",
895
+ name: "Helm",
896
+ checkCommand: "helm",
897
+ // intended: version --short — unverified against real binary (shape 16), do not wire until probed
898
+ checkArgs: ["--version"],
899
+ installStrategy: "github",
900
+ binaryName: "helm",
901
+ github: {
902
+ repo: "helm/helm",
903
+ assetMatch: (platform, arch) => {
904
+ const cpu = arch === "arm64" ? "arm64" : "amd64";
905
+ if (platform === "linux")
906
+ return `linux-${cpu}.tar.gz`;
907
+ if (platform === "darwin")
908
+ return `darwin-${cpu}.tar.gz`;
909
+ if (platform === "win32")
910
+ return `windows-${cpu}.zip`;
911
+ return void 0;
912
+ },
913
+ // Release archives nest the executable under an OS/arch directory;
914
+ // the installer searches recursively and adds the Windows suffix.
915
+ binaryInArchive: "helm"
916
+ }
917
+ },
918
+ {
919
+ // Opengrep: a single standalone binary per platform on GitHub releases —
920
+ // no login, no telemetry (the reason for switching off Semgrep, #111).
921
+ id: "opengrep",
922
+ name: "Opengrep",
923
+ checkCommand: "opengrep",
924
+ checkArgs: ["--version"],
925
+ installStrategy: "github",
926
+ binaryName: "opengrep",
927
+ github: {
928
+ repo: "opengrep/opengrep",
929
+ assetMatch: (platform, arch) => {
930
+ if (platform === "linux")
931
+ return arch === "arm64" ? "opengrep_manylinux_aarch64" : "opengrep_manylinux_x86";
932
+ if (platform === "darwin")
933
+ return arch === "arm64" ? "opengrep_osx_arm64" : "opengrep_osx_x86";
934
+ if (platform === "win32")
935
+ return "opengrep_windows_x86.exe";
936
+ return void 0;
937
+ }
938
+ }
939
+ },
940
+ {
941
+ id: "vscode-css-languageserver",
942
+ name: "VSCode CSS Language Server",
943
+ checkCommand: "vscode-css-language-server",
944
+ checkArgs: ["--version"],
945
+ installStrategy: "npm",
946
+ packageName: "vscode-langservers-extracted",
947
+ binaryName: "vscode-css-language-server"
948
+ },
949
+ {
950
+ id: "dockerfile-language-server-nodejs",
951
+ name: "Dockerfile Language Server",
952
+ checkCommand: "docker-langserver",
953
+ checkArgs: ["--version"],
954
+ installStrategy: "npm",
955
+ packageName: "dockerfile-language-server-nodejs",
956
+ binaryName: "docker-langserver"
957
+ },
958
+ {
959
+ // #2722: intelephense has no CLI — its entry calls createConnection()
960
+ // unconditionally — and Node prints the offending source line before the
961
+ // error. The bundle is one ~4 MB minified line, so the transport-required
962
+ // marker #208 rescues on lands at byte 4,154,741 of a 4,423,356-byte
963
+ // stderr while Node truncates piped stderr at 1 MiB on exit. Measured on
964
+ // intelephense@1.18.5, linux, Node v22.22.1:
965
+ // $ intelephense --version 2>&1 | wc -c -> 1048576
966
+ // $ intelephense --version 2>&1 | grep -c "Connection input stream is not set" -> 0
967
+ // $ intelephense --version 2>err.txt; wc -c < err.txt -> 4423356
968
+ // Same run over the alternatives, each with stdin closed the way
969
+ // verifyToolBinary closes it (`input: ""`):
970
+ // --help, -v, --socket=0 -> identical dump (exit 1, 4423356 bytes,
971
+ // marker at 4154741, 1048576 through a pipe, marker absent)
972
+ // --stdio -> exit 1 with ZERO bytes on either stream,
973
+ // so it carries no marker to rescue on either.
974
+ // No checkArgs value produces a verdict. Verified spawn-free instead.
975
+ id: "intelephense",
976
+ name: "Intelephense",
977
+ checkCommand: "intelephense",
978
+ checkArgs: ["--version"],
979
+ verification: "package-entry",
980
+ installStrategy: "npm",
981
+ packageName: "intelephense",
982
+ binaryName: "intelephense"
983
+ },
984
+ {
985
+ id: "@prisma/language-server",
986
+ name: "Prisma Language Server",
987
+ checkCommand: "prisma-language-server",
988
+ checkArgs: ["--version"],
989
+ // #2169: a real closed-stdin cold run measured 27,265ms, and a warm-cache
990
+ // rerun still took 9,860ms — well past the 10s installer default. 40s
991
+ // keeps the same margin-over-worst-observed ratio Vue's 30s bound uses
992
+ // (#2176) rather than trimming it for a slower binary.
993
+ verificationTimeoutMs: 4e4,
994
+ installStrategy: "npm",
995
+ packageName: "@prisma/language-server",
996
+ binaryName: "prisma-language-server"
997
+ },
998
+ {
999
+ id: "@vue/language-server",
1000
+ name: "Vue Language Server",
1001
+ checkCommand: "vue-language-server",
1002
+ checkArgs: ["--version"],
1003
+ // Vue's launcher loads the full language-service bundle before answering
1004
+ // --version. Its cold start exceeds the dispatch probe budget on some hosts
1005
+ // even though warm starts complete quickly (#2176).
1006
+ verificationTimeoutMs: 3e4,
1007
+ installStrategy: "npm",
1008
+ packageName: "@vue/language-server",
1009
+ binaryName: "vue-language-server"
1010
+ },
1011
+ {
1012
+ id: "svelte-language-server",
1013
+ name: "Svelte Language Server",
1014
+ checkCommand: "svelteserver",
1015
+ checkArgs: ["--version"],
1016
+ // #2169: a real closed-stdin cold run measured 12,410ms — over the 10s
1017
+ // installer default, matching the bash/JSON class of false verification
1018
+ // degradation from a cold-cache host (#2194). 20s mirrors that bound.
1019
+ verificationTimeoutMs: 2e4,
1020
+ installStrategy: "npm",
1021
+ packageName: "svelte-language-server",
1022
+ binaryName: "svelteserver"
1023
+ },
1024
+ {
1025
+ id: "markdownlint",
1026
+ name: "markdownlint-cli2",
1027
+ checkCommand: "markdownlint-cli2",
1028
+ // `--version` is interpreted as a file glob by markdownlint-cli2. Use
1029
+ // stdin with globs disabled so verification cannot scan the workspace.
1030
+ checkArgs: ["--no-globs", "-"],
1031
+ installStrategy: "npm",
1032
+ packageName: "markdownlint-cli2",
1033
+ binaryName: "markdownlint-cli2"
1034
+ },
1035
+ {
1036
+ id: "mypy",
1037
+ name: "mypy",
1038
+ checkCommand: "mypy",
1039
+ checkArgs: ["--version"],
1040
+ installStrategy: "pip",
1041
+ packageName: "mypy",
1042
+ binaryName: "mypy"
1043
+ },
1044
+ {
1045
+ id: "rubocop",
1046
+ name: "RuboCop",
1047
+ checkCommand: "rubocop",
1048
+ checkArgs: ["--version"],
1049
+ installStrategy: "gem",
1050
+ packageName: "rubocop",
1051
+ binaryName: "rubocop"
1052
+ },
1053
+ {
1054
+ id: "stylelint",
1055
+ name: "Stylelint",
1056
+ checkCommand: "stylelint",
1057
+ checkArgs: ["--version"],
1058
+ installStrategy: "npm",
1059
+ packageName: "stylelint",
1060
+ binaryName: "stylelint"
1061
+ },
1062
+ {
1063
+ id: "oxlint",
1064
+ name: "Oxlint",
1065
+ checkCommand: "oxlint",
1066
+ checkArgs: ["--version"],
1067
+ installStrategy: "npm",
1068
+ packageName: "oxlint",
1069
+ binaryName: "oxlint"
1070
+ },
1071
+ // GitHub release binaries
1072
+ {
1073
+ id: "shellcheck",
1074
+ name: "ShellCheck",
1075
+ checkCommand: "shellcheck",
1076
+ checkArgs: ["--version"],
1077
+ installStrategy: "github",
1078
+ binaryName: "shellcheck",
1079
+ github: {
1080
+ repo: "koalaman/shellcheck",
1081
+ assetMatch: (platform, arch) => {
1082
+ if (platform === "linux")
1083
+ return arch === "arm64" ? "linux.aarch64.tar.xz" : "linux.x86_64.tar.xz";
1084
+ if (platform === "darwin")
1085
+ return arch === "arm64" ? "darwin.aarch64.tar.xz" : "darwin.x86_64.tar.xz";
1086
+ if (platform === "win32")
1087
+ return "zip";
1088
+ return void 0;
1089
+ },
1090
+ binaryInArchive: "shellcheck"
1091
+ }
1092
+ },
1093
+ {
1094
+ id: "shfmt",
1095
+ name: "shfmt",
1096
+ checkCommand: "shfmt",
1097
+ checkArgs: ["--version"],
1098
+ installStrategy: "github",
1099
+ binaryName: "shfmt",
1100
+ github: {
1101
+ repo: "mvdan/sh",
1102
+ assetMatch: (platform, arch) => {
1103
+ if (platform === "linux")
1104
+ return arch === "arm64" ? "linux_arm64" : "linux_amd64";
1105
+ if (platform === "darwin")
1106
+ return arch === "arm64" ? "darwin_arm64" : "darwin_amd64";
1107
+ if (platform === "win32")
1108
+ return arch === "arm64" ? "windows_arm64.exe" : "windows_amd64.exe";
1109
+ return void 0;
1110
+ }
1111
+ // bare binary, no archive
1112
+ }
1113
+ },
1114
+ ...MANAGED_GITHUB_FORMATTERS.map(managedGitHubFormatterTool),
1115
+ ...MANAGED_MAVEN_FORMATTERS.map(managedMavenFormatterTool),
1116
+ {
1117
+ id: "rust-analyzer",
1118
+ name: "rust-analyzer",
1119
+ checkCommand: "rust-analyzer",
1120
+ checkArgs: ["--version"],
1121
+ installStrategy: "github",
1122
+ binaryName: "rust-analyzer",
1123
+ github: {
1124
+ repo: "rust-lang/rust-analyzer",
1125
+ assetMatch: (platform, arch) => {
1126
+ if (platform === "linux")
1127
+ return arch === "arm64" ? "aarch64-unknown-linux-gnu.gz" : "x86_64-unknown-linux-gnu.gz";
1128
+ if (platform === "darwin")
1129
+ return arch === "arm64" ? "aarch64-apple-darwin.gz" : "x86_64-apple-darwin.gz";
1130
+ if (platform === "win32")
1131
+ return "x86_64-pc-windows-msvc.zip";
1132
+ return void 0;
1133
+ }
1134
+ // Linux/macOS: bare .gz; Windows: .zip archive containing rust-analyzer.exe
1135
+ }
1136
+ },
1137
+ {
1138
+ // Alternate JS/TS LSP (fallback when the `typescript` server is unavailable
1139
+ // or disabled — e.g. Deno projects). Used as a managedToolId by DenoServer.
1140
+ // Every platform ships a .zip containing the `deno` binary (the github
1141
+ // strategy extracts it, as it does for rust-analyzer's Windows .zip).
1142
+ id: "deno",
1143
+ name: "Deno",
1144
+ checkCommand: "deno",
1145
+ checkArgs: ["--version"],
1146
+ installStrategy: "github",
1147
+ binaryName: "deno",
1148
+ github: {
1149
+ repo: "denoland/deno",
1150
+ assetMatch: (platform, arch) => {
1151
+ if (platform === "linux")
1152
+ return arch === "arm64" ? "deno-aarch64-unknown-linux-gnu.zip" : "deno-x86_64-unknown-linux-gnu.zip";
1153
+ if (platform === "darwin")
1154
+ return arch === "arm64" ? "deno-aarch64-apple-darwin.zip" : "deno-x86_64-apple-darwin.zip";
1155
+ if (platform === "win32")
1156
+ return "deno-x86_64-pc-windows-msvc.zip";
1157
+ return void 0;
1158
+ }
1159
+ }
1160
+ },
1161
+ {
1162
+ id: "golangci-lint",
1163
+ name: "golangci-lint",
1164
+ checkCommand: "golangci-lint",
1165
+ checkArgs: ["--version"],
1166
+ installStrategy: "github",
1167
+ binaryName: "golangci-lint",
1168
+ github: {
1169
+ repo: "golangci/golangci-lint",
1170
+ assetMatch: (platform, arch) => {
1171
+ if (platform === "linux")
1172
+ return arch === "arm64" ? "linux-arm64.tar.gz" : "linux-amd64.tar.gz";
1173
+ if (platform === "darwin")
1174
+ return arch === "arm64" ? "darwin-arm64.tar.gz" : "darwin-amd64.tar.gz";
1175
+ if (platform === "win32")
1176
+ return arch === "arm64" ? "windows-arm64.zip" : "windows-amd64.zip";
1177
+ return void 0;
1178
+ },
1179
+ binaryInArchive: "golangci-lint"
1180
+ }
1181
+ },
1182
+ {
1183
+ id: "ktlint",
1184
+ name: "ktlint",
1185
+ checkCommand: "ktlint",
1186
+ checkArgs: ["--version"],
1187
+ installStrategy: "github",
1188
+ binaryName: "ktlint",
1189
+ github: {
1190
+ // ktlint ships a self-executable `ktlint` (a JAR with a shell preamble)
1191
+ // for Linux/macOS, plus a `ktlint.bat` wrapper for Windows that runs
1192
+ // `java -jar %~dp0ktlint`. On Windows BOTH files are needed: the .bat AND
1193
+ // the `ktlint` jar it wraps (#218). No arm64-specific asset.
1194
+ repo: "pinterest/ktlint",
1195
+ assetMatch: (platform, _arch) => {
1196
+ if (platform === "linux")
1197
+ return "ktlint";
1198
+ if (platform === "darwin")
1199
+ return "ktlint";
1200
+ if (platform === "win32")
1201
+ return "ktlint.bat";
1202
+ return void 0;
1203
+ },
1204
+ extraAssets: (platform) => platform === "win32" ? ["ktlint"] : []
1205
+ }
1206
+ },
1207
+ {
1208
+ // ktfmt (Meta's opinionated Kotlin formatter) ships only as a Maven-Central
1209
+ // fat JAR — no native binary, no npm package — so it uses the maven strategy
1210
+ // (#129). Run via a `java -jar` launcher; requires a JRE.
1211
+ id: "ktfmt",
1212
+ name: "ktfmt",
1213
+ checkCommand: "ktfmt",
1214
+ checkArgs: ["--version"],
1215
+ installStrategy: "maven",
1216
+ binaryName: "ktfmt",
1217
+ maven: {
1218
+ groupId: "com.facebook",
1219
+ artifactId: "ktfmt",
1220
+ version: "0.63",
1221
+ classifier: "with-dependencies"
1222
+ }
1223
+ },
1224
+ {
1225
+ // SpotBugs (bytecode bug-pattern analyzer for Java/Kotlin/Scala/Groovy)
1226
+ // ships as a distribution archive — a lib/ of many JARs + bin/ launchers,
1227
+ // NOT a runnable fat JAR — so it uses the archive strategy, not maven
1228
+ // (refs #133). Requires a JRE (gated by the runner, not the install).
1229
+ id: "spotbugs",
1230
+ name: "SpotBugs",
1231
+ checkCommand: "spotbugs",
1232
+ // intended: -version — unverified against real binary (shape 16), do not wire until probed
1233
+ checkArgs: ["--version"],
1234
+ installStrategy: "archive",
1235
+ binaryName: "spotbugs",
1236
+ archive: {
1237
+ url: "https://github.com/spotbugs/spotbugs/releases/download/4.10.2/spotbugs-4.10.2.tgz",
1238
+ kind: "tgz",
1239
+ launcher: "bin/spotbugs",
1240
+ sha256: {
1241
+ "https://github.com/spotbugs/spotbugs/releases/download/4.10.2/spotbugs-4.10.2.tgz": "63d7687c35fba12cbc8e55ec2a889a2bbf1b9be299dea91f2b0d351dc285308a"
1242
+ }
1243
+ }
1244
+ },
1245
+ {
1246
+ // kotlin-language-server (fwcd, #3400) — a platform-agnostic launcher ZIP
1247
+ // (`server/{bin,lib}`, 87 MB) whose `bin/kotlin-language-server` script
1248
+ // starts a JVM on ANY argument and has no stable `--version`, so it is
1249
+ // verified at install by manifest, not by spawn: the pinned sha256, the
1250
+ // launcher on disk with an exec bit, and `java` on PATH or JAVA_HOME before
1251
+ // the download (`verification: "tree-manifest"`). The 2025 release publishes
1252
+ // no digest, so its pin is trust-on-first-use (the hash of the download). The initialize handshake is the nightly
1253
+ // tool-smoke `kotlin` row. fwcd 1.3.13 (2025-01-18) rather than JetBrains'
1254
+ // kotlin-lsp (v263.4702.0): its CDN ships the macOS standalone archives as
1255
+ // `.sit`, which this installer's tar/unzip/Expand-Archive paths cannot
1256
+ // extract, and its six per-platform archives would need six pins.
1257
+ id: "kotlin-language-server",
1258
+ name: "Kotlin Language Server",
1259
+ checkCommand: "kotlin-language-server",
1260
+ checkArgs: ["--version"],
1261
+ installStrategy: "archive",
1262
+ binaryName: "kotlin-language-server",
1263
+ verification: "tree-manifest",
1264
+ archive: {
1265
+ url: "https://github.com/fwcd/kotlin-language-server/releases/download/1.3.13/server.zip",
1266
+ kind: "zip",
1267
+ launcher: "bin/kotlin-language-server",
1268
+ runtime: "java",
1269
+ sha256: {
1270
+ "https://github.com/fwcd/kotlin-language-server/releases/download/1.3.13/server.zip": "4fe7d71d087b307c7869036171bd9d8c6a4284cd7c25b89098b0a24eb2d9b6d2"
1271
+ }
1272
+ }
1273
+ },
1274
+ {
1275
+ // PowerShell Editor Services (#278). NOT a single binary — a multi-folder
1276
+ // PowerShell MODULE BUNDLE launched via `pwsh Start-EditorServices.ps1
1277
+ // -Stdio` (see PowerShellServer.spawn). archive TREE BUNDLE: the release zip
1278
+ // extracts sibling module dirs (PowerShellEditorServices/, PSReadLine/,
1279
+ // PSScriptAnalyzer/) at the root with no wrapping dir, so stripComponents:0
1280
+ // + no launcher — the whole tree is kept and resolved to its extract dir.
1281
+ // checkCommand "pwsh" documents the runtime but is unused for resolution
1282
+ // (tree bundles resolve only via the extract dir + treeMarker).
1283
+ id: "powershell-editor-services",
1284
+ name: "PowerShell Editor Services",
1285
+ checkCommand: "pwsh",
1286
+ checkArgs: [
1287
+ "-NoProfile",
1288
+ "-Command",
1289
+ "$PSVersionTable.PSVersion.ToString()"
1290
+ ],
1291
+ installStrategy: "archive",
1292
+ binaryName: "powershell-editor-services",
1293
+ archive: {
1294
+ url: "https://github.com/PowerShell/PowerShellEditorServices/releases/download/v4.6.0/PowerShellEditorServices.zip",
1295
+ kind: "zip",
1296
+ stripComponents: 0,
1297
+ treeMarker: "PowerShellEditorServices/Start-EditorServices.ps1",
1298
+ sha256: {
1299
+ "https://github.com/PowerShell/PowerShellEditorServices/releases/download/v4.6.0/PowerShellEditorServices.zip": "0d91898f73d4faeb64291336f6386f0c890a933df012827571adf7008480a04a"
1300
+ }
1301
+ }
1302
+ },
1303
+ {
1304
+ // clangd (C/C++/Obj-C LSP, #241) — a self-contained native TREE BUNDLE: the
1305
+ // release zip wraps `clangd_<ver>/{bin,lib}` (bin/clangd[.exe] + the bundled
1306
+ // libclang headers under lib/), so stripComponents:1 drops the version dir and
1307
+ // the whole tree is kept (no launcher). Unlike PSES there is no external
1308
+ // runtime — CppServer launches `<bundle>/bin/clangd` directly. checkCommand
1309
+ // documents the binary but is unused for resolution (tree bundles resolve only
1310
+ // via the extract dir + treeMarker). Platform-matched url: clangd ships x64
1311
+ // prebuilts; arm runs the x64 build under Rosetta/emulation (darwin/win32),
1312
+ // while linux/arm64 has no official build → undefined (graceful unavailable).
1313
+ id: "clangd",
1314
+ name: "clangd",
1315
+ checkCommand: "clangd",
1316
+ checkArgs: ["--version"],
1317
+ installStrategy: "archive",
1318
+ binaryName: "clangd",
1319
+ archive: {
1320
+ url: (platform, arch) => {
1321
+ const version = "22.1.0";
1322
+ const base = `https://github.com/clangd/clangd/releases/download/${version}`;
1323
+ if (platform === "linux")
1324
+ return arch === "x64" ? `${base}/clangd-linux-${version}.zip` : void 0;
1325
+ if (platform === "darwin")
1326
+ return `${base}/clangd-mac-${version}.zip`;
1327
+ if (platform === "win32")
1328
+ return `${base}/clangd-windows-${version}.zip`;
1329
+ return void 0;
1330
+ },
1331
+ kind: "zip",
1332
+ stripComponents: 1,
1333
+ treeMarker: "bin",
1334
+ sha256: {
1335
+ "https://github.com/clangd/clangd/releases/download/22.1.0/clangd-linux-22.1.0.zip": "c54e57dbff3ccc9e8352367ddb7030ad3f624073ec58c7477424e7919f578572",
1336
+ "https://github.com/clangd/clangd/releases/download/22.1.0/clangd-mac-22.1.0.zip": "71eddc5303da9a5bc5e8b509488b5b2c5acf45f20e33b8394e71a12a56d67198",
1337
+ "https://github.com/clangd/clangd/releases/download/22.1.0/clangd-windows-22.1.0.zip": "e31e271fe11f6dcd7cf87ca74be4a12788ff8ce5a0b07762583e335c058e939a"
1338
+ }
1339
+ }
1340
+ },
1341
+ {
1342
+ // lua-language-server (#564, split from #241) — same self-contained native
1343
+ // TREE BUNDLE shape as clangd: bin/lua-language-server[.exe] + bundled
1344
+ // locale/meta files, no external runtime. UNLIKE clangd, the release
1345
+ // archive has NO wrapping version dir (verified by inspecting the actual
1346
+ // 3.18.2 linux-x64 .tar.gz and win32-x64 .zip contents: `bin/`, `LICENSE`,
1347
+ // `locale/`, … sit at archive root) — so stripComponents:0, not 1.
1348
+ // LuaServer launches `<bundle>/bin/lua-language-server` directly.
1349
+ // checkCommand documents the binary but is unused for resolution (tree
1350
+ // bundles resolve only via the extract dir + treeMarker). Platform-matched
1351
+ // url: LuaLS publishes darwin/linux x64+arm64 and win32 x64 (no win32/arm64
1352
+ // build as of 3.18.2 → undefined, graceful unavailable); asset naming
1353
+ // verified against the live GitHub release listing, not guessed.
1354
+ id: "lua-language-server",
1355
+ name: "lua-language-server",
1356
+ checkCommand: "lua-language-server",
1357
+ checkArgs: ["--version"],
1358
+ installStrategy: "archive",
1359
+ binaryName: "lua-language-server",
1360
+ archive: {
1361
+ url: (platform, arch) => {
1362
+ const version = "3.18.2";
1363
+ const base = `https://github.com/LuaLS/lua-language-server/releases/download/${version}`;
1364
+ if (platform === "linux")
1365
+ return arch === "arm64" ? `${base}/lua-language-server-${version}-linux-arm64.tar.gz` : `${base}/lua-language-server-${version}-linux-x64.tar.gz`;
1366
+ if (platform === "darwin")
1367
+ return arch === "arm64" ? `${base}/lua-language-server-${version}-darwin-arm64.tar.gz` : `${base}/lua-language-server-${version}-darwin-x64.tar.gz`;
1368
+ if (platform === "win32")
1369
+ return arch === "arm64" ? void 0 : `${base}/lua-language-server-${version}-win32-x64.zip`;
1370
+ return void 0;
1371
+ },
1372
+ kind: (platform) => platform === "win32" ? "zip" : "tgz",
1373
+ stripComponents: 0,
1374
+ treeMarker: "bin",
1375
+ sha256: {
1376
+ "https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-linux-arm64.tar.gz": "273af33f26f4a1143f27c96d9f9e1188aba619c71e0807042134f66b4bd27f24",
1377
+ "https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-linux-x64.tar.gz": "ca71415dd19f19e30aaa35a4915aefca9fdb5fec31b98331cc3d77f778d539c5",
1378
+ "https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-darwin-arm64.tar.gz": "cec99d70b1f612acec4a10a79a03664e3aa0c229d4d8a586cb3f928ec37d509e",
1379
+ "https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-darwin-x64.tar.gz": "e26cfefe423dd7326fc7c649539e4d4aaa4f35f34d2fefd8af2ed7090b72c556",
1380
+ "https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-win32-x64.zip": "a4439a8f5e8e9e6505c11f045a7bf45db602124a1e246371c1dbe34924f3cf71"
1381
+ }
1382
+ }
1383
+ },
1384
+ {
1385
+ id: "actionlint",
1386
+ name: "actionlint",
1387
+ checkCommand: "actionlint",
1388
+ checkArgs: ["--version"],
1389
+ installStrategy: "github",
1390
+ binaryName: "actionlint",
1391
+ github: {
1392
+ repo: "rhysd/actionlint",
1393
+ assetMatch: (platform, arch) => {
1394
+ if (platform === "linux")
1395
+ return arch === "arm64" ? "linux_arm64.tar.gz" : "linux_amd64.tar.gz";
1396
+ if (platform === "darwin")
1397
+ return arch === "arm64" ? "darwin_arm64.tar.gz" : "darwin_amd64.tar.gz";
1398
+ if (platform === "win32")
1399
+ return arch === "arm64" ? "windows_arm64.zip" : "windows_amd64.zip";
1400
+ return void 0;
1401
+ },
1402
+ binaryInArchive: "actionlint"
1403
+ }
1404
+ },
1405
+ {
1406
+ // zizmor: GitHub Actions workflow security scanner that speaks LSP (#272).
1407
+ // cargo-dist release archives, one per target triple, each holding a single
1408
+ // `zizmor` binary (extracted via the recursive binary find). Online audits
1409
+ // (known-vulnerable-actions, unpinned-uses, …) need a GitHub token — the LSP
1410
+ // spawn forwards one via resolveZizmorGitHubToken (clients/zizmor-config.ts).
1411
+ id: "zizmor",
1412
+ name: "zizmor",
1413
+ checkCommand: "zizmor",
1414
+ checkArgs: ["--version"],
1415
+ installStrategy: "github",
1416
+ binaryName: "zizmor",
1417
+ github: {
1418
+ repo: "zizmorcore/zizmor",
1419
+ assetMatch: (platform, arch) => {
1420
+ if (platform === "linux")
1421
+ return arch === "arm64" ? "aarch64-unknown-linux-gnu.tar.gz" : "x86_64-unknown-linux-gnu.tar.gz";
1422
+ if (platform === "darwin")
1423
+ return arch === "arm64" ? "aarch64-apple-darwin.tar.gz" : "x86_64-apple-darwin.tar.gz";
1424
+ if (platform === "win32")
1425
+ return "x86_64-pc-windows-msvc.zip";
1426
+ return void 0;
1427
+ },
1428
+ binaryInArchive: "zizmor"
1429
+ }
1430
+ },
1431
+ {
1432
+ // typos-lsp: source-code spell checker that speaks LSP (#283). cargo-dist
1433
+ // release archives, one per target triple, each holding a single `typos-lsp`
1434
+ // binary (extracted via the recursive binary find). NO token / network — the
1435
+ // dictionary is compiled in. The binary takes no `--version` (it ignores args
1436
+ // and serves the LSP on stdin/stdout); the PATH probe ignores checkArgs and
1437
+ // verifyToolBinary runs with stdin:ignore so the server gets EOF and exits.
1438
+ id: "typos-lsp",
1439
+ name: "typos-lsp",
1440
+ checkCommand: "typos-lsp",
1441
+ checkArgs: ["--version"],
1442
+ installStrategy: "github",
1443
+ binaryName: "typos-lsp",
1444
+ github: {
1445
+ repo: "tekumara/typos-lsp",
1446
+ assetMatch: (platform, arch) => {
1447
+ if (platform === "linux")
1448
+ return arch === "arm64" ? "aarch64-unknown-linux-gnu.tar.gz" : "x86_64-unknown-linux-gnu.tar.gz";
1449
+ if (platform === "darwin")
1450
+ return arch === "arm64" ? "aarch64-apple-darwin.tar.gz" : "x86_64-apple-darwin.tar.gz";
1451
+ if (platform === "win32")
1452
+ return arch === "arm64" ? "aarch64-pc-windows-msvc.zip" : "x86_64-pc-windows-msvc.zip";
1453
+ return void 0;
1454
+ },
1455
+ binaryInArchive: "typos-lsp"
1456
+ }
1457
+ },
1458
+ {
1459
+ id: "tflint",
1460
+ name: "tflint",
1461
+ checkCommand: "tflint",
1462
+ checkArgs: ["--version"],
1463
+ installStrategy: "github",
1464
+ binaryName: "tflint",
1465
+ github: {
1466
+ repo: "terraform-linters/tflint",
1467
+ assetMatch: archAssetMatch(OS_ARCH_ZIP_ASSETS),
1468
+ binaryInArchive: "tflint"
1469
+ }
1470
+ },
1471
+ {
1472
+ // Terragrunt ships a bare native binary per platform on GitHub releases.
1473
+ // Windows arm64 uses the x64 binary through Windows' built-in emulation —
1474
+ // there is no terragrunt_windows_arm64.exe upstream.
1475
+ id: "terragrunt",
1476
+ name: "terragrunt",
1477
+ checkCommand: "terragrunt",
1478
+ checkArgs: ["--version"],
1479
+ installStrategy: "github",
1480
+ binaryName: "terragrunt",
1481
+ github: {
1482
+ repo: "gruntwork-io/terragrunt",
1483
+ assetMatch: archAssetMatch({
1484
+ linux: {
1485
+ x64: "terragrunt_linux_amd64",
1486
+ arm64: "terragrunt_linux_arm64"
1487
+ },
1488
+ darwin: {
1489
+ x64: "terragrunt_darwin_amd64",
1490
+ arm64: "terragrunt_darwin_arm64"
1491
+ },
1492
+ win32: {
1493
+ x64: "terragrunt_windows_amd64.exe",
1494
+ arm64: "terragrunt_windows_amd64.exe"
1495
+ }
1496
+ })
1497
+ // bare binary — no binaryInArchive
1498
+ }
1499
+ },
1500
+ {
1501
+ id: "gitleaks",
1502
+ name: "gitleaks",
1503
+ checkCommand: "gitleaks",
1504
+ // intended: version — unverified against real binary (shape 16), do not wire until probed
1505
+ checkArgs: ["--version"],
1506
+ installStrategy: "github",
1507
+ binaryName: "gitleaks",
1508
+ github: {
1509
+ repo: "gitleaks/gitleaks",
1510
+ // gitleaks asset naming uses `x64` not `amd64` (unlike most Go-built
1511
+ // tools). Substring match is exact-enough — release assets are
1512
+ // named e.g. `gitleaks_8.18.4_linux_x64.tar.gz`.
1513
+ assetMatch: archAssetMatch({
1514
+ linux: { x64: "linux_x64.tar.gz", arm64: "linux_arm64.tar.gz" },
1515
+ darwin: { x64: "darwin_x64.tar.gz", arm64: "darwin_arm64.tar.gz" },
1516
+ win32: { x64: "windows_x64.zip", arm64: "windows_arm64.zip" }
1517
+ }),
1518
+ binaryInArchive: "gitleaks"
1519
+ }
1520
+ },
1521
+ {
1522
+ id: "trivy",
1523
+ name: "Trivy",
1524
+ checkCommand: "trivy",
1525
+ checkArgs: ["--version"],
1526
+ installStrategy: "github",
1527
+ binaryName: "trivy",
1528
+ github: {
1529
+ repo: "aquasecurity/trivy",
1530
+ // Trivy asset naming is `trivy_<ver>_<OS>-<bits>.{tar.gz,zip}` with a
1531
+ // capitalized OS and `64bit`/`ARM64` arch tokens — e.g.
1532
+ // `trivy_0.71.2_Linux-64bit.tar.gz`, `trivy_0.71.2_macOS-ARM64.tar.gz`.
1533
+ // No windows-arm64 asset exists (win32.arm64 omitted), so (like
1534
+ // swiftlint) trivy is absent from GITHUB_TOOLS and covered by the
1535
+ // weaker "at least one platform" guard.
1536
+ assetMatch: archAssetMatch({
1537
+ linux: { x64: "Linux-64bit.tar.gz", arm64: "Linux-ARM64.tar.gz" },
1538
+ darwin: { x64: "macOS-64bit.tar.gz", arm64: "macOS-ARM64.tar.gz" },
1539
+ win32: { x64: "windows-64bit.zip" }
1540
+ }),
1541
+ binaryInArchive: "trivy"
1542
+ }
1543
+ },
1544
+ {
1545
+ id: "swiftlint",
1546
+ name: "SwiftLint",
1547
+ checkCommand: "swiftlint",
1548
+ checkArgs: ["--version"],
1549
+ installStrategy: "github",
1550
+ binaryName: "swiftlint",
1551
+ github: {
1552
+ repo: "realm/SwiftLint",
1553
+ assetMatch: (platform, arch) => {
1554
+ if (platform === "darwin")
1555
+ return "portable_swiftlint.zip";
1556
+ if (platform === "linux")
1557
+ return arch === "arm64" ? "swiftlint_linux_arm64.zip" : "swiftlint_linux_amd64.zip";
1558
+ return void 0;
1559
+ },
1560
+ binaryInArchive: "swiftlint"
1561
+ }
1562
+ },
1563
+ {
1564
+ id: "taplo",
1565
+ name: "taplo",
1566
+ checkCommand: "taplo",
1567
+ checkArgs: ["--version"],
1568
+ installStrategy: "github",
1569
+ binaryName: "taplo",
1570
+ github: {
1571
+ repo: "tamasfe/taplo",
1572
+ assetMatch: (platform, arch) => {
1573
+ if (platform === "linux")
1574
+ return arch === "arm64" ? "taplo-linux-aarch64.gz" : "taplo-linux-x86_64.gz";
1575
+ if (platform === "darwin")
1576
+ return arch === "arm64" ? "taplo-darwin-aarch64.gz" : "taplo-darwin-x86_64.gz";
1577
+ if (platform === "win32")
1578
+ return "taplo-windows-x86_64.gz";
1579
+ return void 0;
1580
+ }
1581
+ }
1582
+ },
1583
+ {
1584
+ id: "vale",
1585
+ name: "Vale",
1586
+ checkCommand: "vale",
1587
+ checkArgs: ["--version"],
1588
+ installStrategy: "github",
1589
+ binaryName: "vale",
1590
+ github: {
1591
+ repo: "vale-cli/vale",
1592
+ assetMatch: (platform, arch) => {
1593
+ const version = "3.14.2";
1594
+ if (platform === "linux")
1595
+ return arch === "arm64" ? `vale_${version}_Linux_arm64.tar.gz` : `vale_${version}_Linux_64-bit.tar.gz`;
1596
+ if (platform === "darwin")
1597
+ return arch === "arm64" ? `vale_${version}_macOS_arm64.tar.gz` : `vale_${version}_macOS_64-bit.tar.gz`;
1598
+ if (platform === "win32")
1599
+ return `vale_${version}_Windows_64-bit.zip`;
1600
+ return void 0;
1601
+ },
1602
+ binaryInArchive: "vale"
1603
+ }
1604
+ },
1605
+ {
1606
+ id: "terraform-ls",
1607
+ name: "terraform-ls",
1608
+ checkCommand: "terraform-ls",
1609
+ // intended: version — unverified against real binary (shape 16), do not wire until probed
1610
+ checkArgs: ["--version"],
1611
+ installStrategy: "github",
1612
+ binaryName: "terraform-ls",
1613
+ github: {
1614
+ repo: "hashicorp/terraform-ls",
1615
+ hashiCorpReleaseProduct: "terraform-ls",
1616
+ assetMatch: archAssetMatch(OS_ARCH_ZIP_ASSETS),
1617
+ binaryInArchive: "terraform-ls"
1618
+ }
1619
+ },
1620
+ {
1621
+ id: "zls",
1622
+ name: "zls",
1623
+ checkCommand: "zls",
1624
+ checkArgs: ["--version"],
1625
+ installStrategy: "github",
1626
+ binaryName: "zls",
1627
+ github: {
1628
+ repo: "zigtools/zls",
1629
+ assetMatch: (platform, arch) => {
1630
+ if (platform === "linux")
1631
+ return arch === "arm64" ? "aarch64-linux.tar.xz" : "x86_64-linux.tar.xz";
1632
+ if (platform === "darwin")
1633
+ return arch === "arm64" ? "aarch64-macos.tar.xz" : "x86_64-macos.tar.xz";
1634
+ if (platform === "win32")
1635
+ return arch === "arm64" ? "aarch64-windows.zip" : "x86_64-windows.zip";
1636
+ return void 0;
1637
+ },
1638
+ binaryInArchive: "zls"
1639
+ }
1640
+ },
1641
+ {
1642
+ // clojure-lsp ships a self-contained native (GraalVM) binary per platform
1643
+ // on GitHub releases — no JVM needed. Used as managedToolId by ClojureServer.
1644
+ // The .zip carries the bare binary (located recursively on extract).
1645
+ id: "clojure-lsp",
1646
+ name: "clojure-lsp",
1647
+ checkCommand: "clojure-lsp",
1648
+ checkArgs: ["--version"],
1649
+ installStrategy: "github",
1650
+ binaryName: "clojure-lsp",
1651
+ github: {
1652
+ repo: "clojure-lsp/clojure-lsp",
1653
+ assetMatch: (platform, arch) => {
1654
+ if (platform === "linux")
1655
+ return arch === "arm64" ? "native-linux-aarch64.zip" : "native-linux-amd64.zip";
1656
+ if (platform === "darwin")
1657
+ return arch === "arm64" ? "native-macos-aarch64.zip" : "native-macos-amd64.zip";
1658
+ if (platform === "win32")
1659
+ return "native-windows-amd64.zip";
1660
+ return void 0;
1661
+ },
1662
+ binaryInArchive: "clojure-lsp"
1663
+ }
1664
+ },
1665
+ {
1666
+ // CUE ships a single native binary per platform on GitHub releases;
1667
+ // the LSP runs via `cue lsp serve`. Used as managedToolId by CueServer.
1668
+ id: "cue",
1669
+ name: "CUE",
1670
+ checkCommand: "cue",
1671
+ // Probed locally with CUE v0.17.1: `cue version` exits 0.
1672
+ checkArgs: ["version"],
1673
+ installStrategy: "github",
1674
+ binaryName: "cue",
1675
+ github: {
1676
+ repo: "cue-lang/cue",
1677
+ assetMatch: (platform, arch) => {
1678
+ if (platform === "linux")
1679
+ return arch === "arm64" ? "linux_arm64.tar.gz" : "linux_amd64.tar.gz";
1680
+ if (platform === "darwin")
1681
+ return arch === "arm64" ? "darwin_arm64.tar.gz" : "darwin_amd64.tar.gz";
1682
+ if (platform === "win32")
1683
+ return arch === "arm64" ? "windows_arm64.zip" : "windows_amd64.zip";
1684
+ return void 0;
1685
+ },
1686
+ binaryInArchive: "cue"
1687
+ }
1688
+ },
1689
+ {
1690
+ // gleam ships a single static binary per platform on GitHub releases; the
1691
+ // LSP runs via `gleam lsp`. Used as managedToolId by GleamServer. The linux
1692
+ // build is a FLAT musl tarball (a bare `gleam`), handled by the recursive
1693
+ // tar-binary lookup in installGitHubTool.
1694
+ id: "gleam",
1695
+ name: "Gleam",
1696
+ checkCommand: "gleam",
1697
+ checkArgs: ["--version"],
1698
+ installStrategy: "github",
1699
+ binaryName: "gleam",
1700
+ github: {
1701
+ repo: "gleam-lang/gleam",
1702
+ assetMatch: (platform, arch) => {
1703
+ if (platform === "linux")
1704
+ return arch === "arm64" ? "aarch64-unknown-linux-musl.tar.gz" : "x86_64-unknown-linux-musl.tar.gz";
1705
+ if (platform === "darwin")
1706
+ return arch === "arm64" ? "aarch64-apple-darwin.tar.gz" : "x86_64-apple-darwin.tar.gz";
1707
+ if (platform === "win32")
1708
+ return arch === "arm64" ? "aarch64-pc-windows-msvc.zip" : "x86_64-pc-windows-msvc.zip";
1709
+ return void 0;
1710
+ },
1711
+ binaryInArchive: "gleam"
1712
+ }
1713
+ },
1714
+ {
1715
+ // Tinymist publishes cargo-dist archives containing the `tinymist` binary
1716
+ // for the supported desktop targets. The LSP server uses `tinymist lsp`.
1717
+ id: "tinymist",
1718
+ name: "Tinymist",
1719
+ checkCommand: "tinymist",
1720
+ checkArgs: ["--version"],
1721
+ installStrategy: "github",
1722
+ binaryName: "tinymist",
1723
+ github: {
1724
+ repo: "Myriad-Dreamin/tinymist",
1725
+ assetMatch: archAssetMatch({
1726
+ linux: {
1727
+ x64: "tinymist-x86_64-unknown-linux-gnu.tar.gz",
1728
+ arm64: "tinymist-aarch64-unknown-linux-gnu.tar.gz"
1729
+ },
1730
+ darwin: {
1731
+ x64: "tinymist-x86_64-apple-darwin.tar.gz",
1732
+ arm64: "tinymist-aarch64-apple-darwin.tar.gz"
1733
+ },
1734
+ win32: {
1735
+ x64: "tinymist-x86_64-pc-windows-msvc.zip",
1736
+ arm64: "tinymist-aarch64-pc-windows-msvc.zip"
1737
+ }
1738
+ }),
1739
+ binaryInArchive: "tinymist"
1740
+ }
1741
+ },
1742
+ {
1743
+ // marksman ships a single BARE (uncompressed) binary per platform on GitHub
1744
+ // releases — no archive, so it lands via the bare-binary branch of
1745
+ // installGitHubTool (the `else` that writes the asset directly, like shfmt).
1746
+ // Used as managedToolId by MarksmanServer; LSP entrypoint is `marksman
1747
+ // server` (stdio). macOS ships a universal binary; Windows has only x64
1748
+ // (runs on arm64 via emulation) — so all six platform/arch combos resolve.
1749
+ id: "marksman",
1750
+ name: "Marksman",
1751
+ checkCommand: "marksman",
1752
+ checkArgs: ["--version"],
1753
+ installStrategy: "github",
1754
+ binaryName: "marksman",
1755
+ github: {
1756
+ repo: "artempyanykh/marksman",
1757
+ assetMatch: (platform, arch) => {
1758
+ if (platform === "linux")
1759
+ return arch === "arm64" ? "marksman-linux-arm64" : "marksman-linux-x64";
1760
+ if (platform === "darwin")
1761
+ return "marksman-macos";
1762
+ if (platform === "win32")
1763
+ return "marksman.exe";
1764
+ return void 0;
1765
+ }
1766
+ // bare binary — no binaryInArchive
1767
+ }
1768
+ },
1769
+ {
1770
+ // Expert ships a bare native binary per platform on GitHub releases. Its
1771
+ // `--stdio` flag is required to start the LSP transport. Windows arm64 uses
1772
+ // the x64 binary through Windows' built-in x64 emulation.
1773
+ id: "expert",
1774
+ name: "Expert",
1775
+ checkCommand: "expert",
1776
+ checkArgs: ["--version"],
1777
+ installStrategy: "github",
1778
+ binaryName: "expert",
1779
+ github: {
1780
+ repo: "expert-lsp/expert",
1781
+ assetMatch: (platform, arch) => {
1782
+ if (arch !== "x64" && arch !== "arm64")
1783
+ return void 0;
1784
+ if (platform === "linux")
1785
+ return arch === "arm64" ? "expert_linux_arm64" : "expert_linux_amd64";
1786
+ if (platform === "darwin")
1787
+ return arch === "arm64" ? "expert_darwin_arm64" : "expert_darwin_amd64";
1788
+ if (platform === "win32")
1789
+ return "expert_windows_amd64.exe";
1790
+ return void 0;
1791
+ }
1792
+ // bare binary — no binaryInArchive
1793
+ }
1794
+ }
1795
+ ];
1796
+ function getToolVerificationTimeout(tool) {
1797
+ return tool.verificationTimeoutMs ?? 1e4;
1798
+ }
1799
+ var ensureInFlight = /* @__PURE__ */ new Map();
1800
+ var installFailureReasons = /* @__PURE__ */ new Map();
1801
+ function getInstallFailureReason(toolId) {
1802
+ return installFailureReasons.get(toolId);
1803
+ }
1804
+ var installAttempts = /* @__PURE__ */ new Map();
1805
+ function noteInstallAttempt(toolId, outcome, reason) {
1806
+ installAttempts.set(toolId, { outcome, reason, at: Date.now() });
1807
+ }
1808
+ function noteInstallAttemptIfUnrecorded(toolId, outcome, reason) {
1809
+ if (installAttempts.has(toolId))
1810
+ return;
1811
+ noteInstallAttempt(toolId, outcome, reason);
1812
+ }
1813
+ function getInstallAttempt(toolId) {
1814
+ return installAttempts.get(toolId);
1815
+ }
1816
+ var lastEnsureResolutionSource = /* @__PURE__ */ new Map();
1817
+ function getLastEnsureResolutionSource(toolId) {
1818
+ return lastEnsureResolutionSource.get(toolId);
1819
+ }
1820
+ var resolvedPathCache = new BoundedLruCache(256);
1821
+ function resetResolvedPathCache() {
1822
+ resolvedPathCache.clear();
1823
+ }
1824
+ var PROBE_CACHE_PATH = path3.join(getGlobalPiLensDir(), "probe-cache.json");
1825
+ var PROBE_CACHE_LOCK_STALE_MS = 18e4;
1826
+ var PROBE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
1827
+ var PROBE_CACHE_TRANSIENT_COOLDOWN_MS = TRANSIENT_MAX_COOLDOWN_MS;
1828
+ var PROBE_CACHE_FLUSH_LOCK_WAIT_MS = 250;
1829
+ var PROBE_CACHE_FLUSH_RETRY_DELAY_MS = 300;
1830
+ var PROBE_CACHE_FLUSH_RETRY_MAX_DELAY_MS = 3e4;
1831
+ var _probeCache = null;
1832
+ var _probeCacheDirty = false;
1833
+ var _probeCacheFlushTimer = null;
1834
+ var _probeCacheWriteInFlight = null;
1835
+ var _probeCacheRetryAttempt = 0;
1836
+ var _probeCacheChangeGeneration = 0;
1837
+ var _probeCacheChanges = /* @__PURE__ */ new Map();
1838
+ var _probeCacheChangeVersions = /* @__PURE__ */ new Map();
1839
+ async function readProbeCache() {
1840
+ if (_probeCache !== null)
1841
+ return _probeCache;
1842
+ try {
1843
+ const raw = await fs2.readFile(PROBE_CACHE_PATH, "utf-8");
1844
+ const parsed = JSON.parse(raw);
1845
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1846
+ throw new Error("probe-cache root is not an object");
1847
+ }
1848
+ _probeCache = parsed;
1849
+ } catch (err) {
1850
+ const code = err?.code;
1851
+ if (code !== "ENOENT") {
1852
+ logSessionStart(`auto-install probe-cache: read failed (${code ?? "invalid"}); treating cache as unavailable`);
1853
+ }
1854
+ _probeCache = {};
1855
+ }
1856
+ return _probeCache;
1857
+ }
1858
+ function markProbeCacheChange(toolId, entry) {
1859
+ _probeCacheChanges.set(toolId, entry);
1860
+ _probeCacheChangeVersions.set(toolId, ++_probeCacheChangeGeneration);
1861
+ _probeCacheDirty = true;
1862
+ scheduleProbeFlush();
1863
+ }
1864
+ function scheduleProbeFlush(delayMs = PROBE_CACHE_FLUSH_RETRY_DELAY_MS) {
1865
+ if (_probeCacheFlushTimer !== null)
1866
+ return;
1867
+ _probeCacheFlushTimer = setTimeout(() => {
1868
+ void flushProbeCache();
1869
+ }, delayMs);
1870
+ _probeCacheFlushTimer.unref?.();
1871
+ }
1872
+ function scheduleProbeFlushRetry() {
1873
+ const delay = Math.min(PROBE_CACHE_FLUSH_RETRY_MAX_DELAY_MS, PROBE_CACHE_FLUSH_RETRY_DELAY_MS * 2 ** Math.min(_probeCacheRetryAttempt, 6));
1874
+ _probeCacheRetryAttempt += 1;
1875
+ scheduleProbeFlush(delay);
1876
+ }
1877
+ function snapshotProbeCacheChanges() {
1878
+ return {
1879
+ changes: new Map(_probeCacheChanges),
1880
+ versions: new Map(_probeCacheChangeVersions)
1881
+ };
1882
+ }
1883
+ function deserializeProbeCache(contents) {
1884
+ if (contents === void 0)
1885
+ return {};
1886
+ try {
1887
+ const parsed = JSON.parse(contents);
1888
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1889
+ throw new Error("probe-cache root is not an object");
1890
+ }
1891
+ return parsed;
1892
+ } catch (err) {
1893
+ logSessionStart(`auto-install probe-cache: write-side read was corrupt (${err.message}); recovering as empty`);
1894
+ return {};
1895
+ }
1896
+ }
1897
+ function applyProbeCacheChanges(disk, changes) {
1898
+ for (const [toolId, entry] of changes) {
1899
+ if (entry === null)
1900
+ delete disk[toolId];
1901
+ else
1902
+ disk[toolId] = entry;
1903
+ }
1904
+ }
1905
+ function ageProbeCache(disk) {
1906
+ const now = Date.now();
1907
+ for (const [toolId, entry] of Object.entries(disk)) {
1908
+ const ttl = entry.transient ? PROBE_CACHE_TRANSIENT_COOLDOWN_MS : PROBE_CACHE_TTL_MS;
1909
+ if (!Number.isFinite(entry.cachedAt) || entry.cachedAt < now - ttl) {
1910
+ delete disk[toolId];
1911
+ }
1912
+ }
1913
+ }
1914
+ function publishProbeCacheWrite(disk, snapshotVersions) {
1915
+ const pendingAfterWrite = new Map(_probeCacheChanges);
1916
+ _probeCache = disk;
1917
+ for (const [toolId, entry] of pendingAfterWrite) {
1918
+ if (entry === null)
1919
+ delete _probeCache[toolId];
1920
+ else
1921
+ _probeCache[toolId] = entry;
1922
+ }
1923
+ for (const [toolId, version] of snapshotVersions) {
1924
+ if (_probeCacheChangeVersions.get(toolId) === version) {
1925
+ _probeCacheChanges.delete(toolId);
1926
+ _probeCacheChangeVersions.delete(toolId);
1927
+ }
1928
+ }
1929
+ _probeCacheDirty = _probeCacheChanges.size > 0;
1930
+ _probeCacheRetryAttempt = 0;
1931
+ return _probeCacheDirty ? "written-with-pending" : "written";
1932
+ }
1933
+ async function writeProbeCache() {
1934
+ try {
1935
+ const { changes, versions } = snapshotProbeCacheChanges();
1936
+ let result = "written";
1937
+ const committed = await commitDurableStoreAsync({
1938
+ path: PROBE_CACHE_PATH,
1939
+ deserialize: deserializeProbeCache,
1940
+ merge: (disk) => {
1941
+ ageProbeCache(disk);
1942
+ applyProbeCacheChanges(disk, changes);
1943
+ return disk;
1944
+ },
1945
+ serialize: (disk) => JSON.stringify(disk, null, 2),
1946
+ waitMs: PROBE_CACHE_FLUSH_LOCK_WAIT_MS,
1947
+ retryMs: 25,
1948
+ staleMs: PROBE_CACHE_LOCK_STALE_MS,
1949
+ timeoutMessage: "Timed out waiting for probe-cache lock",
1950
+ onContention: "skip-log",
1951
+ logContention: () => {
1952
+ logSessionStart("auto-install probe-cache: flush deferred because another process owns the lock");
1953
+ },
1954
+ afterWriteLocked: (disk) => {
1955
+ result = publishProbeCacheWrite(disk, versions);
1956
+ }
1957
+ });
1958
+ if (committed === void 0) {
1959
+ scheduleProbeFlushRetry();
1960
+ return "deferred";
1961
+ }
1962
+ return result;
1963
+ } catch (err) {
1964
+ logSessionStart(`auto-install probe-cache: flush failed (${err?.code ?? "write error"}); pending update retained`);
1965
+ scheduleProbeFlushRetry();
1966
+ return "failed";
1967
+ }
1968
+ }
1969
+ async function flushProbeCache() {
1970
+ if (_probeCacheFlushTimer !== null) {
1971
+ clearTimeout(_probeCacheFlushTimer);
1972
+ _probeCacheFlushTimer = null;
1973
+ }
1974
+ if (_probeCacheWriteInFlight) {
1975
+ await _probeCacheWriteInFlight;
1976
+ if (!_probeCacheDirty)
1977
+ return "written";
1978
+ }
1979
+ if (!_probeCacheDirty || _probeCache === null)
1980
+ return "idle";
1981
+ const write = writeProbeCache();
1982
+ _probeCacheWriteInFlight = write;
1983
+ try {
1984
+ return await write;
1985
+ } finally {
1986
+ if (_probeCacheWriteInFlight === write)
1987
+ _probeCacheWriteInFlight = null;
1988
+ }
1989
+ }
1990
+ function isAstGrepVersionOutput(output) {
1991
+ return /\bast[- ]grep\b/i.test(output);
1992
+ }
1993
+ async function verifyAstGrepProbePath(binPath) {
1994
+ const result = await probeToolAsync(binPath, ["--version"], {
1995
+ timeout: 5e3
1996
+ });
1997
+ return !result.error && result.status === 0 && isAstGrepVersionOutput(`${result.stdout}${result.stderr}`);
1998
+ }
1999
+ async function checkProbeCache(toolId) {
2000
+ const cache = await readProbeCache();
2001
+ const entry = cache[toolId];
2002
+ if (!entry)
2003
+ return void 0;
2004
+ const ttl = entry.transient ? PROBE_CACHE_TRANSIENT_COOLDOWN_MS : PROBE_CACHE_TTL_MS;
2005
+ if (Date.now() - entry.cachedAt > ttl) {
2006
+ logSessionStart(`auto-install probe-cache ${toolId}: miss (${entry.transient ? "transient cooldown" : "ttl"} expired)`);
2007
+ delete cache[toolId];
2008
+ markProbeCacheChange(toolId, null);
2009
+ return void 0;
2010
+ }
2011
+ try {
2012
+ await fs2.access(entry.path);
2013
+ const stat = await fs2.stat(entry.path);
2014
+ if (stat.mtimeMs !== entry.mtimeMs || entry.sizeBytes !== void 0 && stat.size !== entry.sizeBytes) {
2015
+ logSessionStart(`auto-install probe-cache ${toolId}: miss (mtime/size changed)`);
2016
+ delete cache[toolId];
2017
+ markProbeCacheChange(toolId, null);
2018
+ return void 0;
2019
+ }
2020
+ if (toolId === "ast-grep" && !await verifyAstGrepProbePath(entry.path)) {
2021
+ logSessionStart(`auto-install probe-cache ${toolId}: miss (not ast-grep: ${entry.path})`);
2022
+ delete cache[toolId];
2023
+ markProbeCacheChange(toolId, null);
2024
+ return void 0;
2025
+ }
2026
+ return entry.path;
2027
+ } catch {
2028
+ logSessionStart(`auto-install probe-cache ${toolId}: miss (gone: ${entry.path})`);
2029
+ delete cache[toolId];
2030
+ markProbeCacheChange(toolId, null);
2031
+ return void 0;
2032
+ }
2033
+ }
2034
+ async function updateProbeCache(toolId, resolvedPath, transient = false) {
2035
+ try {
2036
+ const stat = await fs2.stat(resolvedPath);
2037
+ const cache = await readProbeCache();
2038
+ const entry = {
2039
+ path: resolvedPath,
2040
+ mtimeMs: stat.mtimeMs,
2041
+ sizeBytes: stat.size,
2042
+ cachedAt: Date.now(),
2043
+ ...transient && { transient: true }
2044
+ };
2045
+ cache[toolId] = entry;
2046
+ markProbeCacheChange(toolId, entry);
2047
+ } catch {
2048
+ }
2049
+ }
2050
+ function resetProbeCacheStateForTesting() {
2051
+ _probeCache = null;
2052
+ _probeCacheDirty = false;
2053
+ _probeCacheChanges.clear();
2054
+ _probeCacheChangeVersions.clear();
2055
+ _probeCacheChangeGeneration = 0;
2056
+ _probeCacheRetryAttempt = 0;
2057
+ resetResolvedPathCache();
2058
+ ensureInFlight.clear();
2059
+ installFailureReasons.clear();
2060
+ installAttempts.clear();
2061
+ lastEnsureResolutionSource.clear();
2062
+ lastManagedInstallVersion.clear();
2063
+ lastResolveTransient.clear();
2064
+ resetPathWalkMemo();
2065
+ if (_probeCacheFlushTimer !== null) {
2066
+ clearTimeout(_probeCacheFlushTimer);
2067
+ _probeCacheFlushTimer = null;
2068
+ }
2069
+ }
2070
+ function _peekEnsureInFlightForTesting() {
2071
+ return ensureInFlight;
2072
+ }
2073
+ var pathWalkMemo = /* @__PURE__ */ new Map();
2074
+ function hashSync(value) {
2075
+ let hash = 2166136261;
2076
+ for (let i = 0; i < value.length; i += 1) {
2077
+ hash ^= value.charCodeAt(i);
2078
+ hash = Math.imul(hash, 16777619);
2079
+ }
2080
+ return (hash >>> 0).toString(16);
2081
+ }
2082
+ function resetPathWalkMemo() {
2083
+ pathWalkMemo.clear();
2084
+ }
2085
+ async function isCommandAvailable(command, _args) {
2086
+ const isWindows = installerPlatform() === "win32";
2087
+ const pathEnv = process.env.PATH || process.env.Path || process.env.path || "";
2088
+ const dirs = pathEnv.split(path3.delimiter);
2089
+ const names = isWindows ? [command, `${command}.exe`, `${command}.cmd`, `${command}.bat`] : [command];
2090
+ for (const dir of dirs) {
2091
+ if (!dir)
2092
+ continue;
2093
+ for (const name of names) {
2094
+ const candidate = path3.join(dir, name);
2095
+ try {
2096
+ const stat = statSync(candidate);
2097
+ if (stat.isFile() && stat.size > 0) {
2098
+ return true;
2099
+ }
2100
+ } catch {
2101
+ }
2102
+ }
2103
+ }
2104
+ return false;
2105
+ }
2106
+ async function isSpawnableCommand(command) {
2107
+ if (/[\\/]/.test(command)) {
2108
+ try {
2109
+ const stat = statSync(command);
2110
+ return stat.isFile() && stat.size > 0;
2111
+ } catch {
2112
+ return false;
2113
+ }
2114
+ }
2115
+ const memoKey = `${command}:${hashSync(process.env.PATH || "")}`;
2116
+ if (pathWalkMemo.has(memoKey))
2117
+ return pathWalkMemo.get(memoKey) ?? false;
2118
+ const isSpawnable = await isCommandAvailable(command);
2119
+ pathWalkMemo.set(memoKey, isSpawnable);
2120
+ return isSpawnable;
2121
+ }
2122
+ function isLspTransportRequiredError(output) {
2123
+ return /Connection (?:input|output) stream is not set|Use arguments of createConnection/i.test(output);
2124
+ }
2125
+ var lspTransportRequiredMatcher = /Connection (?:input|output) stream is not set|Use arguments of createConnection/i;
2126
+ function parsePinnedVersion(packageName) {
2127
+ const at = packageName.lastIndexOf("@");
2128
+ if (at <= 0)
2129
+ return void 0;
2130
+ return packageName.slice(at + 1) || void 0;
2131
+ }
2132
+ function extractVersionToken(output) {
2133
+ return output.match(/\d+\.\d+\.\d+(?:[-+][\w.]+)?/)?.[0];
2134
+ }
2135
+ var lastManagedInstallVersion = /* @__PURE__ */ new Map();
2136
+ function packageEntryVerification(tool) {
2137
+ return tool.verification === "package-entry" ? tool.packageName : void 0;
2138
+ }
2139
+ async function verifyNpmPackageEntry(binPath, packageName) {
2140
+ const nodeModulesDir = path3.dirname(path3.dirname(binPath));
2141
+ const pinned = parsePinnedVersion(packageName);
2142
+ const bareName = pinned ? packageName.slice(0, -(pinned.length + 1)) : packageName;
2143
+ const packageDir = path3.join(nodeModulesDir, ...bareName.split("/"));
2144
+ const shimName = path3.basename(binPath).replace(/\.(cmd|exe|ps1|bat)$/i, "").toLowerCase();
2145
+ const fail = (reason) => {
2146
+ logSessionStart(`auto-install verify: failed for ${binPath} (check=package-entry, kind=${reason})`);
2147
+ return false;
2148
+ };
2149
+ try {
2150
+ const shim = statSync(binPath);
2151
+ if (!shim.isFile() || shim.size === 0)
2152
+ return fail("shim-not-a-file");
2153
+ } catch {
2154
+ return fail("shim-missing");
2155
+ }
2156
+ let manifest;
2157
+ try {
2158
+ manifest = JSON.parse(await fs2.readFile(path3.join(packageDir, "package.json"), "utf8"));
2159
+ } catch {
2160
+ return fail("package-json-unreadable");
2161
+ }
2162
+ if (typeof manifest.version !== "string" || !manifest.version) {
2163
+ return fail("package-json-no-version");
2164
+ }
2165
+ const bin = manifest.bin;
2166
+ const entry = typeof bin === "string" ? bin : bin && typeof bin === "object" ? Object.entries(bin).find(
2167
+ // Case-folded on purpose: on a case-insensitive filesystem the
2168
+ // shim on disk can differ in case from the manifest key npm
2169
+ // wrote it from, and `path.basename` reads the disk name.
2170
+ ([name]) => name.toLowerCase() === shimName
2171
+ )?.[1] : void 0;
2172
+ if (typeof entry !== "string" || !entry) {
2173
+ return fail("package-json-no-entry");
2174
+ }
2175
+ try {
2176
+ const stat = statSync(path3.join(packageDir, entry));
2177
+ if (!stat.isFile() || stat.size === 0)
2178
+ return fail("entry-not-a-file");
2179
+ } catch {
2180
+ return fail("entry-missing");
2181
+ }
2182
+ logSessionStart(`auto-install verify: succeeded for ${binPath} (check=package-entry, version=${manifest.version}, entry=${entry})`);
2183
+ return true;
2184
+ }
2185
+ async function verifyToolBinary(binPath, onVersionOutput, onTransient, timeoutMs = 1e4, verificationArgs = ["--version"], packageEntryOf, onInconclusive) {
2186
+ if (packageEntryOf !== void 0) {
2187
+ return verifyNpmPackageEntry(binPath, packageEntryOf);
2188
+ }
2189
+ const isWindows = installerPlatform() === "win32";
2190
+ const hasKnownWindowsExt = /\.(cmd|exe|ps1)$/i.test(binPath);
2191
+ let execPath = isWindows && !hasKnownWindowsExt ? `${binPath}.cmd` : binPath;
2192
+ if (isWindows && /\.ps1$/i.test(execPath)) {
2193
+ const cmdSibling = `${execPath.slice(0, -4)}.cmd`;
2194
+ if (__require("node:fs").existsSync(cmdSibling)) {
2195
+ execPath = cmdSibling;
2196
+ }
2197
+ }
2198
+ const useShell = isWindows && /\.(cmd|bat)$/i.test(execPath);
2199
+ void useShell;
2200
+ try {
2201
+ const result = await safeSpawnAsync(execPath, verificationArgs, {
2202
+ timeout: timeoutMs,
2203
+ input: "",
2204
+ // A broken or version-blind language server can emit a bundled
2205
+ // megabytes-long diagnostic on stderr. Keep verification bounded even
2206
+ // when the child reaches its normal timeout first.
2207
+ maxOutputBytes: 64 * 1024,
2208
+ matchWhileStreaming: lspTransportRequiredMatcher
2209
+ });
2210
+ const output = `${result.stdout}
2211
+ ${result.stderr}`;
2212
+ if (result.outputTruncated) {
2213
+ recordDegradationOnce({
2214
+ kind: "installer-verification-output-truncated",
2215
+ subject: binPath,
2216
+ reason: `verification output exceeded 65536 bytes (${verificationArgs.join(" ")})`
2217
+ });
2218
+ }
2219
+ if (result.status === 0 && !result.error) {
2220
+ debugLog(`Verified: ${binPath} (${verificationArgs.join(" ")}: ${result.stdout.trim()})`);
2221
+ onVersionOutput?.(result.stdout);
2222
+ return true;
2223
+ }
2224
+ if (result.streamingMatch || isLspTransportRequiredError(output)) {
2225
+ debugLog(`Verified (stdio LSP, transport-required): ${binPath}`);
2226
+ return true;
2227
+ }
2228
+ if (result.signal !== void 0 || result.spawnFailure)
2229
+ onTransient?.();
2230
+ if (result.outputTruncated && result.signal === void 0 && !result.spawnFailure) {
2231
+ onInconclusive?.();
2232
+ recordDegradationOnce({
2233
+ kind: "installer-verification-inconclusive",
2234
+ subject: binPath,
2235
+ reason: `transport-required marker unresolved in truncated output (${verificationArgs.join(" ")})`
2236
+ });
2237
+ }
2238
+ const kind = result.spawnFailure?.kind ?? (result.signal ? `killed-signal=${result.signal}` : result.error ? "spawn-error" : "exit-nonzero");
2239
+ logSessionStart(`auto-install verify: failed for ${binPath} (check=${verificationArgs.join(" ")}, kind=${kind}${result.status !== null ? `, exit=${result.status}` : ""})`);
2240
+ return false;
2241
+ } catch (err) {
2242
+ logSessionStart(`auto-install verify: spawn threw for ${binPath} (${err instanceof Error ? err.message : String(err)})`);
2243
+ onTransient?.();
2244
+ return false;
2245
+ }
2246
+ }
2247
+ async function getAllToolStatuses() {
2248
+ const statuses = [];
2249
+ for (const tool of TOOLS) {
2250
+ const status = {
2251
+ id: tool.id,
2252
+ name: tool.name,
2253
+ installed: false,
2254
+ source: "not-installed",
2255
+ strategy: tool.installStrategy
2256
+ };
2257
+ if (tool.installStrategy === "archive" && !tool.archive?.launcher) {
2258
+ const bundleDir = await getArchiveTreeBundlePath(tool);
2259
+ if (bundleDir) {
2260
+ status.installed = true;
2261
+ status.source = "archive-dist";
2262
+ status.path = bundleDir;
2263
+ }
2264
+ statuses.push(status);
2265
+ continue;
2266
+ }
2267
+ if (await isCommandAvailable(tool.checkCommand, tool.checkArgs)) {
2268
+ status.installed = true;
2269
+ status.source = "global-path";
2270
+ status.path = tool.checkCommand;
2271
+ if (tool.verification !== "tree-manifest") {
2272
+ const probe = await probeToolAsync(tool.checkCommand, ["--version"], {
2273
+ timeout: 5e3
2274
+ });
2275
+ status.version = `${probe.stdout}${probe.stderr}`.trim().split("\n")[0]?.slice(0, 30) || void 0;
2276
+ }
2277
+ statuses.push(status);
2278
+ continue;
2279
+ }
2280
+ if (tool.installStrategy === "npm") {
2281
+ const npmPath = await findNpmGlobalToolPath(tool.binaryName || tool.id, void 0, tool.checkArgs, getToolVerificationTimeout(tool));
2282
+ if (npmPath) {
2283
+ status.installed = true;
2284
+ status.source = "npm-global";
2285
+ status.path = npmPath;
2286
+ statuses.push(status);
2287
+ continue;
2288
+ }
2289
+ }
2290
+ if (tool.installStrategy === "pip") {
2291
+ const pipPath = await findPipUserToolPath(tool.binaryName || tool.id, void 0, tool.checkArgs, getToolVerificationTimeout(tool));
2292
+ if (pipPath) {
2293
+ status.installed = true;
2294
+ status.source = "pip-user";
2295
+ status.path = pipPath;
2296
+ statuses.push(status);
2297
+ continue;
2298
+ }
2299
+ }
2300
+ if (tool.installStrategy === "github" || tool.installStrategy === "maven" || tool.installStrategy === "archive") {
2301
+ const githubPath = await findGitHubToolPath(tool.binaryName || tool.id);
2302
+ if (githubPath) {
2303
+ status.installed = true;
2304
+ status.source = tool.installStrategy === "maven" ? "maven-jar" : tool.installStrategy === "archive" ? "archive-dist" : "github-release";
2305
+ status.path = githubPath;
2306
+ statuses.push(status);
2307
+ continue;
2308
+ }
2309
+ }
2310
+ const localBase = path3.join(TOOLS_DIR, "node_modules", ".bin", tool.binaryName || tool.id);
2311
+ const localPath = installerPlatform() === "win32" ? `${localBase}.cmd` : localBase;
2312
+ try {
2313
+ await fs2.access(localPath);
2314
+ if (await verifyToolBinary(localPath, void 0, void 0, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
2315
+ status.installed = true;
2316
+ status.source = "pi-lens-auto";
2317
+ status.path = localPath;
2318
+ statuses.push(status);
2319
+ continue;
2320
+ }
2321
+ } catch {
2322
+ }
2323
+ if (tool.installStrategy === "npm") {
2324
+ status.source = "npx-fallback";
2325
+ }
2326
+ statuses.push(status);
2327
+ }
2328
+ return statuses;
2329
+ }
2330
+ async function isToolInstalled(toolId) {
2331
+ return await getToolPath(toolId) !== void 0;
2332
+ }
2333
+ async function getArchiveTreeBundlePath(tool) {
2334
+ if (tool.installStrategy !== "archive" || tool.archive?.launcher) {
2335
+ return void 0;
2336
+ }
2337
+ const extractDir = path3.join(TOOLS_DIR, tool.id);
2338
+ const marker = tool.archive?.treeMarker ? path3.join(extractDir, ...tool.archive.treeMarker.split("/")) : extractDir;
2339
+ try {
2340
+ await fs2.access(marker);
2341
+ return extractDir;
2342
+ } catch {
2343
+ return void 0;
2344
+ }
2345
+ }
2346
+ function resolvePlatformPackageBinary(tool) {
2347
+ const spec = tool.platformPackage;
2348
+ if (!spec || !tool.packageName)
2349
+ return void 0;
2350
+ const suffix = spec.suffixes[`${installerPlatform()}-${process.arch}`];
2351
+ if (!suffix)
2352
+ return void 0;
2353
+ const platformPkg = `${spec.base ?? tool.packageName}-${suffix}`;
2354
+ try {
2355
+ const mainPkgJson = _installerRequire.resolve(`${tool.packageName}/package.json`);
2356
+ const fromMain = createRequire(mainPkgJson);
2357
+ let pkgDir;
2358
+ try {
2359
+ pkgDir = path3.dirname(fromMain.resolve(`${platformPkg}/package.json`));
2360
+ } catch {
2361
+ pkgDir = path3.dirname(_installerRequire.resolve(`${platformPkg}/package.json`));
2362
+ }
2363
+ const isWin = installerPlatform() === "win32";
2364
+ for (const bin of spec.binaries) {
2365
+ for (const name of isWin ? [`${bin}.exe`, bin] : [bin]) {
2366
+ const candidate = path3.join(pkgDir, name);
2367
+ if (existsSync(candidate))
2368
+ return candidate;
2369
+ }
2370
+ }
2371
+ } catch {
2372
+ }
2373
+ return void 0;
2374
+ }
2375
+ var lastResolveTransient = /* @__PURE__ */ new Map();
2376
+ var lastInstallResolutionId = /* @__PURE__ */ new Map();
2377
+ function wasLastResolveTransient(toolId) {
2378
+ return lastResolveTransient.get(toolId) ?? false;
2379
+ }
2380
+ async function getToolPath(toolId) {
2381
+ let sawTransient = false;
2382
+ const markTransient = () => {
2383
+ sawTransient = true;
2384
+ };
2385
+ const result = await getToolPathResolved(toolId, markTransient);
2386
+ lastResolveTransient.set(toolId, sawTransient);
2387
+ return result;
2388
+ }
2389
+ async function getToolPathResolved(toolId, onTransient) {
2390
+ const tool = TOOLS.find((t) => t.id === toolId);
2391
+ if (!tool)
2392
+ return void 0;
2393
+ if (tool.installStrategy === "archive" && !tool.archive?.launcher) {
2394
+ return getArchiveTreeBundlePath(tool);
2395
+ }
2396
+ const pinnedVersion = tool.installStrategy === "npm" && tool.packageName ? parsePinnedVersion(tool.packageName) : void 0;
2397
+ if (pinnedVersion)
2398
+ lastManagedInstallVersion.delete(toolId);
2399
+ const recordVersion = pinnedVersion ? (output) => {
2400
+ const seen = extractVersionToken(output);
2401
+ if (seen)
2402
+ lastManagedInstallVersion.set(toolId, seen);
2403
+ } : void 0;
2404
+ const localBase = path3.join(TOOLS_DIR, "node_modules", ".bin", tool.binaryName || tool.id);
2405
+ if (installerPlatform() === "win32") {
2406
+ const cmdPath = `${localBase}.cmd`;
2407
+ try {
2408
+ await fs2.access(cmdPath);
2409
+ if (await verifyToolBinary(cmdPath, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
2410
+ return cmdPath;
2411
+ }
2412
+ logSessionStart(`auto-install verify: ${cmdPath} exists but is broken, will reinstall`);
2413
+ } catch {
2414
+ }
2415
+ const exePath = `${localBase}.exe`;
2416
+ try {
2417
+ await fs2.access(exePath);
2418
+ if (await verifyToolBinary(exePath, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
2419
+ return exePath;
2420
+ }
2421
+ logSessionStart(`auto-install verify: ${exePath} exists but is broken, will reinstall`);
2422
+ } catch {
2423
+ }
2424
+ }
2425
+ if (installerPlatform() !== "win32") {
2426
+ try {
2427
+ await fs2.access(localBase);
2428
+ if (await verifyToolBinary(localBase, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
2429
+ return localBase;
2430
+ }
2431
+ logSessionStart(`auto-install verify: ${localBase} exists but is broken, will reinstall`);
2432
+ } catch {
2433
+ }
2434
+ }
2435
+ if (tool.platformPackage) {
2436
+ const platformBin = resolvePlatformPackageBinary(tool);
2437
+ if (platformBin && await verifyToolBinary(platformBin, void 0, onTransient, getToolVerificationTimeout(tool), tool.checkArgs)) {
2438
+ logSessionStart(`auto-install ${toolId}: resolved platform-package binary at ${platformBin}`);
2439
+ return platformBin;
2440
+ }
2441
+ logSessionStart(`auto-install ${toolId}: platform-package binary not resolved (${process.platform}-${process.arch}, base=${tool.platformPackage.base ?? tool.packageName}) \u2014 falling back to PATH/managed install`);
2442
+ }
2443
+ if (tool.installStrategy === "github" || tool.installStrategy === "maven" || tool.installStrategy === "archive") {
2444
+ const githubPath = await findGitHubToolPath(tool.binaryName || tool.id);
2445
+ if (githubPath)
2446
+ return githubPath;
2447
+ }
2448
+ if (await isCommandAvailable(tool.checkCommand)) {
2449
+ if (packageEntryVerification(tool) !== void 0)
2450
+ return tool.checkCommand;
2451
+ if (tool.verification === "tree-manifest")
2452
+ return tool.checkCommand;
2453
+ let probeStalled = false;
2454
+ const verified = await verifyToolBinary(tool.checkCommand, void 0, () => {
2455
+ probeStalled = true;
2456
+ onTransient();
2457
+ }, getToolVerificationTimeout(tool), tool.checkArgs, void 0, () => {
2458
+ probeStalled = true;
2459
+ });
2460
+ if (verified || probeStalled)
2461
+ return tool.checkCommand;
2462
+ recordDegradationOnce({
2463
+ kind: "installer-path-candidate-unrunnable",
2464
+ subject: toolId,
2465
+ reason: `${tool.checkCommand} on PATH failed its own check (${tool.checkArgs.join(" ")}); ignoring PATH for this tool`
2466
+ });
2467
+ logSessionStart(`auto-install ${toolId}: PATH candidate ${tool.checkCommand} failed ${tool.checkArgs.join(" ")} \u2014 ignoring PATH, trying managed install`);
2468
+ }
2469
+ if (tool.installStrategy === "npm") {
2470
+ const npmPath = await findNpmGlobalToolPath(tool.binaryName || tool.id, onTransient, tool.checkArgs, getToolVerificationTimeout(tool));
2471
+ if (npmPath) {
2472
+ return npmPath;
2473
+ }
2474
+ }
2475
+ if (tool.installStrategy === "pip") {
2476
+ const pipPath = await findPipUserToolPath(tool.binaryName || tool.id, onTransient, tool.checkArgs, getToolVerificationTimeout(tool));
2477
+ if (pipPath) {
2478
+ return pipPath;
2479
+ }
2480
+ }
2481
+ return void 0;
2482
+ }
2483
+ async function findGitHubToolPath(binaryName) {
2484
+ const isWindows = process.platform === "win32";
2485
+ const candidates = isWindows ? [
2486
+ path3.join(GITHUB_BIN_DIR, `${binaryName}.exe`),
2487
+ path3.join(GITHUB_BIN_DIR, `${binaryName}.bat`),
2488
+ path3.join(GITHUB_BIN_DIR, `${binaryName}.cmd`),
2489
+ path3.join(GITHUB_BIN_DIR, binaryName)
2490
+ ] : [path3.join(GITHUB_BIN_DIR, binaryName)];
2491
+ for (const candidate of candidates) {
2492
+ try {
2493
+ await fs2.access(candidate);
2494
+ return candidate;
2495
+ } catch {
2496
+ }
2497
+ }
2498
+ return void 0;
2499
+ }
2500
+ async function findManagedToolBinary(toolId) {
2501
+ const tool = TOOLS.find((candidate) => candidate.id === toolId);
2502
+ if (!tool)
2503
+ return void 0;
2504
+ if (tool.installStrategy !== "github" && tool.installStrategy !== "maven" && tool.installStrategy !== "archive") {
2505
+ return void 0;
2506
+ }
2507
+ return findGitHubToolPath(tool.binaryName || tool.id);
2508
+ }
2509
+ function hasExecutableExtension(name) {
2510
+ return /\.(exe|bat|cmd|ps1)$/i.test(name);
2511
+ }
2512
+ function getGitHubInstalledBinaryName(binaryName, platform, assetName) {
2513
+ if (platform !== "win32")
2514
+ return binaryName;
2515
+ if (hasExecutableExtension(binaryName))
2516
+ return binaryName;
2517
+ if (assetName.endsWith(".bat"))
2518
+ return `${binaryName}.bat`;
2519
+ if (assetName.endsWith(".cmd"))
2520
+ return `${binaryName}.cmd`;
2521
+ return `${binaryName}.exe`;
2522
+ }
2523
+ function launcherForGitHubAsset(spec, assetName) {
2524
+ if (spec.launcher === "php" && assetName.endsWith(".phar"))
2525
+ return "php";
2526
+ if (spec.launcher === "java" && assetName.endsWith(".jar"))
2527
+ return "java";
2528
+ return void 0;
2529
+ }
2530
+ function getArchiveBinaryCandidates(binaryName, platform, assetName) {
2531
+ if (platform !== "win32")
2532
+ return [binaryName];
2533
+ if (hasExecutableExtension(binaryName))
2534
+ return [binaryName];
2535
+ const candidates = /* @__PURE__ */ new Set();
2536
+ if (assetName.endsWith(".bat"))
2537
+ candidates.add(`${binaryName}.bat`);
2538
+ if (assetName.endsWith(".cmd"))
2539
+ candidates.add(`${binaryName}.cmd`);
2540
+ candidates.add(`${binaryName}.exe`);
2541
+ candidates.add(binaryName);
2542
+ candidates.add(`${binaryName}.bat`);
2543
+ candidates.add(`${binaryName}.cmd`);
2544
+ return [...candidates];
2545
+ }
2546
+ async function findNpmGlobalToolPath(binaryName, onTransient, verificationArgs = ["--version"], verificationTimeoutMs = 1e4) {
2547
+ const isWindows = process.platform === "win32";
2548
+ const binDirs = await getNpmGlobalBinCandidates(onTransient);
2549
+ for (const dir of binDirs) {
2550
+ const candidates = isWindows ? [
2551
+ path3.join(dir, `${binaryName}.cmd`),
2552
+ path3.join(dir, `${binaryName}.exe`)
2553
+ ] : [path3.join(dir, binaryName)];
2554
+ for (const candidate of candidates) {
2555
+ try {
2556
+ await fs2.access(candidate);
2557
+ if (await verifyToolBinary(candidate, void 0, onTransient, verificationTimeoutMs, verificationArgs)) {
2558
+ return candidate;
2559
+ }
2560
+ } catch {
2561
+ }
2562
+ }
2563
+ }
2564
+ return void 0;
2565
+ }
2566
+ async function getNpmGlobalBinCandidates(onTransient) {
2567
+ const dirs = [];
2568
+ const seen = /* @__PURE__ */ new Set();
2569
+ const add = (value) => {
2570
+ if (!value)
2571
+ return;
2572
+ const normalized = path3.resolve(value.trim());
2573
+ if (!normalized)
2574
+ return;
2575
+ if (seen.has(normalized))
2576
+ return;
2577
+ seen.add(normalized);
2578
+ dirs.push(normalized);
2579
+ };
2580
+ if (process.platform === "win32") {
2581
+ add(path3.join(process.env.APPDATA || "", "npm"));
2582
+ } else {
2583
+ add(path3.join(os.homedir(), ".npm-global", "bin"));
2584
+ }
2585
+ for (const dir of await allAvailableGlobalBinDirs(onTransient)) {
2586
+ add(dir);
2587
+ }
2588
+ return dirs;
2589
+ }
2590
+ async function findPipUserToolPath(binaryName, onTransient, verificationArgs = ["--version"], verificationTimeoutMs = 1e4) {
2591
+ const isWindows = installerPlatform() === "win32";
2592
+ const userBaseCandidates = [
2593
+ path3.join(getGlobalPiLensDir(), "pip-tools"),
2594
+ path3.join(getGlobalPiLensDir(), "pip-user"),
2595
+ ...await getPythonUserBaseCandidates()
2596
+ ];
2597
+ for (const userBase of userBaseCandidates) {
2598
+ const scriptDirs = [pipScriptsDir(userBase, installerPlatform())];
2599
+ if (isWindows) {
2600
+ try {
2601
+ const children = await fs2.readdir(userBase, { withFileTypes: true });
2602
+ for (const entry of children) {
2603
+ if (!entry.isDirectory())
2604
+ continue;
2605
+ if (!/^python\d+$/i.test(entry.name))
2606
+ continue;
2607
+ scriptDirs.push(path3.join(userBase, entry.name, "Scripts"));
2608
+ }
2609
+ } catch {
2610
+ }
2611
+ }
2612
+ for (const dir of scriptDirs) {
2613
+ const candidates = isWindows ? [
2614
+ path3.join(dir, `${binaryName}.exe`),
2615
+ path3.join(dir, `${binaryName}.cmd`),
2616
+ path3.join(dir, binaryName)
2617
+ ] : [path3.join(dir, binaryName)];
2618
+ for (const candidate of candidates) {
2619
+ try {
2620
+ await fs2.access(candidate);
2621
+ if (await verifyToolBinary(candidate, void 0, onTransient, verificationTimeoutMs, verificationArgs)) {
2622
+ return candidate;
2623
+ }
2624
+ } catch {
2625
+ }
2626
+ }
2627
+ }
2628
+ }
2629
+ return void 0;
2630
+ }
2631
+ function userBaseProbeResult(command, code, stdout) {
2632
+ if (stdout.truncated) {
2633
+ recordDegradationOnce({
2634
+ kind: "spawn-output-cap-truncated",
2635
+ subject: `user-base-probe:${command}`,
2636
+ reason: `\`${command} -m site --user-base\` reached the ${DEFAULT_MAX_OUTPUT_BYTES}-byte default cap after ${stdout.observedBytes} bytes; the probed user base is unusable`,
2637
+ metadata: {
2638
+ capBytes: DEFAULT_MAX_OUTPUT_BYTES,
2639
+ capSource: "default",
2640
+ observedBytes: stdout.observedBytes,
2641
+ killed: false
2642
+ }
2643
+ });
2644
+ return "";
2645
+ }
2646
+ return code === 0 ? stdout.text.trim() : "";
2647
+ }
2648
+ async function getPythonUserBaseCandidates() {
2649
+ const candidates = [];
2650
+ const seen = /* @__PURE__ */ new Set();
2651
+ const add = (value) => {
2652
+ if (!value)
2653
+ return;
2654
+ const normalized = value.trim();
2655
+ if (!normalized)
2656
+ return;
2657
+ if (seen.has(normalized))
2658
+ return;
2659
+ seen.add(normalized);
2660
+ candidates.push(normalized);
2661
+ };
2662
+ if (process.platform === "win32") {
2663
+ add(path3.join(process.env.APPDATA || "", "Python"));
2664
+ }
2665
+ const probes = process.platform === "win32" ? [
2666
+ { command: "py", args: ["-m", "site", "--user-base"] },
2667
+ { command: "python", args: ["-m", "site", "--user-base"] }
2668
+ ] : [
2669
+ { command: "python3", args: ["-m", "site", "--user-base"] },
2670
+ { command: "python", args: ["-m", "site", "--user-base"] }
2671
+ ];
2672
+ for (const probe of probes) {
2673
+ const userBase = await new Promise((resolve) => {
2674
+ const isWin = process.platform === "win32";
2675
+ const spawnCmd = isWin ? [probe.command, ...probe.args].join(" ") : probe.command;
2676
+ let proc;
2677
+ try {
2678
+ proc = spawn(spawnCmd, isWin ? [] : probe.args, {
2679
+ stdio: ["ignore", "pipe", "pipe"],
2680
+ shell: isWin
2681
+ });
2682
+ } catch {
2683
+ resolve("");
2684
+ return;
2685
+ }
2686
+ const stdout = createBoundedOutputSink();
2687
+ proc.stdout?.on("data", (data) => stdout.append(data));
2688
+ proc.on("exit", (code) => resolve(userBaseProbeResult(probe.command, code, stdout)));
2689
+ proc.on("error", () => resolve(""));
2690
+ });
2691
+ add(userBase);
2692
+ }
2693
+ return candidates;
2694
+ }
2695
+ async function githubApiAuthHeaders() {
2696
+ const token = await resolveGitHubToken();
2697
+ return token ? { Authorization: `Bearer ${token}` } : {};
2698
+ }
2699
+ var HttpStatusError = class extends Error {
2700
+ statusCode;
2701
+ constructor(statusCode, url) {
2702
+ super(url ? `HTTP ${statusCode} for ${url}` : `HTTP ${statusCode}`);
2703
+ this.name = "HttpStatusError";
2704
+ this.statusCode = statusCode;
2705
+ }
2706
+ };
2707
+ var GitHubHttpError = class extends HttpStatusError {
2708
+ anonymousRateLimitExhausted;
2709
+ constructor(statusCode, requestHeaders, responseHeaders) {
2710
+ super(statusCode);
2711
+ this.name = "GitHubHttpError";
2712
+ this.message = `GitHub API HTTP ${statusCode}`;
2713
+ this.anonymousRateLimitExhausted = statusCode === 403 && !Object.keys(requestHeaders).some((key) => key.toLowerCase() === "authorization") && readHeader(responseHeaders, "x-ratelimit-remaining") === "0";
2714
+ }
2715
+ };
2716
+ function readHeader(headers, name) {
2717
+ const entry = Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
2718
+ return Array.isArray(entry) ? entry[0]?.trim() : entry?.trim();
2719
+ }
2720
+ function isGitHubApiUrl(url) {
2721
+ try {
2722
+ return new URL(url).host.toLowerCase() === "api.github.com";
2723
+ } catch {
2724
+ return false;
2725
+ }
2726
+ }
2727
+ function sameHost(a, b) {
2728
+ try {
2729
+ return new URL(a).host === new URL(b).host;
2730
+ } catch {
2731
+ return false;
2732
+ }
2733
+ }
2734
+ function httpsGetWithMeta(url, maxRedirects = 5, headers = {}) {
2735
+ return new Promise((resolve, reject) => {
2736
+ https.get(url, { headers: { "User-Agent": "pi-lens/1.0", ...headers } }, (res) => {
2737
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
2738
+ if (maxRedirects === 0)
2739
+ return reject(new Error("Too many redirects"));
2740
+ const location = res.headers.location;
2741
+ const nextHeaders = sameHost(url, location) ? headers : (() => {
2742
+ const { Authorization: _drop, ...rest } = headers;
2743
+ return rest;
2744
+ })();
2745
+ return resolve(httpsGetWithMeta(location, maxRedirects - 1, nextHeaders));
2746
+ }
2747
+ const etag = typeof res.headers.etag === "string" ? res.headers.etag : void 0;
2748
+ if (res.statusCode === 304) {
2749
+ res.resume();
2750
+ return resolve({ statusCode: 304, body: Buffer.alloc(0), etag });
2751
+ }
2752
+ if (res.statusCode !== 200) {
2753
+ res.resume();
2754
+ return reject(isGitHubApiUrl(url) ? new GitHubHttpError(res.statusCode ?? 0, headers, res.headers) : new HttpStatusError(res.statusCode ?? 0, url));
2755
+ }
2756
+ const chunks = [];
2757
+ res.on("data", (chunk) => chunks.push(chunk));
2758
+ res.on("end", () => resolve({ statusCode: 200, body: Buffer.concat(chunks), etag }));
2759
+ res.on("error", reject);
2760
+ }).on("error", reject);
2761
+ });
2762
+ }
2763
+ async function httpsGet(url, maxRedirects = 5, headers = {}) {
2764
+ const response = await httpsGetWithMeta(url, maxRedirects, headers);
2765
+ if (response.statusCode !== 200) {
2766
+ throw new Error(`HTTP ${response.statusCode} for ${url}`);
2767
+ }
2768
+ return response.body;
2769
+ }
2770
+ function runCommand(command, args, cwd) {
2771
+ return new Promise((resolve) => {
2772
+ let proc;
2773
+ try {
2774
+ proc = spawn(command, args, {
2775
+ cwd,
2776
+ stdio: "ignore",
2777
+ shell: process.platform === "win32"
2778
+ });
2779
+ } catch {
2780
+ resolve(false);
2781
+ return;
2782
+ }
2783
+ proc.on("exit", (code) => resolve(code === 0));
2784
+ proc.on("error", () => resolve(false));
2785
+ });
2786
+ }
2787
+ async function installGitHubTool(tool, prefetchedRelease) {
2788
+ const spec = tool.github;
2789
+ if (!spec)
2790
+ return void 0;
2791
+ const platform = process.platform;
2792
+ const arch = process.arch;
2793
+ const assetSubstring = spec.assetMatch(platform, arch);
2794
+ if (!assetSubstring) {
2795
+ logSessionStart(`github-install ${tool.id}: unsupported platform=${platform} arch=${arch}`);
2796
+ return void 0;
2797
+ }
2798
+ let releaseJson;
2799
+ if (prefetchedRelease) {
2800
+ releaseJson = prefetchedRelease;
2801
+ logSessionStart(`github-install ${tool.id}: using caller-supplied release metadata for ${spec.repo} (${prefetchedRelease.tag_name ?? "untagged"})`);
2802
+ } else {
2803
+ logSessionStart(`github-install ${tool.id}: fetching release metadata from ${spec.repo}`);
2804
+ try {
2805
+ const body = await httpsGet(`https://api.github.com/repos/${spec.repo}/releases/latest`, 5, await githubApiAuthHeaders());
2806
+ releaseJson = JSON.parse(body.toString("utf8"));
2807
+ } catch (err) {
2808
+ const reason = err instanceof GitHubHttpError && err.anonymousRateLimitExhausted ? "GitHub API rate limit exhausted; authenticate with `gh auth login` or set GITHUB_TOKEN/GH_TOKEN and retry" : `release fetch failed: ${err.message}`;
2809
+ if (err instanceof GitHubHttpError && err.anonymousRateLimitExhausted) {
2810
+ recordDegradationOnce({
2811
+ kind: "github-api-rate-limit",
2812
+ subject: tool.id,
2813
+ reason
2814
+ });
2815
+ }
2816
+ logSessionStart(`github-install ${tool.id}: ${reason}`);
2817
+ return void 0;
2818
+ }
2819
+ }
2820
+ if (releaseJson.tag_name) {
2821
+ lastInstallResolutionId.set(tool.id, releaseJson.tag_name);
2822
+ }
2823
+ if (!Array.isArray(releaseJson.assets)) {
2824
+ logSessionStart(`github-install ${tool.id}: release metadata has no assets array`);
2825
+ return void 0;
2826
+ }
2827
+ const asset = pickReleaseAsset(releaseJson.assets, assetSubstring) ?? deriveHashiCorpReleaseAsset(tool, releaseJson.tag_name, assetSubstring);
2828
+ if (!asset) {
2829
+ logSessionStart(`github-install ${tool.id}: no asset matched "${assetSubstring}"`);
2830
+ return void 0;
2831
+ }
2832
+ logSessionStart(`github-install ${tool.id}: downloading ${asset.name}`);
2833
+ debugLog(`[github] downloading ${asset.name} from ${asset.browser_download_url}`);
2834
+ const downloadStart = Date.now();
2835
+ let assetBuffer;
2836
+ try {
2837
+ assetBuffer = await httpsGet(asset.browser_download_url);
2838
+ logSessionStart(`github-install ${tool.id}: downloaded ${asset.name} (${assetBuffer.length} bytes, ${Date.now() - downloadStart}ms)`);
2839
+ } catch (err) {
2840
+ logSessionStart(`github-install ${tool.id}: download failed: ${err.message}`);
2841
+ return void 0;
2842
+ }
2843
+ await fs2.mkdir(GITHUB_BIN_DIR, { recursive: true });
2844
+ const binaryName = tool.binaryName ?? tool.id;
2845
+ const isWindows = platform === "win32";
2846
+ const finalBinaryName = getGitHubInstalledBinaryName(binaryName, platform, asset.name);
2847
+ let destPath = path3.join(GITHUB_BIN_DIR, finalBinaryName);
2848
+ const assetName = asset.name;
2849
+ const launcherRuntime = launcherForGitHubAsset(spec, assetName);
2850
+ if (launcherRuntime && !await isCommandAvailable(launcherRuntime, ["--version"])) {
2851
+ logSessionStart(`github-install ${tool.id}: ${launcherRuntime} not found \u2014 asset requires a runtime launcher`);
2852
+ return void 0;
2853
+ }
2854
+ try {
2855
+ if (launcherRuntime) {
2856
+ const assetPath = path3.join(GITHUB_BIN_DIR, `${tool.id}${assetName.endsWith(".phar") ? ".phar" : ".jar"}`);
2857
+ await writeFileAtomicAsync(assetPath, assetBuffer, {
2858
+ bestEffort: false,
2859
+ mode: 488
2860
+ });
2861
+ const launcherName = isWindows ? `${binaryName}.bat` : binaryName;
2862
+ destPath = path3.join(GITHUB_BIN_DIR, launcherName);
2863
+ const runtimeTarget = assetName.endsWith(".phar") ? `${tool.id}.phar` : `${tool.id}.jar`;
2864
+ const command = isWindows ? `@echo off\r
2865
+ ${launcherRuntime} "%~dp0${runtimeTarget}" %*\r
2866
+ ` : `#!/bin/sh
2867
+ exec ${launcherRuntime} "$(dirname "$0")/${runtimeTarget}" "$@"
2868
+ `;
2869
+ await writeFileAtomicAsync(destPath, command, {
2870
+ bestEffort: false,
2871
+ mode: isWindows ? void 0 : 488
2872
+ });
2873
+ } else if (assetName.endsWith(".gz") && !assetName.endsWith(".tar.gz")) {
2874
+ const decompressed = await new Promise((resolve, reject) => {
2875
+ const gunzip = createGunzip();
2876
+ const chunks = [];
2877
+ gunzip.on("data", (chunk) => chunks.push(chunk));
2878
+ gunzip.on("end", () => resolve(Buffer.concat(chunks)));
2879
+ gunzip.on("error", reject);
2880
+ gunzip.end(assetBuffer);
2881
+ });
2882
+ await writeFileAtomicAsync(destPath, decompressed, {
2883
+ bestEffort: false,
2884
+ mode: 488
2885
+ });
2886
+ } else if (assetName.endsWith(".tar.gz") || assetName.endsWith(".tar.xz")) {
2887
+ const tmpArchive = path3.join(GITHUB_BIN_DIR, `_tmp_${assetName}`);
2888
+ await fs2.writeFile(tmpArchive, assetBuffer);
2889
+ const tmpDir = path3.join(GITHUB_BIN_DIR, `_tmp_extract_${tool.id}`);
2890
+ await fs2.mkdir(tmpDir, { recursive: true });
2891
+ const extracted = await runCommand("tar", ["xf", tmpArchive, "-C", tmpDir], GITHUB_BIN_DIR);
2892
+ await fs2.rm(tmpArchive, { force: true });
2893
+ if (!extracted) {
2894
+ await fs2.rm(tmpDir, { recursive: true, force: true });
2895
+ logSessionStart(`github-install ${tool.id}: tar extraction failed for ${assetName}`);
2896
+ return void 0;
2897
+ }
2898
+ const tarBinaryName = spec.binaryInArchive ?? binaryName;
2899
+ const tarSrcBinary = await findFirstFileRecursive(tmpDir, getArchiveBinaryCandidates(tarBinaryName, platform, assetName));
2900
+ if (!tarSrcBinary) {
2901
+ await fs2.rm(tmpDir, { recursive: true, force: true });
2902
+ logSessionStart(`github-install ${tool.id}: binary candidates ${JSON.stringify(getArchiveBinaryCandidates(tarBinaryName, platform, assetName))} not found in tar ${assetName}`);
2903
+ return void 0;
2904
+ }
2905
+ await fs2.rename(tarSrcBinary, destPath);
2906
+ await fs2.rm(tmpDir, { recursive: true, force: true });
2907
+ if (!isWindows)
2908
+ await fs2.chmod(destPath, 488);
2909
+ } else if (assetName.endsWith(".zip")) {
2910
+ const tmpArchive = path3.join(GITHUB_BIN_DIR, `_tmp_${assetName}`);
2911
+ await fs2.writeFile(tmpArchive, assetBuffer);
2912
+ const tmpDir = path3.join(GITHUB_BIN_DIR, `_tmp_extract_${tool.id}`);
2913
+ await fs2.mkdir(tmpDir, { recursive: true });
2914
+ const extracted = isWindows ? await runCommand("powershell", [
2915
+ "-NoProfile",
2916
+ "-Command",
2917
+ `Expand-Archive -LiteralPath '${tmpArchive}' -DestinationPath '${tmpDir}' -Force`
2918
+ ], GITHUB_BIN_DIR) : await runCommand("unzip", ["-q", "-o", tmpArchive, "-d", tmpDir], GITHUB_BIN_DIR);
2919
+ await fs2.rm(tmpArchive, { force: true });
2920
+ if (!extracted) {
2921
+ await fs2.rm(tmpDir, { recursive: true, force: true });
2922
+ logSessionStart(`github-install ${tool.id}: zip extraction failed for ${assetName}`);
2923
+ return void 0;
2924
+ }
2925
+ const archiveBinaryName = spec.binaryInArchive ?? binaryName;
2926
+ const srcBinary = await findFirstFileRecursive(tmpDir, getArchiveBinaryCandidates(archiveBinaryName, platform, assetName));
2927
+ if (!srcBinary) {
2928
+ await fs2.rm(tmpDir, { recursive: true, force: true });
2929
+ logSessionStart(`github-install ${tool.id}: binary candidates ${JSON.stringify(getArchiveBinaryCandidates(archiveBinaryName, platform, assetName))} not found in zip ${assetName}`);
2930
+ return void 0;
2931
+ }
2932
+ await fs2.rename(srcBinary, destPath);
2933
+ await fs2.rm(tmpDir, { recursive: true, force: true });
2934
+ if (!isWindows)
2935
+ await fs2.chmod(destPath, 488);
2936
+ } else {
2937
+ await writeFileAtomicAsync(destPath, assetBuffer, {
2938
+ bestEffort: false,
2939
+ mode: 488
2940
+ });
2941
+ }
2942
+ } catch (err) {
2943
+ logSessionStart(`github-install ${tool.id}: install failed: ${err.message}`);
2944
+ return void 0;
2945
+ }
2946
+ for (const extraName of spec.extraAssets?.(platform, arch) ?? []) {
2947
+ const extraAsset = releaseJson.assets.find((a) => a.name === extraName);
2948
+ if (!extraAsset) {
2949
+ logSessionStart(`github-install ${tool.id}: required extra asset "${extraName}" not found`);
2950
+ return void 0;
2951
+ }
2952
+ try {
2953
+ const extraBuffer = await httpsGet(extraAsset.browser_download_url);
2954
+ await writeFileAtomicAsync(path3.join(GITHUB_BIN_DIR, extraName), extraBuffer, { bestEffort: false, mode: 488 });
2955
+ logSessionStart(`github-install ${tool.id}: installed extra asset ${extraName} (${extraBuffer.length} bytes)`);
2956
+ } catch (err) {
2957
+ logSessionStart(`github-install ${tool.id}: extra asset ${extraName} download failed: ${err.message}`);
2958
+ return void 0;
2959
+ }
2960
+ }
2961
+ debugLog(`[github] installed ${tool.name} \u2192 ${destPath}`);
2962
+ logSessionStart(`github-install ${tool.id}: installed \u2192 ${destPath}`);
2963
+ return destPath;
2964
+ }
2965
+ async function findFirstFileRecursive(dir, names) {
2966
+ const wanted = new Set(names.map((name) => name.toLowerCase()));
2967
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
2968
+ for (const entry of entries) {
2969
+ const full = path3.join(dir, entry.name);
2970
+ if (entry.isDirectory()) {
2971
+ const found = await findFirstFileRecursive(full, names);
2972
+ if (found)
2973
+ return found;
2974
+ } else if (wanted.has(entry.name.toLowerCase())) {
2975
+ return full;
2976
+ }
2977
+ }
2978
+ return void 0;
2979
+ }
2980
+ var NEEDS_POSTINSTALL = /* @__PURE__ */ new Set([
2981
+ "@biomejs/biome",
2982
+ "@ast-grep/cli",
2983
+ // postinstall copies platform binary (ast-grep.exe/sg.exe) into place
2984
+ "@ast-grep/napi",
2985
+ "esbuild",
2986
+ "intelephense"
2987
+ // postinstall fetches platform binary; --ignore-scripts breaks install
2988
+ ]);
2989
+ function npmToolNeedsPostinstall(packageName) {
2990
+ return NEEDS_POSTINSTALL.has(packageName);
2991
+ }
2992
+ function getRefreshableManagedNpmTools() {
2993
+ const seenPackages = /* @__PURE__ */ new Set();
2994
+ return getRefreshableManagedTools().filter((candidate) => candidate.strategy === "npm").map((candidate) => ({
2995
+ toolId: candidate.toolId,
2996
+ // The npm branch of getRefreshableManagedTools only admits entries that
2997
+ // have both, so these are total.
2998
+ packageName: candidate.packageName,
2999
+ binaryName: candidate.binaryName
3000
+ })).filter((candidate) => {
3001
+ if (seenPackages.has(candidate.packageName))
3002
+ return false;
3003
+ seenPackages.add(candidate.packageName);
3004
+ return true;
3005
+ });
3006
+ }
3007
+ function mavenCoordinate(spec) {
3008
+ return [
3009
+ spec.repoBaseUrl ?? MAVEN_CENTRAL_BASE,
3010
+ spec.groupId,
3011
+ spec.artifactId,
3012
+ spec.version,
3013
+ spec.classifier ?? ""
3014
+ ].join(":");
3015
+ }
3016
+ function getRefreshableManagedTools() {
3017
+ const refreshable = [];
3018
+ for (const tool of TOOLS) {
3019
+ switch (tool.installStrategy) {
3020
+ case "npm": {
3021
+ if (!tool.packageName)
3022
+ continue;
3023
+ if (parsePinnedVersion(tool.packageName) !== void 0)
3024
+ continue;
3025
+ if (!tool.binaryName)
3026
+ continue;
3027
+ refreshable.push({
3028
+ toolId: tool.id,
3029
+ strategy: "npm",
3030
+ checkArgs: tool.checkArgs,
3031
+ packageName: tool.packageName,
3032
+ binaryName: tool.binaryName,
3033
+ verificationTimeoutMs: tool.verificationTimeoutMs,
3034
+ packageEntryOf: packageEntryVerification(tool)
3035
+ });
3036
+ break;
3037
+ }
3038
+ case "pip":
3039
+ case "gem": {
3040
+ if (!tool.packageName)
3041
+ continue;
3042
+ refreshable.push({
3043
+ toolId: tool.id,
3044
+ strategy: tool.installStrategy,
3045
+ checkArgs: tool.checkArgs,
3046
+ packageName: tool.packageName
3047
+ });
3048
+ break;
3049
+ }
3050
+ case "github": {
3051
+ if (!tool.github)
3052
+ continue;
3053
+ refreshable.push({
3054
+ toolId: tool.id,
3055
+ strategy: "github",
3056
+ checkArgs: tool.checkArgs
3057
+ });
3058
+ break;
3059
+ }
3060
+ case "maven": {
3061
+ if (!tool.maven)
3062
+ continue;
3063
+ refreshable.push({
3064
+ toolId: tool.id,
3065
+ strategy: "maven",
3066
+ checkArgs: tool.checkArgs,
3067
+ pinnedCoordinate: mavenCoordinate(tool.maven)
3068
+ });
3069
+ break;
3070
+ }
3071
+ case "archive": {
3072
+ if (!tool.archive)
3073
+ continue;
3074
+ const url = resolveArchiveUrl(tool.archive);
3075
+ if (!url)
3076
+ continue;
3077
+ refreshable.push({
3078
+ toolId: tool.id,
3079
+ strategy: "archive",
3080
+ checkArgs: tool.checkArgs,
3081
+ pinnedCoordinate: url
3082
+ });
3083
+ break;
3084
+ }
3085
+ }
3086
+ }
3087
+ return refreshable;
3088
+ }
3089
+ async function isManagedToolPresent(toolId) {
3090
+ const tool = TOOLS.find((t) => t.id === toolId);
3091
+ if (!tool)
3092
+ return false;
3093
+ switch (tool.installStrategy) {
3094
+ case "npm": {
3095
+ if (!tool.packageName)
3096
+ return false;
3097
+ try {
3098
+ await fs2.access(path3.join(TOOLS_DIR, "node_modules", tool.packageName, "package.json"));
3099
+ return true;
3100
+ } catch {
3101
+ return false;
3102
+ }
3103
+ }
3104
+ case "github":
3105
+ case "maven":
3106
+ return await findGitHubToolPath(tool.binaryName ?? tool.id) !== void 0;
3107
+ case "archive":
3108
+ return await findGitHubToolPath(tool.binaryName ?? tool.id) !== void 0 || await getArchiveTreeBundlePath(tool) !== void 0;
3109
+ case "pip":
3110
+ case "gem": {
3111
+ const cached = (await readProbeCache())[toolId];
3112
+ return cached?.path !== void 0 && existsSync(cached.path);
3113
+ }
3114
+ default:
3115
+ return false;
3116
+ }
3117
+ }
3118
+ async function probeManagedToolVersion(tool) {
3119
+ const cached = (await readProbeCache())[tool.id];
3120
+ if (!cached?.path || !existsSync(cached.path))
3121
+ return void 0;
3122
+ try {
3123
+ const result = await probeToolAsync(cached.path, tool.checkArgs, {
3124
+ timeout: getToolVerificationTimeout(tool),
3125
+ input: "",
3126
+ ignoreAmbientSignal: true,
3127
+ resourceLabel: `tool-refresh-version:${tool.id}`
3128
+ });
3129
+ if (result.status !== 0)
3130
+ return void 0;
3131
+ return extractVersionToken(`${result.stdout}
3132
+ ${result.stderr}`);
3133
+ } catch {
3134
+ return void 0;
3135
+ }
3136
+ }
3137
+ async function acquireManagedInstallGate(context) {
3138
+ if (process.env.PI_LENS_DISABLE_TOOL_INSTALL === "1") {
3139
+ return {
3140
+ ok: false,
3141
+ reason: "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1"
3142
+ };
3143
+ }
3144
+ if (!assertInstallAllowed(context)) {
3145
+ return {
3146
+ ok: false,
3147
+ reason: `project trust: ${projectTrustDenialReason()}`
3148
+ };
3149
+ }
3150
+ const lock = await acquireInstallLock();
3151
+ if (!lock.release) {
3152
+ return { ok: false, reason: lock.reason ?? "install lock held" };
3153
+ }
3154
+ return { ok: true, release: lock.release };
3155
+ }
3156
+ async function refreshManagedTool(toolId, known = {}) {
3157
+ const tool = TOOLS.find((t) => t.id === toolId);
3158
+ if (!tool) {
3159
+ return { ok: false, unchanged: true, reason: "unknown tool id" };
3160
+ }
3161
+ if (tool.installStrategy !== "github" && tool.installStrategy !== "pip" && tool.installStrategy !== "gem" && tool.installStrategy !== "maven" && tool.installStrategy !== "archive") {
3162
+ return {
3163
+ ok: false,
3164
+ unchanged: true,
3165
+ reason: `strategy ${tool.installStrategy} is not refreshable here`
3166
+ };
3167
+ }
3168
+ const strategy = tool.installStrategy;
3169
+ const gate = await acquireManagedInstallGate(`managed tool refresh: ${toolId}`);
3170
+ if (!gate.ok) {
3171
+ return { ok: false, unchanged: true, declined: true, reason: gate.reason };
3172
+ }
3173
+ try {
3174
+ switch (strategy) {
3175
+ case "github":
3176
+ return await refreshGitHubManagedTool(tool, known);
3177
+ case "pip":
3178
+ case "gem":
3179
+ return await refreshPackageManagerManagedTool(tool);
3180
+ case "maven":
3181
+ case "archive":
3182
+ return await refreshPinnedManagedTool(tool, known);
3183
+ default:
3184
+ return {
3185
+ ok: false,
3186
+ unchanged: true,
3187
+ reason: `strategy ${strategy} is not refreshable here`
3188
+ };
3189
+ }
3190
+ } finally {
3191
+ await gate.release?.();
3192
+ }
3193
+ }
3194
+ async function refreshGitHubManagedTool(tool, known) {
3195
+ const spec = tool.github;
3196
+ if (!spec)
3197
+ return { ok: false, unchanged: true, reason: "no github spec" };
3198
+ let response;
3199
+ try {
3200
+ response = await httpsGetWithMeta(`https://api.github.com/repos/${spec.repo}/releases/latest`, 5, {
3201
+ ...await githubApiAuthHeaders(),
3202
+ ...known.etag ? { "If-None-Match": known.etag } : {}
3203
+ });
3204
+ } catch (err) {
3205
+ const reason = err instanceof GitHubHttpError && err.anonymousRateLimitExhausted ? "GitHub API rate limit exhausted; authenticate with `gh auth login` or set GITHUB_TOKEN/GH_TOKEN and retry" : `release query failed: ${err.message}`;
3206
+ if (err instanceof GitHubHttpError && err.anonymousRateLimitExhausted) {
3207
+ recordDegradationOnce({
3208
+ kind: "github-api-rate-limit",
3209
+ subject: tool.id,
3210
+ reason
3211
+ });
3212
+ }
3213
+ return {
3214
+ ok: false,
3215
+ unchanged: true,
3216
+ reason
3217
+ };
3218
+ }
3219
+ if (response.statusCode === 304) {
3220
+ return {
3221
+ ok: true,
3222
+ unchanged: true,
3223
+ resolutionId: known.resolutionId,
3224
+ etag: known.etag,
3225
+ version: known.version
3226
+ };
3227
+ }
3228
+ let release;
3229
+ try {
3230
+ const parsed = JSON.parse(response.body.toString("utf8"));
3231
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3232
+ throw new Error("release metadata is not an object");
3233
+ }
3234
+ release = parsed;
3235
+ } catch (err) {
3236
+ return {
3237
+ ok: false,
3238
+ unchanged: true,
3239
+ reason: `release metadata unparseable: ${err.message}`
3240
+ };
3241
+ }
3242
+ const tag = release.tag_name;
3243
+ if (!tag) {
3244
+ return { ok: false, unchanged: true, reason: "release has no tag_name" };
3245
+ }
3246
+ if (known.resolutionId === tag) {
3247
+ return {
3248
+ ok: true,
3249
+ unchanged: true,
3250
+ resolutionId: tag,
3251
+ etag: response.etag ?? known.etag,
3252
+ version: known.version ?? tag
3253
+ };
3254
+ }
3255
+ const installed = await installGitHubTool(tool, release);
3256
+ if (!installed) {
3257
+ return {
3258
+ ok: false,
3259
+ unchanged: true,
3260
+ // Keep the ETag off the failure stamp: replaying it would make the next
3261
+ // attempt a 304 and skip the download this one never completed.
3262
+ resolutionId: known.resolutionId,
3263
+ version: known.version,
3264
+ reason: `install from release ${tag} failed`
3265
+ };
3266
+ }
3267
+ const verified = await verifyRefreshedArtifact(tool, installed);
3268
+ if (!verified) {
3269
+ return {
3270
+ ok: false,
3271
+ unchanged: false,
3272
+ resolutionId: known.resolutionId,
3273
+ version: known.version,
3274
+ reason: `release ${tag} installed but its binary does not run`
3275
+ };
3276
+ }
3277
+ return {
3278
+ ok: true,
3279
+ unchanged: false,
3280
+ resolutionId: tag,
3281
+ etag: response.etag,
3282
+ version: tag
3283
+ };
3284
+ }
3285
+ async function verifyRefreshedArtifact(tool, installedPath) {
3286
+ if (tool.installStrategy === "archive" && (!tool.archive?.launcher || tool.verification === "tree-manifest")) {
3287
+ await updateProbeCache(tool.id, installedPath);
3288
+ return true;
3289
+ }
3290
+ if (!await verifyToolBinary(installedPath, void 0, void 0, getToolVerificationTimeout(tool), tool.checkArgs)) {
3291
+ logSessionStart(`managed-tool-refresh ${tool.id}: refreshed artifact at ${installedPath} failed its verification check`);
3292
+ return false;
3293
+ }
3294
+ await updateProbeCache(tool.id, installedPath);
3295
+ return true;
3296
+ }
3297
+ async function refreshPackageManagerManagedTool(tool) {
3298
+ if (!tool.packageName) {
3299
+ return { ok: false, unchanged: true, reason: "no package name" };
3300
+ }
3301
+ const previous = await probeManagedToolVersion(tool);
3302
+ const installed = tool.installStrategy === "pip" ? (
3303
+ // `-U` is the whole fix: without it pip treats the installed copy as
3304
+ // satisfying the requirement and the day-one version never moves.
3305
+ await installPipTool(tool.id, tool.packageName, tool.binaryName ?? tool.id, {
3306
+ upgrade: true
3307
+ })
3308
+ ) : (
3309
+ // `gem install` always fetches the newest version that satisfies the
3310
+ // requirement, so the install command IS the upgrade command.
3311
+ await installGemTool(tool.id, tool.packageName)
3312
+ );
3313
+ if (!installed) {
3314
+ return {
3315
+ ok: false,
3316
+ unchanged: true,
3317
+ version: previous,
3318
+ reason: `${tool.installStrategy} upgrade failed`
3319
+ };
3320
+ }
3321
+ const current = await probeManagedToolVersion(tool);
3322
+ if (previous !== void 0 && current === void 0) {
3323
+ return {
3324
+ ok: false,
3325
+ unchanged: false,
3326
+ version: previous,
3327
+ reason: `${tool.installStrategy} upgrade left the binary unable to report a version`
3328
+ };
3329
+ }
3330
+ return {
3331
+ ok: true,
3332
+ // An unreadable version on both sides cannot prove a move, so it reads as
3333
+ // unchanged rather than inventing one.
3334
+ unchanged: previous === void 0 || current === void 0 || previous === current,
3335
+ version: current ?? previous
3336
+ };
3337
+ }
3338
+ async function refreshPinnedManagedTool(tool, known) {
3339
+ const coordinate = tool.installStrategy === "maven" ? tool.maven && mavenCoordinate(tool.maven) : tool.archive && resolveArchiveUrl(tool.archive);
3340
+ if (!coordinate) {
3341
+ return {
3342
+ ok: false,
3343
+ unchanged: true,
3344
+ reason: "no coordinate for this platform"
3345
+ };
3346
+ }
3347
+ if (known.resolutionId === coordinate) {
3348
+ return {
3349
+ ok: true,
3350
+ unchanged: true,
3351
+ resolutionId: coordinate,
3352
+ version: known.version
3353
+ };
3354
+ }
3355
+ const installed = tool.installStrategy === "maven" ? await installMavenTool(tool) : await installArchiveTool(tool);
3356
+ if (!installed) {
3357
+ return {
3358
+ ok: false,
3359
+ unchanged: true,
3360
+ resolutionId: known.resolutionId,
3361
+ version: known.version,
3362
+ reason: `reinstall from ${coordinate} failed`
3363
+ };
3364
+ }
3365
+ if (!await verifyRefreshedArtifact(tool, installed)) {
3366
+ return {
3367
+ ok: false,
3368
+ unchanged: false,
3369
+ resolutionId: known.resolutionId,
3370
+ version: known.version,
3371
+ reason: `reinstall from ${coordinate} produced an artifact that does not run`
3372
+ };
3373
+ }
3374
+ return {
3375
+ ok: true,
3376
+ // A first-ever stamp is an adoption, not a version move: the coordinate did
3377
+ // not change, pi-lens simply had no record of it. Reporting it as a move
3378
+ // would put a false "x → y" row in the log.
3379
+ unchanged: known.resolutionId === void 0,
3380
+ resolutionId: coordinate,
3381
+ version: coordinate
3382
+ };
3383
+ }
3384
+ function resolveManagedNpmBinPath(binaryName) {
3385
+ const binBase = path3.join(TOOLS_DIR, "node_modules", ".bin", binaryName);
3386
+ return installerPlatform() === "win32" ? `${binBase}.cmd` : binBase;
3387
+ }
3388
+ function invalidateManagedToolResolution(toolId) {
3389
+ resolvedPathCache.delete(toolId);
3390
+ if (_probeCache !== null)
3391
+ delete _probeCache[toolId];
3392
+ markProbeCacheChange(toolId, null);
3393
+ }
3394
+ var MAVEN_CENTRAL_BASE = "https://repo1.maven.org/maven2";
3395
+ async function installMavenTool(tool) {
3396
+ const spec = tool.maven;
3397
+ if (!spec)
3398
+ return void 0;
3399
+ const binaryName = tool.binaryName ?? tool.id;
3400
+ const isWindows = process.platform === "win32";
3401
+ if (!await isCommandAvailable("java", ["-version"])) {
3402
+ logSessionStart(`maven-install ${tool.id}: java not found \u2014 a JAR tool can't run without a JRE`);
3403
+ return void 0;
3404
+ }
3405
+ let base = spec.repoBaseUrl ?? MAVEN_CENTRAL_BASE;
3406
+ while (base.endsWith("/"))
3407
+ base = base.slice(0, -1);
3408
+ const groupPath = spec.groupId.replace(/\./g, "/");
3409
+ const jarFile = `${spec.artifactId}-${spec.version}${spec.classifier ? `-${spec.classifier}` : ""}.jar`;
3410
+ const url = `${base}/${groupPath}/${spec.artifactId}/${spec.version}/${jarFile}`;
3411
+ lastInstallResolutionId.set(tool.id, mavenCoordinate(spec));
3412
+ logSessionStart(`maven-install ${tool.id}: downloading ${url}`);
3413
+ let jarBuffer;
3414
+ try {
3415
+ jarBuffer = await httpsGet(url);
3416
+ } catch (err) {
3417
+ logSessionStart(`maven-install ${tool.id}: download failed: ${err.message}`);
3418
+ return void 0;
3419
+ }
3420
+ try {
3421
+ await fs2.mkdir(GITHUB_BIN_DIR, { recursive: true });
3422
+ const jarPath = path3.join(GITHUB_BIN_DIR, `${tool.id}.jar`);
3423
+ await writeFileAtomicAsync(jarPath, jarBuffer, { bestEffort: false });
3424
+ const launcherName = isWindows ? `${binaryName}.bat` : binaryName;
3425
+ const launcherPath = path3.join(GITHUB_BIN_DIR, launcherName);
3426
+ if (isWindows) {
3427
+ await writeFileAtomicAsync(launcherPath, `@echo off\r
3428
+ java -jar "%~dp0${tool.id}.jar" %*\r
3429
+ `, { bestEffort: false });
3430
+ } else {
3431
+ await writeFileAtomicAsync(launcherPath, `#!/bin/sh
3432
+ exec java -jar "$(dirname "$0")/${tool.id}.jar" "$@"
3433
+ `, { bestEffort: false, mode: 488 });
3434
+ }
3435
+ logSessionStart(`maven-install ${tool.id}: installed \u2192 ${launcherPath} (${jarBuffer.length} bytes)`);
3436
+ debugLog(`[maven] installed ${tool.name} \u2192 ${launcherPath}`);
3437
+ return launcherPath;
3438
+ } catch (err) {
3439
+ logSessionStart(`maven-install ${tool.id}: install failed: ${err.message}`);
3440
+ return void 0;
3441
+ }
3442
+ }
3443
+ function resolveArchiveUrl(spec, platform = installerPlatform(), arch = process.arch) {
3444
+ return typeof spec.url === "function" ? spec.url(platform, arch) : spec.url;
3445
+ }
3446
+ function resolveArchiveKind(spec, platform = installerPlatform(), arch = process.arch) {
3447
+ return typeof spec.kind === "function" ? spec.kind(platform, arch) : spec.kind;
3448
+ }
3449
+ function recordArchiveExtractionDegradation(toolId, format, reason) {
3450
+ recordDegradationOnce({
3451
+ kind: "managed-tool-install",
3452
+ subject: `${toolId}:${format}`,
3453
+ reason: `archive extraction ${reason}`
3454
+ });
3455
+ }
3456
+ async function stripExtractedArchiveRoot(dir, components) {
3457
+ for (let i = 0; i < components; i++) {
3458
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
3459
+ const [entry] = entries;
3460
+ if (entries.length !== 1 || !entry?.isDirectory())
3461
+ return false;
3462
+ const root = path3.join(dir, entry.name);
3463
+ for (const child of await fs2.readdir(root))
3464
+ await fs2.rename(path3.join(root, child), path3.join(dir, child));
3465
+ await fs2.rm(root, { recursive: true, force: true });
3466
+ }
3467
+ return true;
3468
+ }
3469
+ async function swapExtractedDir(toolId, tmpDir, finalDir) {
3470
+ const backupDir = `${finalDir}.rollback`;
3471
+ await fs2.rm(backupDir, { recursive: true, force: true });
3472
+ let hadPrevious = false;
3473
+ try {
3474
+ await fs2.rename(finalDir, backupDir);
3475
+ hadPrevious = true;
3476
+ } catch (err) {
3477
+ if (err.code !== "ENOENT")
3478
+ throw err;
3479
+ }
3480
+ try {
3481
+ await fs2.rename(tmpDir, finalDir);
3482
+ } catch (err) {
3483
+ if (hadPrevious) {
3484
+ try {
3485
+ await fs2.rename(backupDir, finalDir);
3486
+ } catch (rollbackErr) {
3487
+ recordDegradationOnce({
3488
+ kind: "managed-tool-refresh",
3489
+ subject: toolId,
3490
+ reason: `swap rollback failed after a failed install: working copy orphaned at ${backupDir} (${rollbackErr.message})`
3491
+ });
3492
+ logSessionStart(`archive-install ${toolId}: swap rollback failed \u2014 working copy orphaned at ${backupDir} (${rollbackErr.message})`);
3493
+ }
3494
+ }
3495
+ throw err;
3496
+ }
3497
+ if (hadPrevious) {
3498
+ await fs2.rm(backupDir, { recursive: true, force: true }).catch(() => {
3499
+ });
3500
+ }
3501
+ }
3502
+ var ARCHIVE_RUNTIME_HOMES = {
3503
+ java: { env: "JAVA_HOME", dir: "bin" }
3504
+ };
3505
+ function runtimeHomeVerdict(runtime) {
3506
+ const home = ARCHIVE_RUNTIME_HOMES[runtime];
3507
+ const root = home ? process.env[home.env] : void 0;
3508
+ if (!home || !root)
3509
+ return void 0;
3510
+ const windows = installerPlatform() === "win32";
3511
+ const names = windows ? [`${runtime}.exe`, runtime] : [runtime];
3512
+ return names.some((name) => {
3513
+ try {
3514
+ const stat = statSync(path3.join(root, home.dir, name));
3515
+ return stat.isFile() && stat.size > 0 && (windows || (stat.mode & 73) !== 0);
3516
+ } catch {
3517
+ return false;
3518
+ }
3519
+ });
3520
+ }
3521
+ async function installArchiveTool(tool) {
3522
+ const spec = tool.archive;
3523
+ if (!spec)
3524
+ return void 0;
3525
+ const binaryName = tool.binaryName ?? tool.id;
3526
+ const platform = installerPlatform();
3527
+ const isWindows = platform === "win32";
3528
+ const archiveKind = resolveArchiveKind(spec, platform, process.arch);
3529
+ const url = resolveArchiveUrl(spec, platform, process.arch);
3530
+ if (!url) {
3531
+ logSessionStart(`archive-install ${tool.id}: no archive for ${process.platform}/${process.arch} \u2014 unsupported, skipping`);
3532
+ return void 0;
3533
+ }
3534
+ lastInstallResolutionId.set(tool.id, url);
3535
+ logSessionStart(`archive-install ${tool.id}: downloading ${url}`);
3536
+ let archiveBuffer;
3537
+ try {
3538
+ archiveBuffer = await httpsGet(url);
3539
+ } catch (err) {
3540
+ logSessionStart(`archive-install ${tool.id}: download failed: ${err.message}`);
3541
+ return void 0;
3542
+ }
3543
+ const pinned = spec.sha256?.[url];
3544
+ const digest = createHash("sha256").update(archiveBuffer).digest("hex");
3545
+ if (digest !== pinned) {
3546
+ const reason = pinned === void 0 ? "sha256-unpinned" : "sha256-mismatch";
3547
+ recordDegradationOnce({
3548
+ kind: "managed-tool-install",
3549
+ subject: `${tool.id}:${archiveKind}:integrity`,
3550
+ reason: `archive integrity ${reason}`
3551
+ });
3552
+ installFailureReasons.set(tool.id, `archive integrity ${reason} (${archiveBuffer.length} bytes from ${url})`);
3553
+ logSessionStart(`archive-install ${tool.id}: refused ${reason} (got ${digest}, pinned ${pinned ?? "none"}) \u2014 keeping installed version`);
3554
+ return void 0;
3555
+ }
3556
+ const extractName = tool.id;
3557
+ const tmpExtractName = `${extractName}.refresh-tmp`;
3558
+ const archiveName = `${tool.id}.download.${archiveKind === "zip" ? "zip" : "tgz"}`;
3559
+ const extractDir = path3.join(TOOLS_DIR, extractName);
3560
+ const tmpExtractDir = path3.join(TOOLS_DIR, tmpExtractName);
3561
+ const tmpArchive = path3.join(TOOLS_DIR, archiveName);
3562
+ try {
3563
+ await fs2.mkdir(TOOLS_DIR, { recursive: true });
3564
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true });
3565
+ await fs2.mkdir(tmpExtractDir, { recursive: true });
3566
+ await fs2.writeFile(tmpArchive, archiveBuffer);
3567
+ const stripComponents = spec.stripComponents ?? 1;
3568
+ const extractionArgs = archiveKind === "zip" && isWindows ? [
3569
+ "-NoProfile",
3570
+ "-Command",
3571
+ `Expand-Archive -LiteralPath '${archiveName}' -DestinationPath '${tmpExtractName}' -Force`
3572
+ ] : archiveKind === "zip" ? ["-q", "-o", archiveName, "-d", tmpExtractName] : [
3573
+ "-xzf",
3574
+ archiveName,
3575
+ "-C",
3576
+ tmpExtractName,
3577
+ ...stripComponents > 0 ? [`--strip-components=${stripComponents}`] : []
3578
+ ];
3579
+ const extractor = archiveKind === "zip" && isWindows ? `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe` : archiveKind === "zip" ? "unzip" : isWindows ? `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\tar.exe` : "tar";
3580
+ const extractionResult = await safeSpawnAsync(extractor, extractionArgs, {
3581
+ cwd: TOOLS_DIR,
3582
+ timeout: 12e4,
3583
+ ignoreAmbientSignal: true,
3584
+ lifetimeCoupled: true
3585
+ });
3586
+ const extracted = {
3587
+ ok: extractionResult.status === 0,
3588
+ reason: extractionResult.spawnFailure?.kind === "tool-not-found" ? "extractor-unavailable" : extractionResult.spawnFailure ? "extractor-error" : "extractor-exit"
3589
+ };
3590
+ await fs2.rm(tmpArchive, { force: true });
3591
+ if (!extracted.ok) {
3592
+ recordArchiveExtractionDegradation(tool.id, archiveKind, extracted.reason);
3593
+ logSessionStart(`archive-install ${tool.id}: ${archiveKind} extraction failed (${extracted.reason}) \u2014 keeping installed version`);
3594
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true }).catch(() => {
3595
+ });
3596
+ return void 0;
3597
+ }
3598
+ if (archiveKind === "zip" && !await stripExtractedArchiveRoot(tmpExtractDir, stripComponents)) {
3599
+ recordArchiveExtractionDegradation(tool.id, archiveKind, "layout-invalid");
3600
+ logSessionStart(`archive-install ${tool.id}: ${archiveKind} layout invalid \u2014 keeping installed version`);
3601
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true }).catch(() => {
3602
+ });
3603
+ return void 0;
3604
+ }
3605
+ if (!spec.launcher) {
3606
+ const tmpMarker = spec.treeMarker ? path3.join(tmpExtractDir, ...spec.treeMarker.split("/")) : tmpExtractDir;
3607
+ try {
3608
+ await fs2.access(tmpMarker);
3609
+ } catch {
3610
+ recordArchiveExtractionDegradation(tool.id, archiveKind, "marker-missing");
3611
+ logSessionStart(`archive-install ${tool.id}: ${archiveKind} marker missing after extraction \u2014 keeping installed version`);
3612
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true }).catch(() => {
3613
+ });
3614
+ return void 0;
3615
+ }
3616
+ await swapExtractedDir(tool.id, tmpExtractDir, extractDir);
3617
+ logSessionStart(`archive-install ${tool.id}: installed tree bundle \u2192 ${extractDir} (extracted ${archiveBuffer.length} bytes, sha256 verified ${digest})`);
3618
+ debugLog(`[archive] installed ${tool.name} bundle \u2192 ${extractDir}`);
3619
+ return extractDir;
3620
+ }
3621
+ const launcherParts = spec.launcher.split("/").map((p) => p);
3622
+ const tmpInnerLauncher = path3.join(tmpExtractDir, ...launcherParts);
3623
+ const tmpResolvedInner = isWindows ? `${tmpInnerLauncher}.bat` : tmpInnerLauncher;
3624
+ try {
3625
+ await fs2.access(tmpResolvedInner);
3626
+ } catch {
3627
+ recordArchiveExtractionDegradation(tool.id, archiveKind, "launcher-missing");
3628
+ logSessionStart(`archive-install ${tool.id}: ${archiveKind} launcher missing after extraction \u2014 keeping installed version`);
3629
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true }).catch(() => {
3630
+ });
3631
+ return void 0;
3632
+ }
3633
+ if (!isWindows)
3634
+ await fs2.chmod(tmpResolvedInner, 488).catch(() => {
3635
+ });
3636
+ const launcherStat = await fs2.stat(tmpResolvedInner).catch(() => void 0);
3637
+ const launcherRunnable = launcherStat?.isFile() === true && launcherStat.size > 0 && (isWindows || (launcherStat.mode & 73) !== 0);
3638
+ if (!launcherRunnable) {
3639
+ recordArchiveExtractionDegradation(tool.id, archiveKind, "launcher-invalid");
3640
+ logSessionStart(`archive-install ${tool.id}: ${archiveKind} launcher is empty or not executable \u2014 keeping installed version`);
3641
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true }).catch(() => {
3642
+ });
3643
+ return void 0;
3644
+ }
3645
+ await swapExtractedDir(tool.id, tmpExtractDir, extractDir);
3646
+ const innerLauncher = path3.join(extractDir, ...launcherParts);
3647
+ const resolvedInner = isWindows ? `${innerLauncher}.bat` : innerLauncher;
3648
+ await fs2.mkdir(GITHUB_BIN_DIR, { recursive: true });
3649
+ const launcherName = isWindows ? `${binaryName}.bat` : binaryName;
3650
+ const shimPath = path3.join(GITHUB_BIN_DIR, launcherName);
3651
+ if (isWindows) {
3652
+ await writeFileAtomicAsync(shimPath, `@echo off\r
3653
+ call "${resolvedInner}" %*\r
3654
+ `, { bestEffort: false });
3655
+ } else {
3656
+ await writeFileAtomicAsync(shimPath, `#!/bin/sh
3657
+ exec "${resolvedInner}" "$@"
3658
+ `, { bestEffort: false, mode: 488 });
3659
+ }
3660
+ logSessionStart(`archive-install ${tool.id}: installed \u2192 ${shimPath} (extracted ${archiveBuffer.length} bytes, sha256 verified ${digest})`);
3661
+ debugLog(`[archive] installed ${tool.name} \u2192 ${shimPath}`);
3662
+ return shimPath;
3663
+ } catch (err) {
3664
+ await fs2.rm(tmpArchive, { force: true }).catch(() => {
3665
+ });
3666
+ await fs2.rm(tmpExtractDir, { recursive: true, force: true }).catch(() => {
3667
+ });
3668
+ logSessionStart(`archive-install ${tool.id}: install failed: ${err.message} \u2014 keeping installed version`);
3669
+ return void 0;
3670
+ }
3671
+ }
3672
+ function recordPackageManagerInstallException(toolId, strategyLabel, packageName, err) {
3673
+ const message = boundInstallError(err.message);
3674
+ logSessionStart(`auto-install ${strategyLabel} ${packageName}: exception: ${message}`);
3675
+ installFailureReasons.set(toolId, message);
3676
+ return void 0;
3677
+ }
3678
+ var INSTALL_ERROR_LINE_LIMIT = 1e3;
3679
+ var INSTALL_CANDIDATE_ERROR_LIMIT = 200;
3680
+ function boundInstallError(value, limit = INSTALL_ERROR_LINE_LIMIT) {
3681
+ const line = value.replace(/[\r\n]+/g, " ").trim();
3682
+ return line.length > limit ? `${line.slice(0, limit - 3)}...` : line;
3683
+ }
3684
+ var InstallLockLostError = class extends Error {
3685
+ };
3686
+ async function installNpmTool(toolId, packageName, binaryName, verificationArgs = ["--version"], verificationTimeoutMs = 1e4, packageEntryOf, ownsLock) {
3687
+ const assertOwnsLock = (context) => {
3688
+ if (ownsLock && !ownsLock()) {
3689
+ recordDegradationOnce({
3690
+ kind: "install-lock-lost-mid-install",
3691
+ subject: toolId,
3692
+ reason: `install lock generation lost before ${context}; aborting rather than risk a second writer in TOOLS_DIR`
3693
+ });
3694
+ throw new InstallLockLostError(`install lock lost before ${context} for ${packageName} (#3515)`);
3695
+ }
3696
+ };
3697
+ try {
3698
+ await fs2.mkdir(TOOLS_DIR, { recursive: true });
3699
+ const packageJsonPath = path3.join(TOOLS_DIR, "package.json");
3700
+ try {
3701
+ await fs2.access(packageJsonPath);
3702
+ } catch {
3703
+ await writeFileAtomicAsync(packageJsonPath, JSON.stringify({ name: "pi-lens-tools", version: "1.0.0" }, null, 2), { bestEffort: false });
3704
+ }
3705
+ const isWindows = installerPlatform() === "win32";
3706
+ const pm = await resolveNodePackageManager(TOOLS_DIR);
3707
+ const testNpmScript = process.env.PI_LENS_TEST_MODE === "1" ? process.env.PI_LENS_TEST_NPM_SCRIPT : void 0;
3708
+ const pmCommand = testNpmScript ? process.execPath : pmBinary(pm);
3709
+ const needsScripts = NEEDS_POSTINSTALL.has(packageName);
3710
+ const baseInstallArgs = installArgs(pm, packageName, {
3711
+ ignoreScripts: !needsScripts
3712
+ });
3713
+ const INSTALL_TIMEOUT_MS = Number(process.env.PI_LENS_INSTALL_TIMEOUT_MS) || 12e4;
3714
+ const runInstallAttempt = async (args) => {
3715
+ const result = await safeSpawnAsync(pmCommand, args, {
3716
+ cwd: TOOLS_DIR,
3717
+ timeout: INSTALL_TIMEOUT_MS,
3718
+ ignoreAmbientSignal: true,
3719
+ lifetimeCoupled: true
3720
+ });
3721
+ return {
3722
+ ok: result.status === 0,
3723
+ stderr: result.error?.message ?? result.stderr
3724
+ };
3725
+ };
3726
+ assertOwnsLock(`spawning ${pmCommand} install`);
3727
+ let outcome = await runInstallAttempt([
3728
+ ...testNpmScript ? [testNpmScript] : [],
3729
+ ...baseInstallArgs
3730
+ ]);
3731
+ const erResolve = outcome.ok === false && /npm\s+error\s+ERESOLVE|\bERESOLVE\b|could not resolve/i.test(outcome.stderr);
3732
+ if (pm === "npm" && erResolve) {
3733
+ assertOwnsLock(`retrying ${pmCommand} install with --legacy-peer-deps`);
3734
+ const retryArgs = installArgs(pm, packageName, {
3735
+ ignoreScripts: !needsScripts,
3736
+ legacyPeerDeps: true
3737
+ });
3738
+ logSessionStart(`auto-install npm ${packageName}: retry with --legacy-peer-deps after ERESOLVE`);
3739
+ outcome = await runInstallAttempt([
3740
+ ...testNpmScript ? [testNpmScript] : [],
3741
+ ...retryArgs
3742
+ ]);
3743
+ }
3744
+ if (!outcome.ok) {
3745
+ throw new Error(`Failed to install ${packageName}: ${outcome.stderr}`);
3746
+ }
3747
+ const binBase = path3.join(TOOLS_DIR, "node_modules", ".bin", binaryName);
3748
+ const binPath = installerPlatform() === "win32" ? `${binBase}.cmd` : binBase;
3749
+ if (installerPlatform() !== "win32") {
3750
+ try {
3751
+ await fs2.chmod(binPath, 488);
3752
+ } catch {
3753
+ }
3754
+ }
3755
+ await new Promise((r) => setTimeout(r, 500));
3756
+ debugLog(`Verifying ${binaryName}...`);
3757
+ let isValid = false;
3758
+ let lastAttemptTransient = false;
3759
+ let lastAttemptInconclusive = false;
3760
+ for (let attempt = 1; attempt <= 3; attempt++) {
3761
+ lastAttemptTransient = false;
3762
+ lastAttemptInconclusive = false;
3763
+ isValid = await verifyToolBinary(binPath, void 0, () => {
3764
+ lastAttemptTransient = true;
3765
+ }, verificationTimeoutMs, verificationArgs, packageEntryOf, () => {
3766
+ lastAttemptInconclusive = true;
3767
+ });
3768
+ if (isValid)
3769
+ break;
3770
+ if (attempt < 3) {
3771
+ logSessionStart(`auto-install verify ${binaryName}: attempt ${attempt} failed, retrying in ${attempt}s`);
3772
+ await new Promise((r) => setTimeout(r, 1e3 * attempt));
3773
+ }
3774
+ }
3775
+ if (!isValid && lastAttemptInconclusive) {
3776
+ if (await verifyNpmPackageEntry(binPath, packageName)) {
3777
+ logSessionStart(`auto-install ${packageName}: verification inconclusive (output truncated before the transport-required marker) but the installed tree is intact; keeping installation for re-probe`);
3778
+ return void 0;
3779
+ }
3780
+ logSessionStart(`auto-install ${packageName}: verification inconclusive AND the installed tree is incomplete; cleaning up so the next install can repair it`);
3781
+ }
3782
+ if (!isValid && lastAttemptTransient) {
3783
+ logSessionStart(`auto-install ${packageName}: verification inconclusive (transient); keeping installation for re-probe`);
3784
+ return void 0;
3785
+ }
3786
+ if (!isValid) {
3787
+ logSessionStart(`auto-install ${packageName}: installed but verification failed, cleaning up`);
3788
+ try {
3789
+ const packagePath = path3.join(TOOLS_DIR, "node_modules", packageName);
3790
+ await fs2.rm(packagePath, { recursive: true, force: true });
3791
+ await fs2.rm(binBase, { force: true });
3792
+ if (isWindows) {
3793
+ await fs2.rm(`${binBase}.cmd`, { force: true });
3794
+ await fs2.rm(`${binBase}.ps1`, { force: true });
3795
+ }
3796
+ } catch {
3797
+ }
3798
+ return void 0;
3799
+ }
3800
+ return binPath;
3801
+ } catch (err) {
3802
+ return recordPackageManagerInstallException(toolId, "npm", packageName, err);
3803
+ }
3804
+ }
3805
+ function pipCommandCandidates() {
3806
+ return process.platform === "win32" ? ["pip", "py", "python"] : ["pip3", "pip", "python3", "python"];
3807
+ }
3808
+ function pipScriptsDir(base, platform = installerPlatform()) {
3809
+ return path3.join(base, platform === "win32" ? "Scripts" : "bin");
3810
+ }
3811
+ var pipPep668LoggedRefusals = createGenerationMap("installer-pep668-log");
3812
+ async function pipConstraintEnvFor(toolId) {
3813
+ const constraints = TOOLS.find((t) => t.id === toolId)?.pipConstraints;
3814
+ if (!constraints || constraints.length === 0)
3815
+ return {};
3816
+ const directories = [
3817
+ path3.join(getGlobalPiLensDir(), "pip-constraints"),
3818
+ path3.join(os.tmpdir(), "pi-lens-pip-constraints")
3819
+ ];
3820
+ const directory = directories.find((candidate) => !/\s/.test(candidate));
3821
+ if (!directory) {
3822
+ recordDegradationOnce({
3823
+ kind: "pip-constraint-path-unusable",
3824
+ subject: toolId,
3825
+ reason: `no whitespace-free directory for the constraints file (tried ${directories.join(", ")}); installing unconstrained`
3826
+ });
3827
+ return {};
3828
+ }
3829
+ const file = path3.join(directory, `${toolId}.txt`);
3830
+ try {
3831
+ await fs2.mkdir(path3.dirname(file), { recursive: true });
3832
+ await writeFileAtomicAsync(file, `${constraints.join("\n")}
3833
+ `, {
3834
+ bestEffort: false
3835
+ });
3836
+ } catch (err) {
3837
+ recordDegradationOnce({
3838
+ kind: "pip-constraint-file-unwritable",
3839
+ subject: toolId,
3840
+ reason: `${file}: ${err instanceof Error ? err.message : String(err)}`
3841
+ });
3842
+ return {};
3843
+ }
3844
+ logSessionStart(`auto-install pip ${toolId}: constraining resolution with ${constraints.join(", ")} (${file})`);
3845
+ return { PIP_CONSTRAINT: file, UV_CONSTRAINT: file };
3846
+ }
3847
+ async function installPipTool(toolId, packageName, binaryName, options = {}) {
3848
+ try {
3849
+ const isWindows = installerPlatform() === "win32";
3850
+ const verb = options.upgrade ? ["install", "-U"] : ["install"];
3851
+ const pipConstraintEnv = await pipConstraintEnvFor(toolId);
3852
+ const pipCandidates = pipCommandCandidates().map((command) => ({
3853
+ command,
3854
+ args: command === "pip" || command === "pip3" ? [...verb, packageName] : ["-m", "pip", ...verb, packageName]
3855
+ }));
3856
+ const pep668 = /externally-managed-environment/i;
3857
+ const refuse = (strategy, reason) => {
3858
+ if (!pep668.test(reason))
3859
+ return;
3860
+ const subject = `${toolId}:${strategy}`;
3861
+ recordDegradationOnce({
3862
+ kind: "pip-pep668-strategy-refused",
3863
+ subject,
3864
+ reason
3865
+ });
3866
+ const logKey = `${getDegradationLedgerGeneration()}:${subject}`;
3867
+ if (pipPep668LoggedRefusals.current(logKey) === 0) {
3868
+ pipPep668LoggedRefusals.bump(logKey);
3869
+ logSessionStart(`auto-install pip ${packageName}: ${strategy} refused by PEP 668 (${boundInstallError(reason)})`);
3870
+ }
3871
+ };
3872
+ const succeeded = (strategy, binaryPath) => {
3873
+ recordDegradationOnce({
3874
+ kind: "pip-install-strategy-succeeded",
3875
+ subject: `${toolId}:${strategy}`,
3876
+ reason: binaryPath
3877
+ });
3878
+ return binaryPath;
3879
+ };
3880
+ const run = (command, args, env) => {
3881
+ const spawnEnv = Object.keys(pipConstraintEnv).length > 0 ? { ...env ?? process.env, ...pipConstraintEnv } : env;
3882
+ return safeSpawnAsync(command, args, {
3883
+ timeout: 12e4,
3884
+ ignoreAmbientSignal: true,
3885
+ lifetimeCoupled: true,
3886
+ cwd: resolveToolCwd("runner", toolId, getGlobalPiLensDir(), {
3887
+ cwd: getGlobalPiLensDir(),
3888
+ suppressTelemetry: true
3889
+ }).cwd,
3890
+ ...spawnEnv ? { env: spawnEnv } : {}
3891
+ });
3892
+ };
3893
+ const addBinToPath = async (binDir) => {
3894
+ try {
3895
+ await fs2.access(binDir);
3896
+ } catch {
3897
+ return void 0;
3898
+ }
3899
+ const currentPath = process.env.PATH || process.env.Path || "";
3900
+ const separator = isWindows ? ";" : path3.delimiter;
3901
+ if (!currentPath.toLowerCase().split(separator).includes(binDir.toLowerCase())) {
3902
+ const updatedPath = `${binDir}${separator}${currentPath}`;
3903
+ process.env.PATH = updatedPath;
3904
+ if (isWindows)
3905
+ process.env.Path = updatedPath;
3906
+ }
3907
+ const names = isWindows ? [`${binaryName}.exe`, `${binaryName}.cmd`, binaryName] : [binaryName];
3908
+ for (const name of names) {
3909
+ const candidate = path3.join(binDir, name);
3910
+ try {
3911
+ await fs2.access(candidate);
3912
+ return candidate;
3913
+ } catch {
3914
+ }
3915
+ }
3916
+ return void 0;
3917
+ };
3918
+ if (await isCommandAvailable("pipx")) {
3919
+ const result = await run("pipx", options.upgrade ? ["upgrade", packageName] : ["install", "--force", packageName]);
3920
+ const error = (result.error?.message ?? result.stderr).trim();
3921
+ if (result.status === 0) {
3922
+ const location = await run("pipx", [
3923
+ "environment",
3924
+ "--value",
3925
+ "PIPX_BIN_DIR"
3926
+ ]);
3927
+ const binDir = location.status === 0 && location.stdout.trim() ? location.stdout.trim() : path3.join(os.homedir(), ".local", "bin");
3928
+ const binaryPath = await addBinToPath(binDir);
3929
+ if (binaryPath)
3930
+ return succeeded("pipx", binaryPath);
3931
+ throw new Error(`pipx installed ${packageName} but ${binaryName} is not resolvable`);
3932
+ }
3933
+ refuse("pipx", error);
3934
+ }
3935
+ const pythonCandidates = pipCandidates.filter(({ command }) => command === "python3" || command === "python" || command === "py");
3936
+ const pythonAvailability = await Promise.all(pythonCandidates.map(({ command }) => isCommandAvailable(command)));
3937
+ const availablePythonCandidates = pythonCandidates.filter((_, index) => pythonAvailability[index]);
3938
+ const venvRoot = path3.join(getGlobalPiLensDir(), "pip-tools");
3939
+ for (const candidate of availablePythonCandidates) {
3940
+ const venvBin = pipScriptsDir(venvRoot, installerPlatform());
3941
+ let venvPip = path3.join(venvBin, isWindows ? "pip.exe" : "pip");
3942
+ try {
3943
+ await fs2.access(venvPip);
3944
+ } catch {
3945
+ const created = await run(candidate.command, ["-m", "venv", venvRoot]);
3946
+ const error2 = (created.error?.message ?? created.stderr).trim();
3947
+ if (created.status !== 0) {
3948
+ refuse("venv", error2 || "python venv module unavailable");
3949
+ continue;
3950
+ }
3951
+ }
3952
+ try {
3953
+ await fs2.access(venvPip);
3954
+ } catch {
3955
+ venvPip = path3.join(venvBin, isWindows ? "pip.cmd" : "pip3");
3956
+ try {
3957
+ await fs2.access(venvPip);
3958
+ } catch {
3959
+ continue;
3960
+ }
3961
+ }
3962
+ const result = await run(venvPip, [...verb, packageName]);
3963
+ const error = (result.error?.message ?? result.stderr).trim();
3964
+ if (result.status === 0) {
3965
+ const binaryPath = await addBinToPath(venvBin);
3966
+ if (binaryPath)
3967
+ return succeeded("venv", binaryPath);
3968
+ throw new Error(`venv installed ${packageName} but ${binaryName} is not resolvable`);
3969
+ }
3970
+ refuse("venv", error);
3971
+ }
3972
+ const candidateErrors = [];
3973
+ let userRefused = false;
3974
+ for (const candidate of pipCandidates) {
3975
+ const args = candidate.command === "pip" || candidate.command === "pip3" ? [...verb, "--user", packageName] : ["-m", "pip", ...verb, "--user", packageName];
3976
+ const result = await run(candidate.command, args);
3977
+ const error = (result.error?.message ?? result.stderr).trim();
3978
+ if (result.status === 0) {
3979
+ const base = await new Promise((resolve) => {
3980
+ let probe;
3981
+ try {
3982
+ probe = spawn(candidate.command, ["-m", "site", "--user-base"], {
3983
+ stdio: ["ignore", "pipe", "pipe"],
3984
+ shell: isWindows
3985
+ });
3986
+ } catch {
3987
+ resolve("");
3988
+ return;
3989
+ }
3990
+ const stdout = createBoundedOutputSink();
3991
+ probe.stdout?.on("data", (data) => stdout.append(data));
3992
+ probe.on("exit", (code) => resolve(userBaseProbeResult(candidate.command, code, stdout)));
3993
+ probe.on("error", () => resolve(""));
3994
+ });
3995
+ const binaryPath = base ? await addBinToPath(pipScriptsDir(base, installerPlatform())) : void 0;
3996
+ return succeeded("user", binaryPath ?? packageName);
3997
+ }
3998
+ const candidateError = `${candidate.command} ${args.join(" ")}: ${boundInstallError(error, INSTALL_CANDIDATE_ERROR_LIMIT)}`;
3999
+ candidateErrors.push(candidateError);
4000
+ if (pep668.test(error)) {
4001
+ userRefused = true;
4002
+ refuse("user", error);
4003
+ }
4004
+ }
4005
+ if (!userRefused)
4006
+ throw new Error(`pip install failed: ${candidateErrors.join(" | ") || "unknown error"}`);
4007
+ const privateBase = path3.join(getGlobalPiLensDir(), "pip-user");
4008
+ const privateEnv = { ...process.env, PYTHONUSERBASE: privateBase };
4009
+ for (const candidate of pipCandidates) {
4010
+ const args = candidate.command === "pip" || candidate.command === "pip3" ? [...verb, "--user", "--break-system-packages", packageName] : [
4011
+ "-m",
4012
+ "pip",
4013
+ ...verb,
4014
+ "--user",
4015
+ "--break-system-packages",
4016
+ packageName
4017
+ ];
4018
+ const result = await run(candidate.command, args, privateEnv);
4019
+ const error = (result.error?.message ?? result.stderr).trim();
4020
+ if (result.status !== 0) {
4021
+ const candidateError = `${candidate.command} ${args.join(" ")}: ${boundInstallError(error, INSTALL_CANDIDATE_ERROR_LIMIT)}`;
4022
+ candidateErrors.push(candidateError);
4023
+ continue;
4024
+ }
4025
+ const binaryPath = await addBinToPath(pipScriptsDir(privateBase, installerPlatform()));
4026
+ if (binaryPath)
4027
+ return succeeded("private-prefix", binaryPath);
4028
+ throw new Error(`private-prefix pip installed ${packageName} but ${binaryName} is not resolvable`);
4029
+ }
4030
+ throw new Error(`pip install failed: ${candidateErrors.join(" | ") || "unknown error"}`);
4031
+ } catch (err) {
4032
+ return recordPackageManagerInstallException(toolId, "pip", packageName, err);
4033
+ }
4034
+ }
4035
+ async function installGemTool(toolId, packageName) {
4036
+ try {
4037
+ const gemResult = await safeSpawnAsync("gem", ["install", packageName, "--no-document"], {
4038
+ timeout: 12e4,
4039
+ ignoreAmbientSignal: true,
4040
+ lifetimeCoupled: true
4041
+ });
4042
+ const outcome = {
4043
+ ok: gemResult.status === 0,
4044
+ error: (gemResult.error?.message ?? gemResult.stderr).trim()
4045
+ };
4046
+ if (!outcome.ok) {
4047
+ throw new Error(`Failed to install ${packageName} via gem: ${outcome.error}`);
4048
+ }
4049
+ return packageName;
4050
+ } catch (err) {
4051
+ return recordPackageManagerInstallException(toolId, "gem", packageName, err);
4052
+ }
4053
+ }
4054
+ async function stampInstallResolution(toolId) {
4055
+ const tool = TOOLS.find((t) => t.id === toolId);
4056
+ if (tool?.installStrategy === "npm")
4057
+ return;
4058
+ try {
4059
+ const resolutionId = lastInstallResolutionId.get(toolId);
4060
+ const refresh = await import("./chunk-CBD2B5CP.js");
4061
+ await refresh.stampManagedToolInstall(toolId, resolutionId);
4062
+ } catch {
4063
+ }
4064
+ }
4065
+ async function finishInstallAttempt(toolId, ok, startedAt) {
4066
+ logSessionStart(`auto-install ${toolId}: ${ok ? "success" : "failed"} (${Date.now() - startedAt}ms)`);
4067
+ if (ok)
4068
+ await stampInstallResolution(toolId);
4069
+ noteInstallAttempt(toolId, ok ? "succeeded" : "failed", ok ? void 0 : installFailureReasons.get(toolId) ?? "install failed");
4070
+ if (ok) {
4071
+ resetSafeSpawnWindowsCommandCache();
4072
+ try {
4073
+ const { resetMadgeManagedPathMemo } = await import("./chunk-WPE5FPGR.js");
4074
+ resetMadgeManagedPathMemo();
4075
+ } catch (err) {
4076
+ logSessionStart(`auto-install ${toolId}: madge memo reset failed: ${err.message}`);
4077
+ }
4078
+ }
4079
+ return ok;
4080
+ }
4081
+ async function installTool(toolId, ownsLock) {
4082
+ if (process.env.PI_LENS_DISABLE_TOOL_INSTALL === "1") {
4083
+ installFailureReasons.set(toolId, "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1");
4084
+ noteInstallAttempt(toolId, "declined", "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1");
4085
+ logSessionStart(`auto-install ${toolId}: refused \u2014 PI_LENS_DISABLE_TOOL_INSTALL=1`);
4086
+ return false;
4087
+ }
4088
+ const tool = TOOLS.find((t) => t.id === toolId);
4089
+ if (!tool) {
4090
+ noteInstallAttempt(toolId, "declined", "unknown tool id");
4091
+ logSessionStart(`auto-install ${toolId}: unknown tool id`);
4092
+ return false;
4093
+ }
4094
+ const startedAt = Date.now();
4095
+ logSessionStart(`auto-install ${tool.id}: start strategy=${tool.installStrategy} package=${tool.packageName ?? "n/a"}`);
4096
+ try {
4097
+ switch (tool.installStrategy) {
4098
+ case "npm": {
4099
+ if (!tool.packageName || !tool.binaryName)
4100
+ return false;
4101
+ const npmPath = await installNpmTool(tool.id, tool.packageName, tool.binaryName, tool.checkArgs, getToolVerificationTimeout(tool), packageEntryVerification(tool), ownsLock);
4102
+ if (npmPath !== void 0) {
4103
+ await import("./chunk-CBD2B5CP.js").then((m) => m.stampManagedToolInstalled(tool.id, tool.packageName)).catch(() => {
4104
+ });
4105
+ }
4106
+ return finishInstallAttempt(tool.id, npmPath !== void 0, startedAt);
4107
+ }
4108
+ case "pip": {
4109
+ if (!tool.packageName)
4110
+ return false;
4111
+ const pipPath = await installPipTool(tool.id, tool.packageName, tool.binaryName ?? tool.id);
4112
+ return finishInstallAttempt(tool.id, pipPath !== void 0, startedAt);
4113
+ }
4114
+ case "gem": {
4115
+ if (!tool.packageName)
4116
+ return false;
4117
+ const gemPath = await installGemTool(tool.id, tool.packageName);
4118
+ return finishInstallAttempt(tool.id, gemPath !== void 0, startedAt);
4119
+ }
4120
+ case "github": {
4121
+ if (!tool.github)
4122
+ return false;
4123
+ if (!tool.github.assetMatch(process.platform, process.arch)) {
4124
+ const reason = `unsupported platform=${process.platform} arch=${process.arch}`;
4125
+ noteInstallAttempt(tool.id, "unavailable", reason);
4126
+ logSessionStart(`auto-install ${tool.id}: ${reason}`);
4127
+ return false;
4128
+ }
4129
+ const ghPath = await installGitHubTool(tool);
4130
+ return finishInstallAttempt(tool.id, ghPath !== void 0, startedAt);
4131
+ }
4132
+ case "maven": {
4133
+ if (!tool.maven)
4134
+ return false;
4135
+ const mavenPath = await installMavenTool(tool);
4136
+ return finishInstallAttempt(tool.id, mavenPath !== void 0, startedAt);
4137
+ }
4138
+ case "archive": {
4139
+ if (!tool.archive)
4140
+ return false;
4141
+ if (!resolveArchiveUrl(tool.archive)) {
4142
+ const reason = `unsupported platform=${process.platform} arch=${process.arch}`;
4143
+ noteInstallAttempt(tool.id, "unavailable", reason);
4144
+ logSessionStart(`auto-install ${tool.id}: ${reason}`);
4145
+ return false;
4146
+ }
4147
+ const runtime = tool.archive.runtime;
4148
+ const viaHome = runtime ? runtimeHomeVerdict(runtime) : void 0;
4149
+ if (runtime && !(viaHome ?? await isCommandAvailable(runtime))) {
4150
+ const reason = viaHome === void 0 ? `runtime ${runtime} not found on PATH` : `runtime ${runtime} is not an executable file under ${ARCHIVE_RUNTIME_HOMES[runtime]?.env}`;
4151
+ noteInstallAttempt(tool.id, "unavailable", reason);
4152
+ logSessionStart(`auto-install ${tool.id}: ${reason}`);
4153
+ return false;
4154
+ }
4155
+ const archivePath = await installArchiveTool(tool);
4156
+ return finishInstallAttempt(tool.id, archivePath !== void 0, startedAt);
4157
+ }
4158
+ default:
4159
+ logSessionStart(`auto-install ${tool.id}: unsupported strategy`);
4160
+ return false;
4161
+ }
4162
+ } catch (err) {
4163
+ logSessionStart(`auto-install ${tool.id}: exception ${err.message} (${Date.now() - startedAt}ms)`);
4164
+ return false;
4165
+ }
4166
+ }
4167
+ async function ensureTool(toolId, opts) {
4168
+ if (opts?.allowInstall !== false && !assertInstallAllowed(`managed tool ensure: ${toolId}`)) {
4169
+ logSessionStart(`auto-install ensure ${toolId}: install gated \u2014 ${projectTrustDenialReason()}; discovery only`);
4170
+ const denialReason = projectTrustDenialReason();
4171
+ const discovered = await ensureToolResolved(toolId, {
4172
+ ...opts,
4173
+ allowInstall: false
4174
+ });
4175
+ noteInstallAttempt(toolId, "declined", `project trust: ${denialReason}`);
4176
+ return discovered;
4177
+ }
4178
+ return ensureToolResolved(toolId, opts);
4179
+ }
4180
+ async function ensureToolResolved(toolId, opts) {
4181
+ installFailureReasons.delete(toolId);
4182
+ installAttempts.delete(toolId);
4183
+ lastEnsureResolutionSource.delete(toolId);
4184
+ const cacheResolvedPath = (result) => {
4185
+ if (result) {
4186
+ resolvedPathCache.set(toolId, result);
4187
+ void updateProbeCache(toolId, result, wasLastResolveTransient(toolId));
4188
+ }
4189
+ return result;
4190
+ };
4191
+ if (opts?.forceReinstall) {
4192
+ const ensureStartMs2 = Date.now();
4193
+ logSessionStart(`auto-install ensure ${toolId}: force reinstall \u2014 clearing caches`);
4194
+ resolvedPathCache.delete(toolId);
4195
+ try {
4196
+ const probeCache = await readProbeCache();
4197
+ delete probeCache[toolId];
4198
+ markProbeCacheChange(toolId, null);
4199
+ } catch {
4200
+ }
4201
+ if (opts.allowInstall === false) {
4202
+ noteInstallAttempt(toolId, "declined", "install disabled by caller");
4203
+ logSessionStart(`auto-install ensure ${toolId}: force reinstall blocked \u2014 install disabled, discovery only (${Date.now() - ensureStartMs2}ms)`);
4204
+ return cacheResolvedPath(await getToolPath(toolId));
4205
+ }
4206
+ if (process.env.PI_LENS_DISABLE_TOOL_INSTALL === "1") {
4207
+ installFailureReasons.set(toolId, "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1");
4208
+ noteInstallAttempt(toolId, "declined", "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1");
4209
+ logSessionStart(`auto-install ensure ${toolId}: refused \u2014 PI_LENS_DISABLE_TOOL_INSTALL=1`);
4210
+ return void 0;
4211
+ }
4212
+ const lock = await acquireInstallLock();
4213
+ if (!lock.release) {
4214
+ noteInstallAttempt(toolId, "skipped", lock.reason ?? "install lock held");
4215
+ logSessionStart(`auto-install ensure ${toolId}: ${lock.reason}`);
4216
+ return void 0;
4217
+ }
4218
+ let installed;
4219
+ try {
4220
+ installed = await installTool(toolId, lock.ownsLock);
4221
+ } finally {
4222
+ await lock.release();
4223
+ }
4224
+ if (!installed) {
4225
+ noteInstallAttemptIfUnrecorded(toolId, "failed", "install failed");
4226
+ logSessionStart(`auto-install ensure ${toolId}: force reinstall failed (${Date.now() - ensureStartMs2}ms)`);
4227
+ return void 0;
4228
+ }
4229
+ const result = cacheResolvedPath(await getToolPath(toolId));
4230
+ if (result) {
4231
+ logSessionStart(`auto-install ensure ${toolId}: force reinstall success at ${result} (${Date.now() - ensureStartMs2}ms)`);
4232
+ }
4233
+ return result;
4234
+ }
4235
+ const cached = resolvedPathCache.get(toolId);
4236
+ if (cached) {
4237
+ if (!isFullyQualified(cached)) {
4238
+ lastEnsureResolutionSource.set(toolId, "session-cache");
4239
+ return cached;
4240
+ }
4241
+ try {
4242
+ await fs2.access(cached);
4243
+ lastEnsureResolutionSource.set(toolId, "session-cache");
4244
+ return cached;
4245
+ } catch {
4246
+ }
4247
+ resolvedPathCache.delete(toolId);
4248
+ const probeCache = await readProbeCache();
4249
+ delete probeCache[toolId];
4250
+ markProbeCacheChange(toolId, null);
4251
+ logSessionStart(`auto-install ensure ${toolId}: cached path disappeared; re-probing`);
4252
+ }
4253
+ const diskCached = await checkProbeCache(toolId);
4254
+ if (diskCached) {
4255
+ resolvedPathCache.set(toolId, diskCached);
4256
+ lastEnsureResolutionSource.set(toolId, "probe-cache");
4257
+ logSessionStart(`auto-install ensure ${toolId}: probe cache hit \u2192 ${diskCached}`);
4258
+ return diskCached;
4259
+ }
4260
+ const inFlightKey = opts?.allowInstall === false ? `${toolId}:discovery-only` : toolId;
4261
+ const inFlight = ensureInFlight.get(inFlightKey);
4262
+ if (inFlight) {
4263
+ logSessionStart(`auto-install ensure ${toolId}: waiting for in-flight ensure (${inFlightKey})`);
4264
+ return inFlight;
4265
+ }
4266
+ const ensureStartMs = Date.now();
4267
+ const ensurePromise = (async () => {
4268
+ logSessionStart(`auto-install ensure ${toolId}: start`);
4269
+ const existingPath = await getToolPath(toolId);
4270
+ if (existingPath) {
4271
+ const tool = TOOLS.find((t) => t.id === toolId);
4272
+ const pinnedVersion = tool?.installStrategy === "npm" && tool.packageName ? parsePinnedVersion(tool.packageName) : void 0;
4273
+ if (pinnedVersion) {
4274
+ const seenVersion = lastManagedInstallVersion.get(toolId);
4275
+ if (seenVersion && seenVersion !== pinnedVersion) {
4276
+ lastManagedInstallVersion.delete(toolId);
4277
+ logSessionStart(`auto-install ensure ${toolId}: version drift (installed ${seenVersion} != pinned ${pinnedVersion}) \u2014 forcing reinstall (${Date.now() - ensureStartMs}ms)`);
4278
+ return ensureTool(toolId, {
4279
+ forceReinstall: true,
4280
+ allowInstall: opts?.allowInstall
4281
+ });
4282
+ }
4283
+ }
4284
+ resolvedPathCache.set(toolId, existingPath);
4285
+ void updateProbeCache(toolId, existingPath, wasLastResolveTransient(toolId));
4286
+ lastEnsureResolutionSource.set(toolId, "path");
4287
+ logSessionStart(`auto-install ensure ${toolId}: already available at ${existingPath} (${Date.now() - ensureStartMs}ms)`);
4288
+ return existingPath;
4289
+ }
4290
+ if (opts?.allowInstall === false) {
4291
+ noteInstallAttempt(toolId, "declined", "install disabled by caller");
4292
+ logSessionStart(`auto-install ensure ${toolId}: install disabled \u2014 discovery only, not found (${Date.now() - ensureStartMs}ms)`);
4293
+ return void 0;
4294
+ }
4295
+ if (process.env.PI_LENS_DISABLE_TOOL_INSTALL === "1") {
4296
+ installFailureReasons.set(toolId, "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1");
4297
+ noteInstallAttempt(toolId, "declined", "installation disabled by PI_LENS_DISABLE_TOOL_INSTALL=1");
4298
+ logSessionStart(`auto-install ensure ${toolId}: refused \u2014 PI_LENS_DISABLE_TOOL_INSTALL=1 (${Date.now() - ensureStartMs}ms)`);
4299
+ return void 0;
4300
+ }
4301
+ const lock = await acquireInstallLock();
4302
+ if (!lock.release) {
4303
+ installFailureReasons.set(toolId, lock.reason ?? "install lock failed");
4304
+ noteInstallAttempt(toolId, "skipped", lock.reason ?? "install lock held");
4305
+ logSessionStart(`auto-install ensure ${toolId}: ${lock.reason}`);
4306
+ return void 0;
4307
+ }
4308
+ let installed;
4309
+ try {
4310
+ const installedByPeer = await getToolPath(toolId);
4311
+ if (installedByPeer) {
4312
+ noteInstallAttempt(toolId, "succeeded", "installed by a concurrent process");
4313
+ resolvedPathCache.set(toolId, installedByPeer);
4314
+ void updateProbeCache(toolId, installedByPeer, wasLastResolveTransient(toolId));
4315
+ return installedByPeer;
4316
+ }
4317
+ installed = await installTool(toolId, lock.ownsLock);
4318
+ } finally {
4319
+ await lock.release();
4320
+ }
4321
+ if (!installed) {
4322
+ noteInstallAttemptIfUnrecorded(toolId, "failed", "install failed");
4323
+ logSessionStart(`auto-install ensure ${toolId}: unavailable (${Date.now() - ensureStartMs}ms)`);
4324
+ return void 0;
4325
+ }
4326
+ const result = await getToolPath(toolId);
4327
+ if (result) {
4328
+ resolvedPathCache.set(toolId, result);
4329
+ void updateProbeCache(toolId, result, wasLastResolveTransient(toolId));
4330
+ logSessionStart(`auto-install ensure ${toolId}: success at ${result} (${Date.now() - ensureStartMs}ms)`);
4331
+ } else {
4332
+ logSessionStart(`auto-install ensure ${toolId}: unavailable (${Date.now() - ensureStartMs}ms)`);
4333
+ }
4334
+ return result;
4335
+ })();
4336
+ ensureInFlight.set(inFlightKey, ensurePromise);
4337
+ try {
4338
+ return await ensurePromise;
4339
+ } finally {
4340
+ if (ensureInFlight.get(inFlightKey) === ensurePromise) {
4341
+ ensureInFlight.delete(inFlightKey);
4342
+ }
4343
+ }
4344
+ }
4345
+ async function getToolEnvironment() {
4346
+ const localBin = path3.join(TOOLS_DIR, "node_modules", ".bin");
4347
+ const currentPath = process.env.PATH || process.env.Path || process.env.path || "";
4348
+ const separator = process.platform === "win32" ? ";" : ":";
4349
+ const nodeDir = path3.dirname(process.execPath);
4350
+ const withNode = nodeDir ? `${nodeDir}${separator}${currentPath}` : currentPath;
4351
+ const augmentedPath = `${GITHUB_BIN_DIR}${separator}${localBin}${separator}${withNode}`;
4352
+ const env = {
4353
+ ...process.env,
4354
+ PATH: augmentedPath
4355
+ };
4356
+ if (process.platform === "win32") {
4357
+ env.Path = augmentedPath;
4358
+ }
4359
+ return env;
4360
+ }
4361
+ async function checkAllTools() {
4362
+ const results = [];
4363
+ for (const tool of TOOLS) {
4364
+ const path4 = await getToolPath(tool.id);
4365
+ results.push({
4366
+ id: tool.id,
4367
+ name: tool.name,
4368
+ installed: path4 !== void 0,
4369
+ path: path4
4370
+ });
4371
+ }
4372
+ return results;
4373
+ }
4374
+ function isKnownToolId(toolId) {
4375
+ return TOOLS.some((tool) => tool.id === toolId);
4376
+ }
4377
+ function getToolInstallStrategy(toolId) {
4378
+ return TOOLS.find((tool) => tool.id === toolId)?.installStrategy;
4379
+ }
4380
+ var GITHUB_TOOLS = [
4381
+ "cljfmt",
4382
+ "php-cs-fixer",
4383
+ "shellcheck",
4384
+ "shfmt",
4385
+ "rust-analyzer",
4386
+ "golangci-lint",
4387
+ "ktlint",
4388
+ "actionlint",
4389
+ "zizmor",
4390
+ "typos-lsp",
4391
+ "tflint",
4392
+ "terragrunt",
4393
+ "terraform-ls",
4394
+ "zls",
4395
+ "hadolint",
4396
+ "helm",
4397
+ "gitleaks",
4398
+ "taplo",
4399
+ "vale",
4400
+ "opengrep",
4401
+ "deno",
4402
+ "clojure-lsp",
4403
+ "cue",
4404
+ "gleam",
4405
+ "typstyle",
4406
+ "tinymist",
4407
+ "marksman",
4408
+ "expert"
4409
+ ];
4410
+ function resolveGitHubAsset(toolId, platform, arch) {
4411
+ const tool = TOOLS.find((t) => t.id === toolId);
4412
+ return tool?.github?.assetMatch(platform, arch);
4413
+ }
4414
+ function resolveGitHubAssetLauncher(toolId, _platform, assetName) {
4415
+ const tool = TOOLS.find((t) => t.id === toolId);
4416
+ return tool?.github ? launcherForGitHubAsset(tool.github, assetName) : void 0;
4417
+ }
4418
+ function resolveGitHubInstalledBinaryName(toolId, platform, assetName) {
4419
+ const tool = TOOLS.find((t) => t.id === toolId);
4420
+ if (!tool)
4421
+ return void 0;
4422
+ return getGitHubInstalledBinaryName(tool.binaryName ?? tool.id, platform, assetName);
4423
+ }
4424
+ function resolveGitHubArchiveBinaryCandidates(toolId, platform, assetName) {
4425
+ const tool = TOOLS.find((t) => t.id === toolId);
4426
+ if (!tool)
4427
+ return void 0;
4428
+ const binaryName = tool.github?.binaryInArchive ?? tool.binaryName ?? tool.id;
4429
+ return getArchiveBinaryCandidates(binaryName, platform, assetName);
4430
+ }
4431
+ var ASSET_SIDECAR_SUFFIXES = [
4432
+ ".asc",
4433
+ ".sig",
4434
+ ".minisig",
4435
+ ".pem",
4436
+ ".cert",
4437
+ ".sbom",
4438
+ ".sha256",
4439
+ ".sha256sum",
4440
+ ".md5"
4441
+ ];
4442
+ function isAssetSidecar(name) {
4443
+ const lower = name.toLowerCase();
4444
+ return ASSET_SIDECAR_SUFFIXES.some((suffix) => lower.endsWith(suffix));
4445
+ }
4446
+ function pickReleaseAsset(assets, assetSubstring) {
4447
+ return assets.find((a) => a.name === assetSubstring) ?? assets.find((a) => a.name.includes(assetSubstring) && !isAssetSidecar(a.name));
4448
+ }
4449
+ function deriveHashiCorpReleaseAsset(tool, tagName, assetSubstring) {
4450
+ const product = tool.github?.hashiCorpReleaseProduct;
4451
+ if (!product || !tagName)
4452
+ return void 0;
4453
+ const version = tagName.replace(/^v/, "").trim();
4454
+ if (!version)
4455
+ return void 0;
4456
+ const assetName = `${product}_${version}_${assetSubstring}`;
4457
+ return {
4458
+ name: assetName,
4459
+ browser_download_url: `https://releases.hashicorp.com/${product}/${version}/${assetName}`
4460
+ };
4461
+ }
4462
+ function resolveDerivedHashiCorpReleaseAsset(toolId, tagName, platform, arch) {
4463
+ const tool = TOOLS.find((t) => t.id === toolId);
4464
+ if (!tool)
4465
+ return void 0;
4466
+ const assetSubstring = tool.github?.assetMatch(platform, arch);
4467
+ if (!assetSubstring)
4468
+ return void 0;
4469
+ return deriveHashiCorpReleaseAsset(tool, tagName, assetSubstring);
4470
+ }
4471
+
4472
+ export {
4473
+ commitDurableStore,
4474
+ commitDurableStoreAsync,
4475
+ findLocalZizmorConfig,
4476
+ isZizmorAuditTarget,
4477
+ resetZizmorTokenAvailability,
4478
+ resolveZizmorGitHubToken,
4479
+ logSessionStart,
4480
+ getManagedToolsDir,
4481
+ TOOLS,
4482
+ getToolVerificationTimeout,
4483
+ getInstallFailureReason,
4484
+ getInstallAttempt,
4485
+ getLastEnsureResolutionSource,
4486
+ resetResolvedPathCache,
4487
+ flushProbeCache,
4488
+ checkProbeCache,
4489
+ updateProbeCache,
4490
+ resetProbeCacheStateForTesting,
4491
+ _peekEnsureInFlightForTesting,
4492
+ resetPathWalkMemo,
4493
+ isCommandAvailable,
4494
+ isSpawnableCommand,
4495
+ isLspTransportRequiredError,
4496
+ parsePinnedVersion,
4497
+ packageEntryVerification,
4498
+ verifyNpmPackageEntry,
4499
+ verifyToolBinary,
4500
+ getAllToolStatuses,
4501
+ isToolInstalled,
4502
+ resolvePlatformPackageBinary,
4503
+ wasLastResolveTransient,
4504
+ getToolPath,
4505
+ findManagedToolBinary,
4506
+ userBaseProbeResult,
4507
+ npmToolNeedsPostinstall,
4508
+ getRefreshableManagedNpmTools,
4509
+ getRefreshableManagedTools,
4510
+ isManagedToolPresent,
4511
+ acquireManagedInstallGate,
4512
+ refreshManagedTool,
4513
+ resolveManagedNpmBinPath,
4514
+ invalidateManagedToolResolution,
4515
+ resolveArchiveUrl,
4516
+ resolveArchiveKind,
4517
+ swapExtractedDir,
4518
+ pipCommandCandidates,
4519
+ pipScriptsDir,
4520
+ installTool,
4521
+ ensureTool,
4522
+ getToolEnvironment,
4523
+ checkAllTools,
4524
+ isKnownToolId,
4525
+ getToolInstallStrategy,
4526
+ GITHUB_TOOLS,
4527
+ resolveGitHubAsset,
4528
+ resolveGitHubAssetLauncher,
4529
+ resolveGitHubInstalledBinaryName,
4530
+ resolveGitHubArchiveBinaryCandidates,
4531
+ pickReleaseAsset,
4532
+ resolveDerivedHashiCorpReleaseAsset
4533
+ };