@herbertgao/pi-extensions 2026.8.4 → 2026.8.6

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 (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  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/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -0,0 +1,14 @@
1
+ /** Lazy dispatch integration seam for startup-cost control (#1394). */
2
+ let integrationPromise;
3
+ /** Start loading the runner graph once; callers may fire-and-forget this. */
4
+ export function warmDispatchIntegration() {
5
+ return (integrationPromise ??= import("./integration.js"));
6
+ }
7
+ /** Await the same promise used by session-start warming and first use. */
8
+ export function loadDispatchIntegration() {
9
+ return warmDispatchIntegration();
10
+ }
11
+ /** Test-only reset; production sessions intentionally retain the promise. */
12
+ export function resetDispatchIntegrationForTests() {
13
+ integrationPromise = undefined;
14
+ }
@@ -118,6 +118,11 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
118
118
  { mode: "all", runnerIds: ["actionlint"], filterKinds: ["yaml"] },
119
119
  ],
120
120
  },
121
+ "helm-template": {
122
+ name: "Helm Template Linting",
123
+ capabilities: ["lint"],
124
+ writeGroups: [primary("helm-template")],
125
+ },
121
126
  sql: {
122
127
  name: "SQL Processing",
123
128
  capabilities: ["format", "lint"],
@@ -218,9 +223,14 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
218
223
  },
219
224
  terraform: {
220
225
  name: "Terraform Linting",
221
- capabilities: ["types", "lint"],
226
+ capabilities: ["types", "lint", "security"],
222
227
  writeGroups: [primary("terraform")],
223
228
  },
