@herbertgao/pi-extensions 2026.8.4 → 2026.8.5

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 (288) hide show
  1. package/README.md +4 -4
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  13. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  14. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  15. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  16. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
  20. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  21. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  22. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  25. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  26. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  27. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  30. package/node_modules/@narumitw/pi-btw/README.md +8 -7
  31. package/node_modules/@narumitw/pi-btw/package.json +2 -2
  32. package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
  33. package/node_modules/pi-lens/CHANGELOG.md +2440 -954
  34. package/node_modules/pi-lens/README.md +13 -0
  35. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  36. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  37. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  38. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  39. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  40. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  41. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  42. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  43. package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
  44. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  45. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  46. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  47. package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
  48. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  49. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  50. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  51. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  52. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  53. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  54. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  55. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  56. package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
  57. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  58. package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
  59. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  60. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  61. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
  63. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
  64. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
  66. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  67. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  68. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  69. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  70. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  71. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
  72. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  73. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  74. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  75. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  85. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  86. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  87. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  99. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  100. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  101. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  102. package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
  103. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  104. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  105. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  106. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  107. package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
  108. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  109. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  110. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  111. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  112. package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
  113. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  114. package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
  116. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  117. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  118. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
  120. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  121. package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
  122. package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
  123. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  124. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  125. package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
  126. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  127. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  128. package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
  129. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  130. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  131. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
  132. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
  134. package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
  135. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  136. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
  137. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  138. package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
  139. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  140. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  141. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  142. package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
  143. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  144. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  145. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  146. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
  147. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  148. package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
  149. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  150. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  151. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  152. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  153. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  154. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  155. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  157. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  158. package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
  159. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  160. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  161. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  162. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  163. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  164. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  165. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  166. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  167. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  168. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  169. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  170. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  171. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  172. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  173. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  174. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  175. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  177. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  178. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  179. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  180. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  181. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  182. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
  183. package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
  184. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
  185. package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
  186. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  187. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
  188. package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
  189. package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
  190. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  191. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
  192. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  193. package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
  194. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  195. package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
  196. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  197. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  198. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  199. package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
  200. package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
  201. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  202. package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
  203. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  204. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  205. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  210. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  211. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  212. package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
  213. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  214. package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
  215. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  216. package/node_modules/pi-lens/dist/index.js +49361 -36888
  217. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  218. package/node_modules/pi-lens/dist/mcp/server.js +211 -44
  219. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  220. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
  221. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
  222. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  223. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  224. package/node_modules/pi-lens/docs/agent-guide.md +2 -2
  225. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  226. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  227. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  228. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
  229. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  230. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  231. package/node_modules/pi-lens/docs/fable.md +27 -0
  232. package/node_modules/pi-lens/docs/features.md +31 -2
  233. package/node_modules/pi-lens/docs/globalconfig.md +45 -1
  234. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  235. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  236. package/node_modules/pi-lens/docs/mcp.md +37 -4
  237. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  238. package/node_modules/pi-lens/docs/settings.md +12 -1
  239. package/node_modules/pi-lens/docs/tools.md +4 -1
  240. package/node_modules/pi-lens/docs/usage.md +18 -0
  241. package/node_modules/pi-lens/package.json +10 -10
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  252. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  253. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  254. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
  255. package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
  256. package/node_modules/pi-mcp-adapter/README.md +34 -3
  257. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  258. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  259. package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
  260. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  261. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  262. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  263. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  264. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  265. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  266. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  267. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  268. package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
  269. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  270. package/node_modules/pi-mcp-adapter/package.json +3 -3
  271. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  272. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  273. package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
  274. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  275. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  276. package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
  277. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  278. package/node_modules/pi-mcp-adapter/types.ts +93 -27
  279. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  280. package/package.json +11 -12
  281. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  282. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  283. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  284. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  285. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  286. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  287. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  288. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -6,11 +6,11 @@
6
6
  *
7
7
  * Requires: pyright (pip install pyright or npm install -g pyright)
8
8
  */
9
- import { ensureTool } from "../../installer/index.js";
9
+ import { logExtension } from "../../extension-log.js";
10
10
  import { getLSPService } from "../../lsp/index.js";
11
11
  import { safeSpawnAsync } from "../../safe-spawn.js";
12
12
  import { PRIORITY } from "../priorities.js";
13
- import { createAvailabilityChecker } from "./utils/runner-helpers.js";
13
+ import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
14
14
  const pyright = createAvailabilityChecker("pyright", ".exe");
15
15
  const pyrightRunner = {
16
16
  id: "pyright",
@@ -34,9 +34,9 @@ const pyrightRunner = {
34
34
  if (await (pyright.isAvailableAsync(cwd))) {
35
35
  cmd = pyright.getCommand(cwd);
36
36
  }
37
- // Strategy 2: Try to find pyright via ensureTool (installs if needed)
37
+ // Strategy 2: use the shared availability taxonomy and install suppression.
38
38
  if (!cmd) {
39
- const installedPath = await ensureTool("pyright");
39
+ const installedPath = await resolveAvailableOrInstall(pyright, "pyright", cwd);
40
40
  if (installedPath)
41
41
  cmd = installedPath;
42
42
  }
@@ -85,7 +85,11 @@ const pyrightRunner = {
85
85
  // pi-lens-ignore: missing-error-propagation
86
86
  }
87
87
  catch {
88
- console.error(`[runner:pyright] JSON parse failed for ${ctx.filePath} — raw output: ${output.slice(0, 200)}`);
88
+ logExtension({
89
+ subsystem: "runner:pyright",
90
+ message: `JSON parse failed for ${ctx.filePath} — raw output: ${output.slice(0, 200)}`,
91
+ metadata: { filePath: ctx.filePath },
92
+ });
89
93
  return {
90
94
  status: "failed",
91
95
  diagnostics: [],
@@ -6,10 +6,9 @@
6
6
  * mutating files mid-dispatch after LSP sync has already happened.
7
7
  * Supports venv-local installations.
8
8
  */
9
- import { resolvePackagePath } from "../../package-root.js";
10
9
  import { safeSpawnAsync } from "../../safe-spawn.js";
11
10
  import { stripAnsi } from "../../sanitize.js";
12
- import { getAutofixCapability, getLinterPolicyForCwd, hasRuffConfig, } from "../../tool-policy.js";
11
+ import { getAutofixCapability, getLinterPolicyForCwd, ruffConfigArgs, } from "../../tool-policy.js";
13
12
  import { PRIORITY } from "../priorities.js";
14
13
  import { parseRuffOutput } from "./utils/diagnostic-parsers.js";
15
14
  import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
@@ -61,12 +60,9 @@ const ruffRunner = {
61
60
  if (!cmd) {
62
61
  return { status: "skipped", diagnostics: [], semantic: "none" };
63
62
  }
64
- const configArgs = hasRuffConfig(cwd)
65
- ? []
66
- : [
67
- "--config",
68
- resolvePackagePath(import.meta.url, "config/ruff/core.toml"),
69
- ];
63
+ // Shared config-args seam (#1247): the autofix path consumes the same
64
+ // builder, so the package-owned fallback config can never drift.
65
+ const configArgs = ruffConfigArgs(cwd);
70
66
  // Step 1: Capture diagnostics (before fixing) — teaching signal for the agent
71
67
  const checkResult = await safeSpawnAsync(cmd, ["check", "--output-format", "json", ...configArgs, ctx.filePath], { timeout: 30000 });
72
68
  const raw = stripAnsi(checkResult.stdout + checkResult.stderr);
@@ -21,10 +21,9 @@
21
21
  */
22
22
  import * as fs from "node:fs";
23
23
  import * as path from "node:path";
24
- import { ensureTool } from "../../installer/index.js";
25
24
  import { safeSpawnAsync } from "../../safe-spawn.js";
26
25
  import { PRIORITY } from "../priorities.js";
27
- import { createAvailabilityChecker, lspPrimaryCoversFile, } from "./utils/runner-helpers.js";
26
+ import { createAvailabilityChecker, lspPrimaryCoversFile, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
28
27
  const shellcheck = createAvailabilityChecker("shellcheck", ".exe");
29
28
  function findShellcheckConfig(cwd) {
30
29
  const local = path.join(cwd, ".shellcheckrc");
@@ -127,7 +126,7 @@ const shellcheckRunner = {
127
126
  cmd = shellcheck.getCommand(cwd);
128
127
  }
129
128
  else {
130
- const managed = await ensureTool("shellcheck");
129
+ const managed = await resolveAvailableOrInstall(shellcheck, "shellcheck", cwd);
131
130
  if (managed)
132
131
  cmd = managed;
133
132
  }
@@ -1,9 +1,8 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { ensureTool } from "../../installer/index.js";
4
3
  import { safeSpawnAsync } from "../../safe-spawn.js";
5
4
  import { PRIORITY } from "../priorities.js";
6
- import { createAvailabilityChecker } from "./utils/runner-helpers.js";
5
+ import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
7
6
  const shfmt = createAvailabilityChecker("shfmt", ".exe");
8
7
  // shfmt's only config source is .editorconfig. We treat its presence as the
9
8
  // opt-in for the (non-error) format-diff warning, so out of the box shfmt only
@@ -39,7 +38,7 @@ const shfmtRunner = {
39
38
  cmd = shfmt.getCommand(cwd);
40
39
  }
41
40
  else {
42
- const installed = await ensureTool("shfmt");
41
+ const installed = await resolveAvailableOrInstall(shfmt, "shfmt", cwd);
43
42
  if (!installed) {
44
43
  return { status: "skipped", diagnostics: [], semantic: "none" };
45
44
  }
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as os from "node:os";
3
3
  import * as path from "node:path";
4
+ import { BoundedLruCache } from "../../bounded-cache.js";
4
5
  import { safeSpawnAsync } from "../../safe-spawn.js";
5
6
  import { findCompiledClassesDir } from "../../tool-policy.js";
6
7
  import { PRIORITY } from "../priorities.js";
@@ -11,7 +12,7 @@ const java = createAvailabilityChecker("java", ".exe", ["-version"]);
11
12
  const spotbugs = createAvailabilityChecker("spotbugs", ".bat", ["-version"]);
12
13
  const MAX_DIAGNOSTICS = 50;
13
14
  const MAX_XML_BYTES = 4 * 1024 * 1024;
14
- const scanCache = new Map();
15
+ const scanCache = new BoundedLruCache(32);
15
16
  /** Reset the SpotBugs scan cache (tests). */
16
17
  export function _resetSpotbugsCacheForTests() {
17
18
  scanCache.clear();
@@ -3,6 +3,7 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
3
3
  import { getLinterPolicyForCwd } from "../../tool-policy.js";
4
4
  import { PRIORITY } from "../priorities.js";
5
5
  import { createAvailabilityChecker, lspPrimaryCoversFile, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
6
7
  const taplo = createAvailabilityChecker("taplo", ".exe");
7
8
  function parseTaploOutput(raw, filePath) {
8
9
  try {
@@ -55,7 +56,7 @@ const taploRunner = {
55
56
  return { status: "skipped", diagnostics: [], semantic: "none" };
56
57
  const absPath = path.resolve(cwd, ctx.filePath);
57
58
  const result = await safeSpawnAsync(cmd, ["check", "--output=json", absPath], { cwd, timeout: 15000 });
58
- if (result.error && !result.stdout) {
59
+ if (spawnFailedWithNoOutput(result)) {
59
60
  return { status: "skipped", diagnostics: [], semantic: "none" };
60
61
  }
61
62
  const diagnostics = parseTaploOutput(result.stdout || "", ctx.filePath);
@@ -0,0 +1,163 @@
1
+ import * as path from "node:path";
2
+ import { safeSpawnAsync } from "../../safe-spawn.js";
3
+ import { pathsEqual } from "../../path-utils.js";
4
+ import { getLinterPolicyForCwd } from "../../tool-policy.js";
5
+ import { PRIORITY } from "../priorities.js";
6
+ import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
7
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
8
+ const terragrunt = createAvailabilityChecker("terragrunt", ".exe");
9
+ function normalizeSeverity(raw) {
10
+ if (typeof raw === "number")
11
+ return raw === 1 ? "error" : "warning";
12
+ if (typeof raw === "string" && raw.toLowerCase() === "error")
13
+ return "error";
14
+ return "warning";
15
+ }
16
+ function toRawDiagnostics(parsed) {
17
+ if (Array.isArray(parsed))
18
+ return parsed;
19
+ if (!parsed || typeof parsed !== "object")
20
+ return [];
21
+ const invalidFiles = parsed.invalid_files;
22
+ if (!Array.isArray(invalidFiles))
23
+ return [];
24
+ return invalidFiles.flatMap((f) => Array.isArray(f?.diagnostics) ? f.diagnostics : []);
25
+ }
26
+ /**
27
+ * Parse `terragrunt hcl validate --json` output.
28
+ *
29
+ * OBSERVED CONTRACT (captured empirically from terragrunt v1.1.2, win-x64):
30
+ * the payload is a FLAT JSON array of diagnostic objects on stdout, e.g.
31
+ *
32
+ * [{"range":{"filename":"<ABSOLUTE path>","start":{"line":1,"column":8,...},
33
+ * "end":{...}},"snippet":{...},"summary":"Unclosed configuration block",
34
+ * "detail":"...","severity":"error"}]
35
+ *
36
+ * Key facts: `severity` is a STRING ("error"), `range.filename` is an ABSOLUTE
37
+ * path (host separator), and a CLEAN unit prints NOTHING (empty stdout, exit 0)
38
+ * — not `[]`. The nested `{invalid_files:[{diagnostics:[...]}]}` wrapper and the
39
+ * numeric (1=error/2=warning) severity encoding were NOT observed on v1.1.2 and
40
+ * are retained only as a tolerant fallback for other/older shapes.
41
+ * Malformed/unparseable input returns [].
42
+ */
43
+ export function parseTerragruntOutput(raw, filePath, absPath = path.resolve(filePath)) {
44
+ if (!raw.trim())
45
+ return [];
46
+ let parsed;
47
+ try {
48
+ parsed = JSON.parse(raw);
49
+ }
50
+ catch {
51
+ return [];
52
+ }
53
+ // Resolved against the unit dir, not compared by basename: a unit that
54
+ // includes its parent via find_in_parent_folders() gets diagnostics from a
55
+ // parent terragrunt.hcl, whose basename matches but whose lines do not.
56
+ const unitDir = path.dirname(absPath);
57
+ const diagnostics = [];
58
+ for (const d of toRawDiagnostics(parsed)) {
59
+ if (!d || typeof d !== "object")
60
+ continue;
61
+ const diagFile = d.range?.filename;
62
+ if (diagFile && !pathsEqual(path.resolve(unitDir, diagFile), absPath))
63
+ continue;
64
+ const line = d.range?.start?.line ?? 1;
65
+ const column = d.range?.start?.column ?? 1;
66
+ const severity = normalizeSeverity(d.severity);
67
+ const message = d.summary ?? d.detail ?? "terragrunt hcl validate error";
68
+ // No rule code in hcl validate output, so the message carries the identity.
69
+ const idMessage = message
70
+ .toLowerCase()
71
+ .replace(/[^a-z0-9]+/g, "-")
72
+ .slice(0, 80);
73
+ diagnostics.push({
74
+ id: `terragrunt-hclvalidate-${line}-${column}-${idMessage}`,
75
+ message,
76
+ filePath,
77
+ line,
78
+ column,
79
+ severity,
80
+ semantic: severity === "error" ? "blocking" : "warning",
81
+ tool: "terragrunt",
82
+ fixable: false,
83
+ });
84
+ }
85
+ return diagnostics;
86
+ }
87
+ const SKIPPED = {
88
+ status: "skipped",
89
+ diagnostics: [],
90
+ semantic: "none",
91
+ };
92
+ /**
93
+ * Runner for `terragrunt hcl validate --json`, the linter for terragrunt units.
94
+ *
95
+ * REQUIRES the redesigned terragrunt CLI: the `terragrunt hcl validate` /
96
+ * `terragrunt hcl fmt` command group replaced the old `hclvalidate`/`hclfmt`
97
+ * top-level commands in the CLI redesign (~terragrunt v0.75; the legacy names
98
+ * were removed in v1.0). Contract verified empirically on terragrunt v1.1.2.
99
+ *
100
+ * Observed exit-code / output table (terragrunt v1.1.2, win-x64):
101
+ * - clean unit ............ exit 0, EMPTY stdout (no `[]`)
102
+ * - validation findings ... exit 1, flat JSON array on stdout (+ a log line
103
+ * "N HCL validation error(s) found" on stderr)
104
+ * - unknown command ....... an older binary that predates `hcl validate`
105
+ * exits non-zero with the error on STDERR and EMPTY
106
+ * stdout; `spawnFailedWithNoOutput` classifies that
107
+ * as SKIPPED (never a false blocker, and never a
108
+ * false CLEAN — a nonzero exit carries no
109
+ * `SpawnResult.error`, so the status has to be part
110
+ * of the test).
111
+ *
112
+ * `hcl validate` recursively validates the unit(s) at its working dir; it has no
113
+ * per-file flag (`--filter` takes component filter-syntax, NOT a filename — a
114
+ * bare basename silently matches zero components and suppresses ALL findings,
115
+ * verified on v1.1.2). So we validate the edited file's unit directory and
116
+ * attribute findings back to the edited file by absolute path in
117
+ * parseTerragruntOutput.
118
+ *
119
+ * Misdetection edge: `root.hcl` is filename-detected as terragrunt, so a
120
+ * `root.hcl` that is NOT a terragrunt file still gets validated here — `hcl
121
+ * validate` just checks generic HCL, so a non-terragrunt file fails soft
122
+ * (either clean or a plain HCL diagnostic, never a spurious hard blocker).
123
+ */
124
+ const terragruntRunner = {
125
+ id: "terragrunt",
126
+ appliesTo: ["terragrunt"],
127
+ priority: PRIORITY.GENERAL_ANALYSIS,
128
+ enabledByDefault: true,
129
+ skipTestFiles: false,
130
+ async run(ctx) {
131
+ const cwd = ctx.cwd || process.cwd();
132
+ const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
133
+ if (policy && !policy.preferredRunners.includes("terragrunt"))
134
+ return SKIPPED;
135
+ let cmd = null;
136
+ if (await terragrunt.isAvailableAsync(cwd)) {
137
+ cmd = terragrunt.getCommand(cwd);
138
+ }
139
+ else {
140
+ const managed = await resolveAvailableOrInstall(terragrunt, "terragrunt", cwd);
141
+ if (managed)
142
+ cmd = managed;
143
+ }
144
+ if (!cmd)
145
+ return SKIPPED;
146
+ const absPath = path.resolve(cwd, ctx.filePath);
147
+ const fileDir = path.dirname(absPath);
148
+ const result = await safeSpawnAsync(cmd, ["hcl", "validate", "--json", "--non-interactive"], { cwd: fileDir, timeout: 30000 });
149
+ if (spawnFailedWithNoOutput(result))
150
+ return SKIPPED;
151
+ const diagnostics = parseTerragruntOutput(result.stdout || "", ctx.filePath, absPath);
152
+ if (diagnostics.length === 0) {
153
+ return { status: "succeeded", diagnostics: [], semantic: "none" };
154
+ }
155
+ const hasErrors = diagnostics.some((d) => d.severity === "error");
156
+ return {
157
+ status: hasErrors ? "failed" : "succeeded",
158
+ diagnostics,
159
+ semantic: hasErrors ? "blocking" : "warning",
160
+ };
161
+ },
162
+ };
163
+ export default terragruntRunner;
@@ -1,9 +1,26 @@
1
1
  import * as path from "node:path";
2
- import { ensureTool } from "../../installer/index.js";
3
2
  import { safeSpawnAsync } from "../../safe-spawn.js";
4
- import { createAvailabilityChecker } from "./utils/runner-helpers.js";
3
+ import { getLinterPolicyForCwd } from "../../tool-policy.js";
4
+ import { findNearestDirWithAnyBasename } from "../../workspace-topology.js";
5
+ import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
6
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
5
7
  import { PRIORITY } from "../priorities.js";
6
8
  const tflint = createAvailabilityChecker("tflint", ".exe");
9
+ const TFLINT_CONFIG = ".tflint.hcl";
10
+ /**
11
+ * tflint resolves `.tflint.hcl` from its own working directory and never walks
12
+ * parents (its only fallback is `~/.tflint.hcl`). We run it from the edited
13
+ * file's directory, so a repo-root config would govern nothing beneath the
14
+ * root unless we name it explicitly. Returns null when `TFLINT_CONFIG_FILE` is
15
+ * set: `--config` outranks the env var in tflint's own precedence, so passing
16
+ * one would override a deliberate choice.
17
+ */
18
+ function findTflintConfig(fileDir) {
19
+ if (process.env.TFLINT_CONFIG_FILE)
20
+ return null;
21
+ const dir = findNearestDirWithAnyBasename(fileDir, [TFLINT_CONFIG]);
22
+ return dir ? path.join(dir, TFLINT_CONFIG) : null;
23
+ }
7
24
  function parseTflintOutput(raw, filePath) {
8
25
  try {
9
26
  const parsed = JSON.parse(raw);
@@ -36,12 +53,16 @@ const tflintRunner = {
36
53
  skipTestFiles: false,
37
54
  async run(ctx) {
38
55
  const cwd = ctx.cwd || process.cwd();
56
+ const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
57
+ if (policy && !policy.preferredRunners.includes("tflint")) {
58
+ return { status: "skipped", diagnostics: [], semantic: "none" };
59
+ }
39
60
  let cmd = null;
40
61
  if (await (tflint.isAvailableAsync(cwd))) {
41
62
  cmd = tflint.getCommand(cwd);
42
63
  }
43
64
  else {
44
- const managed = await ensureTool("tflint");
65
+ const managed = await resolveAvailableOrInstall(tflint, "tflint", cwd);
45
66
  if (managed)
46
67
  cmd = managed;
47
68
  }
@@ -49,8 +70,19 @@ const tflintRunner = {
49
70
  return { status: "skipped", diagnostics: [], semantic: "none" };
50
71
  const absPath = path.resolve(cwd, ctx.filePath);
51
72
  const fileDir = path.dirname(absPath);
52
- const result = await safeSpawnAsync(cmd, ["--format=json", "--no-color", `--filter=${path.basename(absPath)}`], { cwd: fileDir, timeout: 30000 });
53
- if (result.error && !result.stdout) {
73
+ const args = [
74
+ "--format=json",
75
+ "--no-color",
76
+ `--filter=${path.basename(absPath)}`,
77
+ ];
78
+ const configPath = findTflintConfig(fileDir);
79
+ if (configPath)
80
+ args.push(`--config=${configPath}`);
81
+ const result = await safeSpawnAsync(cmd, args, {
82
+ cwd: fileDir,
83
+ timeout: 30000,
84
+ });
85
+ if (spawnFailedWithNoOutput(result)) {
54
86
  return { status: "skipped", diagnostics: [], semantic: "none" };
55
87
  }
56
88
  const diagnostics = parseTflintOutput(result.stdout || "", ctx.filePath);
@@ -525,7 +525,9 @@ const treeSitterRunner = {
525
525
  });
526
526
  }
527
527
  else {
528
- console.error("[tree-sitter] Batched query run failed:", err);
528
+ // #1333: the logTreeSitter call below already carries this failure to
529
+ // tree-sitter.log — the console.error was a duplicate RAW write into
530
+ // pi's frame, not a second destination. Sink kept, write dropped.
529
531
  logTreeSitter({
530
532
  phase: "query_error",
531
533
  filePath,
@@ -15,8 +15,14 @@
15
15
  * reports at the same line (`suppressTrivyConfigDockerOverlap`), so trivy
16
16
  * only adds the security checks hadolint lacks.
17
17
  *
18
- * Deferred (tracked on #131): Terraform (tflint overlap), Helm chart rendering,
19
- * Docker Compose, CloudFormation.
18
+ * - **Terraform**: the `.tf` language files themselves — trivy evaluates
19
+ * the Terraform language directly, so no content gate is needed (unlike
20
+ * the yaml/k8s heuristic above). Terragrunt (`.hcl`) is deliberately
21
+ * excluded: trivy has no terragrunt support, and terragrunt config is
22
+ * covered by the terragrunt runner instead.
23
+ *
24
+ * Deferred (tracked on #131): Helm chart rendering, Docker Compose,
25
+ * CloudFormation.
20
26
  *
21
27
  * Gating: the same explicit `trivy.enabled` opt-in as the session-scan modes —
22
28
  * trivy is opt-in, period. (Misconfig needs only the small policy bundle, not
@@ -30,7 +36,8 @@ import * as path from "node:path";
30
36
  import { safeSpawnAsync } from "../../safe-spawn.js";
31
37
  import { isTrivyEnabled, resolveSeverityFloor, } from "../../trivy-client.js";
32
38
  import { PRIORITY } from "../priorities.js";
33
- import { createAvailabilityChecker } from "./utils/runner-helpers.js";
39
+ import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
40
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
34
41
  const trivy = createAvailabilityChecker("trivy", ".exe");
35
42
  /**
36
43
  * Heuristic: does this YAML look like a Kubernetes manifest (vs a CI workflow,
@@ -115,7 +122,7 @@ export function parseTrivyConfigOutput(raw, filePath) {
115
122
  }
116
123
  const trivyConfigRunner = {
117
124
  id: "trivy-config",
118
- appliesTo: ["docker", "yaml"],
125
+ appliesTo: ["docker", "yaml", "terraform"],
119
126
  priority: PRIORITY.GENERAL_ANALYSIS,
120
127
  enabledByDefault: true,
121
128
  skipTestFiles: false,
@@ -144,8 +151,7 @@ const trivyConfigRunner = {
144
151
  cmd = trivy.getCommand(cwd);
145
152
  }
146
153
  else {
147
- const { ensureTool } = await import("../../installer/index.js");
148
- const managed = await ensureTool("trivy");
154
+ const managed = await resolveAvailableOrInstall(trivy, "trivy", cwd);
149
155
  if (managed)
150
156
  cmd = managed;
151
157
  }
@@ -162,7 +168,7 @@ const trivyConfigRunner = {
162
168
  severities,
163
169
  absPath,
164
170
  ], { cwd, timeout: 60_000 });
165
- if (result.error && !result.stdout) {
171
+ if (spawnFailedWithNoOutput(result)) {
166
172
  return { status: "skipped", diagnostics: [], semantic: "none" };
167
173
  }
168
174
  const diagnostics = parseTrivyConfigOutput(result.stdout || "", ctx.filePath);
@@ -1,4 +1,5 @@
1
1
  import { safeSpawnAsync } from "../../../safe-spawn.js";
2
+ import { assertInstallAllowed } from "../../../project-trust.js";
2
3
  const attempted = new Set();
3
4
  function key(cwd, tool) {
4
5
  return `${cwd}:${tool}`;
@@ -9,6 +10,8 @@ function key(cwd, tool) {
9
10
  * Installs are attempted once per cwd+tool per session to avoid repeated churn.
10
11
  */
11
12
  export async function tryLazyInstall(tool, cwd) {
13
+ if (!assertInstallAllowed(`runner lazy install: ${tool}`))
14
+ return false;
12
15
  const k = key(cwd, tool);
13
16
  if (attempted.has(k))
14
17
  return false;