229
+ terragrunt: {
230
+ name: "Terragrunt Linting",
231
+ capabilities: ["lint", "format"],
232
+ writeGroups: [primary("terragrunt")],
233
+ },
224
234
  nix: {
225
235
  name: "Nix Linting",
226
236
  capabilities: ["types", "lint"],
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Normalize a rule id to the form a user typically writes in a
3
+ * `pi-lens-ignore` comment, an inline suppression, or a project-level
4
+ * `disable`/`select` list. Strips the `ast-grep:` LSP source prefix and the
5
+ * language suffix used by the rule catalogs.
6
+ */
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { getAstGrepRuleSources } from "../sgconfig.js";
10
+ /** Derive language tags from shipped rule filenames, rather than a list. */
11
+ export function deriveRuleIdLanguageSuffixes(ruleRoot) {
12
+ const suffixes = new Set();
13
+ const visit = (dir) => {
14
+ let entries;
15
+ try {
16
+ entries = fs.readdirSync(dir, { withFileTypes: true });
17
+ }
18
+ catch {
19
+ return;
20
+ }
21
+ for (const entry of entries) {
22
+ const entryPath = path.join(dir, entry.name);
23
+ if (entry.isDirectory())
24
+ visit(entryPath);
25
+ else {
26
+ const match = /-([a-z0-9]+)\.ya?ml$/i.exec(entry.name);
27
+ if (match)
28
+ suffixes.add(match[1].toLowerCase());
29
+ }
30
+ }
31
+ };
32
+ visit(ruleRoot);
33
+ return suffixes;
34
+ }
35
+ const bundledCodeRabbitRules = getAstGrepRuleSources().find((source) => source.origin === "bundled" && source.tier === "secondary");
36
+ const RULE_ID_LANGUAGE_SUFFIXES = new Set(["js"]);
37
+ if (bundledCodeRabbitRules) {
38
+ for (const suffix of deriveRuleIdLanguageSuffixes(bundledCodeRabbitRules.dir)) {
39
+ RULE_ID_LANGUAGE_SUFFIXES.add(suffix);
40
+ }
41
+ }
42
+ export function normalizeRuleId(ruleId) {
43
+ const normalized = ruleId.replace(/^ast-grep:/, "");
44
+ for (const suffix of RULE_ID_LANGUAGE_SUFFIXES) {
45
+ if (normalized.endsWith(`-${suffix}`)) {
46
+ return normalized.slice(0, -(suffix.length + 1));
47
+ }
48
+ }
49
+ return normalized;
50
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Project-level rule policy (`.pi-lens.json` `rules.<id>.disable` /
3
+ * `rules.<id>.select`) — output-only filtering of dispatches, so the project's
4
+ * own policy narrows what the user actually sees without widening the trusted
5
+ * surface area (widget state, baseline, dedup, and per-edit record stay
6
+ * authoritative).
7
+ *
8
+ * Matching is PROJECT-WIDE. The outer `rules.<key>` is a grouping label only —
9
+ * it does not scope which diagnostics a `disable`/`select` list under it can
10
+ * match. Every `disable` entry across every key is unioned into one drop list,
11
+ * and every `select` entry across every key is unioned into one allowlist.
12
+ * Disable is checked first, so it wins globally regardless of which key it's
13
+ * configured under.
14
+ *
15
+ * Match normalization is consolidated with the rest of the rule-id surfaces:
16
+ * `inline-suppressions.ts` and `lens-diagnostics.ts`'s `normalizeRuleId`
17
+ * both strip the `ast-grep:` prefix and the `-js` suffix, so a user listing
18
+ * `no-eval` once under `disable` covers both the LSP tag (`ast-grep:no-eval`)
19
+ * and the napi tag (`no-eval` / `no-eval-js`). Sharing the normalization keeps
20
+ * the three surfaces from drifting.
21
+ */
22
+ import { normalizeRuleId } from "./rule-id-normalize.js";
23
+ /**
24
+ * Decide whether a rule id (in the form it's emitted on a diagnostic — e.g.
25
+ * `ast-grep:no-eval`, `no-eval-js`, `no-eval`, `ts:2322`) should be filtered
26
+ * out under a project's rule policy map. Returns `dropped: true` when the
27
+ * diagnostic would be hidden from output.
28
+ *
29
+ * Project-wide: every `disable` entry across every configured key is checked
30
+ * first (disable wins globally over select). Then every `select` entry
31
+ * across every key is unioned into one allowlist — a non-empty union that
32
+ * the rule doesn't match also drops it. An absent/empty union across all
33
+ * keys means "no restriction". Matching uses the same normalization as
34
+ * inline suppression so a configured `no-eval` entry covers
35
+ * `ast-grep:no-eval` and `no-eval-js`.
36
+ */
37
+ export function evaluateRulePolicy(ruleId, policyMap) {
38
+ if (!policyMap)
39
+ return { dropped: false };
40
+ const raw = ruleId || "";
41
+ const norm = normalizeRuleId(raw);
42
+ if (scanList(policyMap, (e) => e.disable, raw, norm).matched) {
43
+ return { dropped: true };
44
+ }
45
+ const select = scanList(policyMap, (e) => e.select, raw, norm);
46
+ return { dropped: select.sawEntry && !select.matched };
47
+ }
48
+ /**
49
+ * Union one list (`disable` or `select`) across every key in the map and test
50
+ * the rule against it. `sawEntry` reports whether the union was non-empty,
51
+ * which is what makes a `select` union restrictive rather than absent.
52
+ */
53
+ function scanList(policyMap, pick, raw, norm) {
54
+ let sawEntry = false;
55
+ for (const entry of Object.values(policyMap)) {
56
+ for (const candidate of (entry && pick(entry)) ?? []) {
57
+ sawEntry = true;
58
+ if (matchesRule(candidate, raw, norm))
59
+ return { matched: true, sawEntry };
60
+ }
61
+ }
62
+ return { matched: false, sawEntry };
63
+ }
64
+ function matchesRule(entry, raw, normalized) {
65
+ if (entry === raw)
66
+ return true;
67
+ return normalizeRuleId(entry) === normalized;
68
+ }
69
+ /**
70
+ * Filter an array of diagnostics (returns a new array) by the project rule
71
+ * policy map. `rule` is preferred; code-only diagnostics use `code` as their
72
+ * policy key so project-diagnostics details and rendered summaries cannot
73
+ * disagree about a finding that has no explicit rule field. `Diagnostic.id`
74
+ * remains a dedup key (`eslint:unknown:12`), not a policy key, so id-only
75
+ * findings (including blocking parse errors) remain exempt.
76
+ *
77
+ * Used by both the per-edit dispatcher and the `lens-diagnostics` tool's
78
+ * `mode=delta`/`mode=all`/`mode=full` paths so a project's own policy
79
+ * applies consistently across every output surface.
80
+ */
81
+ export function applyRulePolicy(diagnostics, policyMap) {
82
+ if (!policyMap)
83
+ return diagnostics;
84
+ // Fast-path: if every entry has neither disable nor select, there is no
85
+ // output filter to apply. Keeps the hot path (most projects have only
86
+ // thresholds) cheap.
87
+ let hasFilter = false;
88
+ for (const rawEntry of Object.values(policyMap)) {
89
+ if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) {
90
+ continue;
91
+ }
92
+ const entry = rawEntry;
93
+ if ((entry.disable?.length ?? 0) > 0 || (entry.select?.length ?? 0) > 0) {
94
+ hasFilter = true;
95
+ break;
96
+ }
97
+ }
98
+ if (!hasFilter)
99
+ return diagnostics;
100
+ return diagnostics.filter((d) => {
101
+ const ruleId = d.rule ?? d.code;
102
+ if (!ruleId)
103
+ return true;
104
+ const { dropped } = evaluateRulePolicy(ruleId, policyMap);
105
+ return !dropped;
106
+ });
107
+ }
108
+ /**
109
+ * Build the policy map from a `PiLensProjectConfig.rules`-shaped value. Returns
110
+ * undefined when there's nothing to filter (the hot path), or a map suitable
111
+ * for `applyRulePolicy` otherwise. Excludes entries whose only field is
112
+ * `threshold` (a threshold is a separate concern handled elsewhere) so the
113
+ * filter step doesn't repeat the work.
114
+ */
115
+ export function rulePolicyMapFromConfig(rules) {
116
+ if (!rules)
117
+ return undefined;
118
+ let built;
119
+ for (const [key, rawEntry] of Object.entries(rules)) {
120
+ if (!rawEntry || typeof rawEntry !== "object" || Array.isArray(rawEntry)) {
121
+ continue;
122
+ }
123
+ const entry = rawEntry;
124
+ const hasDisable = (entry.disable?.length ?? 0) > 0;
125
+ const hasSelect = (entry.select?.length ?? 0) > 0;
126
+ if (!hasDisable && !hasSelect)
127
+ continue;
128
+ built ??= {};
129
+ built[key] = {
130
+ ...(hasDisable ? { disable: entry.disable } : {}),
131
+ ...(hasSelect ? { select: entry.select } : {}),
132
+ };
133
+ }
134
+ return built;
135
+ }
@@ -19,6 +19,12 @@ import { isAuxiliaryLspAlive } from "../../lsp/index.js";
19
19
  import { resolveAstGrepNativeExe } from "../../lsp/wait-policy/index.js";
20
20
  import { PRIORITY } from "../priorities.js";
21
21
  import { calculateRuleComplexity, isOverlyBroadPattern, isStructuredRule, loadYamlRules, loadYamlRulesFresh, MAX_BLOCKING_RULE_COMPLEXITY, } from "./yaml-rule-parser.js";
22
+ const defaultUnsupportedLanguageLog = new Set();
23
+ const UNSUPPORTED_RULE_ID_SAMPLE_SIZE = 5;
24
+ /** Clear per-session unsupported-language telemetry dedupe. */
25
+ export function resetAstGrepUnsupportedLanguageLog() {
26
+ defaultUnsupportedLanguageLog.clear();
27
+ }
22
28
  // Lazy load the napi package
23
29
  let sg;
24
30
  let sgLoadAttempted = false;
@@ -237,7 +243,7 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
237
243
  const maxTotalDiagnostics = options.maxTotalDiagnostics ?? MAX_TOTAL_DIAGNOSTICS;
238
244
  const blockingOnly = options.blockingOnly === true;
239
245
  const log = options.log;
240
- const unsupportedLanguageLog = options.unsupportedLanguageLog ?? new Set();
246
+ const unsupportedLanguageLog = options.unsupportedLanguageLog ?? defaultUnsupportedLanguageLog;
241
247
  const diagnostics = [];
242
248
  const seenRuleIds = new Set();
243
249
  const suppressLinterOverlap = kind === "jsts" && hasEslintConfig(cwd);
@@ -249,15 +255,28 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
249
255
  const flushUnsupportedRuleSkips = () => {
250
256
  if (newlyUnsupported.size === 0)
251
257
  return;
258
+ const firstSeenLanguages = Array.from(newlyUnsupported.entries()).filter(([language]) => !unsupportedLanguageLog.has(language));
259
+ for (const [language] of firstSeenLanguages) {
260
+ unsupportedLanguageLog.add(language);
261
+ }
262
+ if (firstSeenLanguages.length === 0) {
263
+ newlyUnsupported.clear();
264
+ return;
265
+ }
266
+ for (const [language] of firstSeenLanguages)
267
+ unsupportedLanguageLog.add(language);
252
268
  logLatency({
253
269
  type: "phase",
254
270
  phase: "astgrep_napi_unsupported_rules_skipped",
255
271
  filePath,
256
272
  durationMs: 0,
257
273
  metadata: {
258
- skippedByLanguage: Object.fromEntries(Array.from(newlyUnsupported.entries(), ([language, ruleIds]) => [
274
+ skippedByLanguage: Object.fromEntries(firstSeenLanguages.map(([language, ruleIds]) => [
259
275
  language,
260
- { count: ruleIds.length, ruleIds },
276
+ {
277
+ count: ruleIds.length,
278
+ ruleIds: ruleIds.slice(0, UNSUPPORTED_RULE_ID_SAMPLE_SIZE),
279
+ },
261
280
  ])),
262
281
  },
263
282
  });
@@ -315,8 +334,7 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
315
334
  lang !== "typescript" &&
316
335
  lang !== "tsx" &&
317
336
  lang !== "javascript") {
318
- if (!unsupportedLanguageLog.has(rule.id)) {
319
- unsupportedLanguageLog.add(rule.id);
337
+ if (!unsupportedLanguageLog.has(lang)) {
320
338
  const ids = newlyUnsupported.get(lang) ?? [];
321
339
  ids.push(rule.id);
322
340
  newlyUnsupported.set(lang, ids);
@@ -6,9 +6,8 @@
6
6
  * mutating files mid-dispatch after LSP sync has already happened.
7
7
  */
8
8
  import * as path from "node:path";
9
- import { resolvePackagePath } from "../../package-root.js";
10
9
  import { safeSpawnAsync } from "../../safe-spawn.js";
11
- import { getAutofixCapability, getBiomeConfigPath, getJstsLintPolicyForCwd, } from "../../tool-policy.js";
10
+ import { biomeConfigArgs, getAutofixCapability, getJstsLintPolicyForCwd, } from "../../tool-policy.js";
12
11
  import { PRIORITY } from "../priorities.js";
13
12
  import { resolveToolCommandWithInstallFallback } from "./utils/runner-helpers.js";
14
13
  function parseBiomeJson(raw, filePath) {
@@ -60,13 +59,10 @@ const biomeCheckJsonRunner = {
60
59
  if (!cmd) {
61
60
  return { status: "skipped", diagnostics: [], semantic: "none" };
62
61
  }
63
- // Build config path — use user's if exists, else pi-lens config
64
- const userConfigPath = getBiomeConfigPath(cwd);
65
- const configArg = [
66
- "--config-path=" +
67
- (userConfigPath ??
68
- resolvePackagePath(import.meta.url, "config/biome/core.jsonc")),
69
- ];
62
+ // Shared config-args seam (#1247): `biomeClient.fixFileAsync` consumes
63
+ // the same builder, so the user's config / package fallback applies on
64
+ // `lint --write` too.
65
+ const configArg = biomeConfigArgs(cwd);
70
66
  // Run biome lint (diagnostics only - format is handled separately)
71
67
  const checkResult = await safeSpawnAsync(cmd, [
72
68
  "lint",
@@ -4,6 +4,7 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
4
4
  import { getLinterPolicyForCwd } from "../../tool-policy.js";
5
5
  import { PRIORITY } from "../priorities.js";
6
6
  import { createAvailabilityChecker } from "./utils/runner-helpers.js";
7
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
7
8
  const detekt = createAvailabilityChecker("detekt", ".bat");
8
9
  const DETEKT_CONFIG_CANDIDATES = [
9
10
  "detekt.yml",
@@ -145,10 +146,10 @@ const detektRunner = {
145
146
  return { status: "skipped", diagnostics: [], semantic: "none" };
146
147
  const absPath = path.resolve(cwd, ctx.filePath);
147
148
  const result = await safeSpawnAsync(cmd, ["--input", absPath, "--config", configPath], { cwd, timeout: 60000 });
148
- if (result.error && !result.stdout && !result.stderr) {
149
+ const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
150
+ if (spawnFailedWithNoOutput(result, raw)) {
149
151
  return { status: "skipped", diagnostics: [], semantic: "none" };
150
152
  }
151
- const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
152
153
  const diagnostics = parseDetektOutput(raw, ctx.filePath);
153
154
  if (diagnostics.length === 0) {
154
155
  return { status: "succeeded", diagnostics: [], semantic: "none" };
@@ -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, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
6
7
  const hadolint = createAvailabilityChecker("hadolint", ".exe");
7
8
  function parseHadolintOutput(raw, filePath) {
8
9
  try {
@@ -52,7 +53,7 @@ const hadolintRunner = {
52
53
  return { status: "skipped", diagnostics: [], semantic: "none" };
53
54
  }
54
55
  const result = await safeSpawnAsync(cmd, ["--format", "json", "--no-fail", path.resolve(cwd, ctx.filePath)], { cwd });
55
- if (result.error && !result.stdout) {
56
+ if (spawnFailedWithNoOutput(result)) {
56
57
  return { status: "skipped", diagnostics: [], semantic: "none" };
57
58
  }
58
59
  const output = result.stdout || "";
@@ -0,0 +1,154 @@
1
+ import * as path from "node:path";
2
+ import { PathKeyedMap } from "../../path-keyed-map.js";
3
+ import { normalizeMapKey } from "../../path-utils.js";
4
+ import { safeSpawnAsync } from "../../safe-spawn.js";
5
+ import { findNearestDirWithMarker } from "../../workspace-topology.js";
6
+ import { PRIORITY } from "../priorities.js";
7
+ import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
8
+ const helm = createAvailabilityChecker("helm", ".exe");
9
+ const inFlightByChartRoot = new PathKeyedMap(normalizeMapKey);
10
+ const HELM_LINT_TIMEOUT_MS = 30_000;
11
+ const SKIPPED = {
12
+ status: "skipped",
13
+ diagnostics: [],
14
+ semantic: "none",
15
+ };
16
+ function isWithin(root, candidate) {
17
+ const relative = path.relative(normalizeMapKey(root), normalizeMapKey(candidate));
18
+ return relative === "" || (!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative));
19
+ }
20
+ function diagnosticLocation(message, chartRoot) {
21
+ const location = message.match(/(?:^|\s)([^:\r\n]+\.(?:ya?ml|tpl|json))(?::(\d+))?(?::\d+)?(?::|\s)/i);
22
+ if (!location) {
23
+ return { filePath: path.join(chartRoot, "Chart.yaml"), message };
24
+ }
25
+ const candidate = path.resolve(chartRoot, location[1]);
26
+ return {
27
+ filePath: isWithin(chartRoot, candidate)
28
+ ? candidate
29
+ : path.join(chartRoot, "Chart.yaml"),
30
+ line: location[2] ? Number(location[2]) : undefined,
31
+ message,
32
+ };
33
+ }
34
+ export function parseHelmLintOutput(raw, chartRoot) {
35
+ const diagnostics = [];
36
+ for (const line of raw.split(/\r?\n/)) {
37
+ const match = line.trim().match(/^\[(INFO|WARNING|ERROR)\]\s*(.+)$/);
38
+ if (!match) {
39
+ // helm indents multi-line diagnostic detail under its [LEVEL] header
40
+ // (#1342 review): fold continuation text into the open diagnostic
41
+ // instead of silently dropping it.
42
+ const last = diagnostics[diagnostics.length - 1];
43
+ if (last && /^\s+\S/.test(line)) {
44
+ last.message += `
45
+ ${line.trim()}`;
46
+ }
47
+ continue;
48
+ }
49
+ const level = match[1];
50
+ const location = diagnosticLocation(match[2].trim(), chartRoot);
51
+ const severity = level === "ERROR" ? "error" : level === "WARNING" ? "warning" : "info";
52
+ diagnostics.push({
53
+ id: `helm-lint-${diagnostics.length + 1}-${level.toLowerCase()}`,
54
+ message: location.message,
55
+ filePath: location.filePath,
56
+ line: location.line,
57
+ column: 1,
58
+ severity,
59
+ semantic: severity === "error" ? "blocking" : "warning",
60
+ tool: "helm-lint",
61
+ rule: level.toLowerCase(),
62
+ fixable: false,
63
+ });
64
+ }
65
+ return diagnostics;
66
+ }
67
+ function failedResult(kind, message) {
68
+ return {
69
+ status: "failed",
70
+ diagnostics: [],
71
+ semantic: "warning",
72
+ failureKind: kind,
73
+ failureMessage: message.slice(0, 200),
74
+ };
75
+ }
76
+ async function lintChart(chartRoot, cwd) {
77
+ const cmd = await resolveAvailableOrInstall(helm, "helm", cwd);
78
+ if (!cmd) {
79
+ const outcome = helm.getOutcome(cwd);
80
+ return {
81
+ status: "failed",
82
+ diagnostics: [],
83
+ semantic: "warning",
84
+ failureKind: "unavailable",
85
+ failureMessage: `helm unavailable (${outcome ?? "unknown"})`,
86
+ };
87
+ }
88
+ const result = await safeSpawnAsync(cmd, ["lint", chartRoot], {
89
+ cwd,
90
+ timeout: HELM_LINT_TIMEOUT_MS,
91
+ deadlineAt: Date.now() + HELM_LINT_TIMEOUT_MS,
92
+ resourceLabel: "helm-lint",
93
+ });
94
+ const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
95
+ const diagnostics = parseHelmLintOutput(output, chartRoot);
96
+ const typedFailure = result.spawnFailure?.kind;
97
+ if (typedFailure) {
98
+ const failureKind = typedFailure === "tool-not-found"
99
+ ? "unavailable"
100
+ : typedFailure === "timeout"
101
+ ? "timeout"
102
+ : typedFailure === "killed" && result.failure === "aborted"
103
+ ? "aborted"
104
+ : "server_error";
105
+ return failedResult(failureKind, result.error?.message || `helm lint ${typedFailure}`);
106
+ }
107
+ if (result.failure) {
108
+ return failedResult(result.failure === "timeout" ? "timeout" : result.failure, result.error?.message || `helm lint ${result.failure}`);
109
+ }
110
+ if (result.outputTruncated) {
111
+ return failedResult("parser_error", "helm lint output was truncated before parsing completed");
112
+ }
113
+ const hasErrorDiagnostic = diagnostics.some((diagnostic) => diagnostic.severity === "error");
114
+ if (result.status !== 0 && !hasErrorDiagnostic) {
115
+ return failedResult(output.trim() ? "parser_error" : "server_error", output.trim() || "helm lint exited without an error diagnostic");
116
+ }
117
+ return {
118
+ status: "succeeded",
119
+ diagnostics,
120
+ semantic: diagnostics.some((item) => item.severity === "error")
121
+ ? "blocking"
122
+ : diagnostics.length > 0
123
+ ? "warning"
124
+ : "none",
125
+ };
126
+ }
127
+ const helmLintRunner = {
128
+ id: "helm-lint",
129
+ appliesTo: ["yaml", "helm-template"],
130
+ priority: PRIORITY.GENERAL_ANALYSIS,
131
+ enabledByDefault: true,
132
+ skipTestFiles: false,
133
+ timeoutMs: 35_000,
134
+ async run(ctx) {
135
+ const workspaceRoot = path.resolve(ctx.projectRoot ?? ctx.cwd);
136
+ const startDir = path.dirname(path.resolve(ctx.filePath));
137
+ const discovered = findNearestDirWithMarker(startDir, "chartYamlPath");
138
+ if (!discovered)
139
+ return SKIPPED;
140
+ const chartRoot = path.resolve(discovered);
141
+ if (!isWithin(workspaceRoot, chartRoot))
142
+ return SKIPPED;
143
+ const existing = inFlightByChartRoot.get(chartRoot);
144
+ if (existing)
145
+ return existing;
146
+ const promise = lintChart(chartRoot, ctx.cwd).finally(() => {
147
+ if (inFlightByChartRoot.get(chartRoot) === promise)
148
+ inFlightByChartRoot.delete(chartRoot);
149
+ });
150
+ inFlightByChartRoot.set(chartRoot, promise);
151
+ return promise;
152
+ },
153
+ };
154
+ export default helmLintRunner;
@@ -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, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
+ import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
6
7
  const htmlhint = createAvailabilityChecker("htmlhint");
7
8
  const HTMLHINT_RULES = {
8
9
  "tag-pair": true,
@@ -71,10 +72,10 @@ const htmlhintRunner = {
71
72
  "unix",
72
73
  path.resolve(cwd, ctx.filePath),
73
74
  ], { cwd });
74
- if (result.error && !result.stdout && !result.stderr) {
75
+ const output = result.stdout || result.stderr || "";
76
+ if (spawnFailedWithNoOutput(result, output)) {
75
77
  return { status: "skipped", diagnostics: [], semantic: "none" };
76
78
  }
77
- const output = result.stdout || result.stderr || "";
78
79
  const diagnostics = parseHtmlhintOutput(output, ctx.filePath);
79
80
  if (diagnostics.length === 0) {
80
81
  return { status: "succeeded", diagnostics: [], semantic: "none" };
@@ -16,6 +16,7 @@ import gleamCheckRunner from "./gleam-check.js";
16
16
  import goVetRunner from "./go-vet.js";
17
17
  import golangciRunner from "./golangci-lint.js";
18
18
  import hadolintRunner from "./hadolint.js";
19
+ import helmLintRunner from "./helm-lint.js";
19
20
  import htmlhintRunner from "./htmlhint.js";
20
21
  import javacRunner from "./javac.js";
21
22
  import ktlintRunner from "./ktlint.js";
@@ -40,6 +41,7 @@ import sqlfluffRunner from "./sqlfluff.js";
40
41
  import stylelintRunner from "./stylelint.js";
41
42
  import swiftlintRunner from "./swiftlint.js";
42
43
  import taploRunner from "./taplo.js";
44
+ import terragruntRunner from "./terragrunt.js";
43
45
  import tflintRunner from "./tflint.js";
44
46
  import trivyConfigRunner from "./trivy-config.js";
45
47
  import valeRunner from "./vale.js";
@@ -81,6 +83,7 @@ export function registerDefaultRunners(registry) {
81
83
  registry.register(factRulesRunner); // FactRule pipeline — all registered rules (priority 21)
82
84
  registry.register(htmlhintRunner); // HTML linting — tag pairs, attribute rules (priority 20)
83
85
  registry.register(hadolintRunner); // Dockerfile linting — syntax, best practices (priority 20)
86
+ registry.register(helmLintRunner); // Helm chart linting (priority 20)
84
87
  registry.register(valeRunner); // Prose/style linting for Markdown — config-gated (.vale.ini) (priority 30)
85
88
  registry.register(phpLintRunner); // PHP syntax validation via php -l (priority 20)
86
89
  registry.register(psScriptAnalyzerRunner); // PowerShell linting via PSScriptAnalyzer module (priority 20)
@@ -88,7 +91,8 @@ export function registerDefaultRunners(registry) {
88
91
  registry.register(ktlintRunner); // Kotlin linting via ktlint (priority 10)
89
92
  registry.register(detektRunner); // Kotlin static analysis via detekt (priority 20, config-gated)
90
93
  registry.register(tflintRunner); // Terraform linting via tflint (priority 20)
91
- registry.register(trivyConfigRunner); // IaC misconfig (Dockerfile/k8s) via trivy config (priority 20, trivy.enabled-gated)
94
+ registry.register(terragruntRunner); // Terragrunt linting via terragrunt hcl validate (priority 20)
95
+ registry.register(trivyConfigRunner); // IaC misconfig (Dockerfile/k8s/Terraform) via trivy config (priority 20, trivy.enabled-gated)
92
96
  registry.register(taploRunner); // TOML linting/validation via taplo (priority 10)
93
97
  registry.register(dartAnalyzeRunner); // Dart analysis via dart analyze (priority 20)
94
98
  registry.register(javacRunner); // Java compile diagnostics via javac (priority 20)