@herbertgao/pi-extensions 2026.9.0 → 2026.9.1

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 (293) hide show
  1. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +13 -1
  2. package/node_modules/@czottmann/pi-automode/README.md +20 -0
  3. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +1 -1
  4. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +2 -1
  5. package/node_modules/@czottmann/pi-automode/docs/defaults.md +3 -2
  6. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +38 -2
  7. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +5 -3
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +11 -3
  9. package/node_modules/@czottmann/pi-automode/package.json +1 -1
  10. package/node_modules/@pi-plugins/fast-mode/README.md +5 -3
  11. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
  12. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +20 -55
  13. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  14. package/node_modules/@pi-plugins/fast-mode/package.json +1 -1
  15. package/node_modules/pi-lens/CHANGELOG.md +988 -0
  16. package/node_modules/pi-lens/README.md +3 -0
  17. package/node_modules/pi-lens/config/biome/core.jsonc +11 -2
  18. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +13 -1
  19. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -2
  20. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
  21. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +13 -4
  22. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +123 -3
  23. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +60 -5
  24. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +2 -2
  25. package/node_modules/pi-lens/dist/clients/bash-file-access.js +1 -3
  26. package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
  27. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -0
  28. package/node_modules/pi-lens/dist/clients/bootstrap.js +509 -73
  29. package/node_modules/pi-lens/dist/clients/bounded-cache.js +152 -12
  30. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -4
  31. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
  32. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +2 -2
  33. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +31 -4
  34. package/node_modules/pi-lens/dist/clients/cache-manager.js +105 -6
  35. package/node_modules/pi-lens/dist/clients/cache-observability.js +44 -18
  36. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
  37. package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -2
  38. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +13 -3
  39. package/node_modules/pi-lens/dist/clients/complexity-client.js +16 -5
  40. package/node_modules/pi-lens/dist/clients/config-core/deny.js +221 -0
  41. package/node_modules/pi-lens/dist/clients/config-core/index.js +47 -0
  42. package/node_modules/pi-lens/dist/clients/config-core/merge.js +357 -0
  43. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +340 -0
  44. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +248 -0
  45. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +171 -0
  46. package/node_modules/pi-lens/dist/clients/config-core/records.js +218 -0
  47. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +125 -0
  48. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +78 -0
  49. package/node_modules/pi-lens/dist/clients/config-core/schema.js +167 -0
  50. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +281 -0
  51. package/node_modules/pi-lens/dist/clients/config-locations.js +160 -0
  52. package/node_modules/pi-lens/dist/clients/config-resolve.js +789 -0
  53. package/node_modules/pi-lens/dist/clients/config-schema.js +197 -0
  54. package/node_modules/pi-lens/dist/clients/config-warn.js +407 -0
  55. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -14
  56. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +2 -2
  57. package/node_modules/pi-lens/dist/clients/deadline-utils.js +178 -0
  58. package/node_modules/pi-lens/dist/clients/debug-handles.js +2 -2
  59. package/node_modules/pi-lens/dist/clients/debug-heap.js +3 -3
  60. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +106 -0
  61. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +113 -7
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +8 -19
  63. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
  64. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +14 -4
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -18
  66. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
  67. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -7
  68. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -1
  69. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +380 -26
  70. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -1
  71. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -1
  72. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -1
  73. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -1
  74. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -1
  75. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -1
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -1
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -1
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -1
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -1
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -1
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -1
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +1 -3
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -1
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -1
  85. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -1
  87. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -1
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -1
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -1
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +13 -18
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -1
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -1
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -1
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +7 -4
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -1
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -3
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -1
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -1
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -4
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +194 -80
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +84 -15
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
  121. package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -3
  122. package/node_modules/pi-lens/dist/clients/effective-config.js +403 -0
  123. package/node_modules/pi-lens/dist/clients/error-class.js +23 -0
  124. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +274 -0
  125. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -2
  126. package/node_modules/pi-lens/dist/clients/feature-hints.js +2 -1
  127. package/node_modules/pi-lens/dist/clients/file-time.js +6 -1
  128. package/node_modules/pi-lens/dist/clients/file-utils.js +112 -9
  129. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
  130. package/node_modules/pi-lens/dist/clients/format-service.js +6 -1
  131. package/node_modules/pi-lens/dist/clients/formatters.js +276 -102
  132. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
  133. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +114 -19
  134. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
  135. package/node_modules/pi-lens/dist/clients/git-guard.js +1 -1
  136. package/node_modules/pi-lens/dist/clients/go-client.js +39 -0
  137. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +252 -0
  138. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +424 -0
  139. package/node_modules/pi-lens/dist/clients/hook-budgets.js +76 -0
  140. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +5 -2
  141. package/node_modules/pi-lens/dist/clients/host-ports.js +1 -1
  142. package/node_modules/pi-lens/dist/clients/installer/index.js +71 -52
  143. package/node_modules/pi-lens/dist/clients/instance-reaper.js +104 -230
  144. package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
  145. package/node_modules/pi-lens/dist/clients/language-registry.js +595 -0
  146. package/node_modules/pi-lens/dist/clients/latency-logger.js +160 -2
  147. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +13 -0
  148. package/node_modules/pi-lens/dist/clients/lens-config.js +141 -30
  149. package/node_modules/pi-lens/dist/clients/lens-engine.js +30 -37
  150. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +59 -6
  151. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -2
  152. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
  153. package/node_modules/pi-lens/dist/clients/lsp/client.js +168 -30
  154. package/node_modules/pi-lens/dist/clients/lsp/config.js +483 -158
  155. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/lsp/edits.js +15 -2
  157. package/node_modules/pi-lens/dist/clients/lsp/index.js +676 -71
  158. package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -169
  159. package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
  160. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -16
  161. package/node_modules/pi-lens/dist/clients/lsp/server.js +284 -147
  162. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +116 -23
  163. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +2 -7
  164. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +9 -2
  165. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +163 -21
  167. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +36 -0
  168. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +33 -4
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +5 -16
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +8 -3
  171. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +2 -4
  172. package/node_modules/pi-lens/dist/clients/module-report.js +20 -45
  173. package/node_modules/pi-lens/dist/clients/mutating-tool.js +651 -0
  174. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +368 -0
  175. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +240 -0
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +247 -20
  177. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +101 -0
  178. package/node_modules/pi-lens/dist/clients/observed-mutation.js +1215 -0
  179. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +68 -22
  180. package/node_modules/pi-lens/dist/clients/opengrep-config.js +4 -0
  181. package/node_modules/pi-lens/dist/clients/package-manager.js +195 -26
  182. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +359 -80
  183. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +23 -7
  184. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +21 -2
  185. package/node_modules/pi-lens/dist/clients/path-utils.js +428 -13
  186. package/node_modules/pi-lens/dist/clients/persist-debounce.js +8 -1
  187. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +114 -0
  188. package/node_modules/pi-lens/dist/clients/pipeline.js +77 -16
  189. package/node_modules/pi-lens/dist/clients/probe-home-state.js +228 -0
  190. package/node_modules/pi-lens/dist/clients/process-bridge.js +66 -0
  191. package/node_modules/pi-lens/dist/clients/process-snapshot.js +68 -0
  192. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
  193. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
  194. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
  195. package/node_modules/pi-lens/dist/clients/project-lens-config.js +393 -122
  196. package/node_modules/pi-lens/dist/clients/project-snapshot.js +52 -24
  197. package/node_modules/pi-lens/dist/clients/python-environment.js +217 -0
  198. package/node_modules/pi-lens/dist/clients/python-provenance.js +639 -0
  199. package/node_modules/pi-lens/dist/clients/quiet-window.js +6 -1
  200. package/node_modules/pi-lens/dist/clients/read-bridge.js +13 -21
  201. package/node_modules/pi-lens/dist/clients/read-expansion.js +9 -46
  202. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +15 -4
  203. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
  204. package/node_modules/pi-lens/dist/clients/read-guard.js +21 -0
  205. package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
  206. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +152 -109
  207. package/node_modules/pi-lens/dist/clients/review-graph/service.js +55 -3
  208. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +7 -15
  209. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +10 -74
  210. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +9 -3
  211. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +18 -2
  212. package/node_modules/pi-lens/dist/clients/runtime-context.js +49 -16
  213. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +25 -6
  214. package/node_modules/pi-lens/dist/clients/runtime-session.js +139 -22
  215. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +168 -35
  216. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +797 -243
  217. package/node_modules/pi-lens/dist/clients/runtime-turn.js +1028 -53
  218. package/node_modules/pi-lens/dist/clients/rust-client.js +31 -0
  219. package/node_modules/pi-lens/dist/clients/safe-spawn.js +33 -10
  220. package/node_modules/pi-lens/dist/clients/sanitize.js +7 -1
  221. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +1 -3
  222. package/node_modules/pi-lens/dist/clients/security-scan-client.js +3 -0
  223. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +1 -1
  224. package/node_modules/pi-lens/dist/clients/session-start-observability.js +79 -0
  225. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
  226. package/node_modules/pi-lens/dist/clients/sgconfig.js +6 -1
  227. package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
  228. package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
  229. package/node_modules/pi-lens/dist/clients/string-utils.js +13 -0
  230. package/node_modules/pi-lens/dist/clients/subagent-mode.js +17 -4
  231. package/node_modules/pi-lens/dist/clients/test-runner-client.js +176 -39
  232. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +239 -0
  233. package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
  234. package/node_modules/pi-lens/dist/clients/tool-policy.js +91 -21
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +86 -48
  237. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  238. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +81 -1
  239. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +51 -46
  240. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +28 -0
  241. package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
  242. package/node_modules/pi-lens/dist/clients/user-notify.js +6 -2
  243. package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
  244. package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -2
  245. package/node_modules/pi-lens/dist/clients/word-index-store.js +20 -5
  246. package/node_modules/pi-lens/dist/clients/word-index.js +243 -31
  247. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
  248. package/node_modules/pi-lens/dist/clients/zizmor-config.js +3 -0
  249. package/node_modules/pi-lens/dist/index.js +64335 -54300
  250. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
  251. package/node_modules/pi-lens/dist/mcp/server.js +127 -5
  252. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +583 -0
  253. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +129 -0
  254. package/node_modules/pi-lens/dist/tools/effective-config.js +89 -0
  255. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +95 -24
  256. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +67 -80
  257. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
  258. package/node_modules/pi-lens/dist/tools/shared.js +0 -1
  259. package/node_modules/pi-lens/docs/agent-guide.md +64 -1
  260. package/node_modules/pi-lens/docs/configuration.md +222 -0
  261. package/node_modules/pi-lens/docs/dependencies.md +3 -3
  262. package/node_modules/pi-lens/docs/features.md +44 -5
  263. package/node_modules/pi-lens/docs/language-coverage.md +2 -2
  264. package/node_modules/pi-lens/docs/pi-lens-fixer.md +25 -0
  265. package/node_modules/pi-lens/docs/pi-lens-investigator.md +25 -0
  266. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +27 -0
  267. package/node_modules/pi-lens/docs/pi-lens-subagent.md +38 -0
  268. package/node_modules/pi-lens/docs/pi-lens-warden.md +55 -0
  269. package/node_modules/pi-lens/docs/public-api-stability.md +359 -0
  270. package/node_modules/pi-lens/docs/release-qa-baseline.md +182 -0
  271. package/node_modules/pi-lens/docs/subagent-compat.md +110 -30
  272. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +2 -2
  273. package/node_modules/pi-lens/package.json +15 -23
  274. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
  275. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
  276. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
  277. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +192 -1
  278. package/node_modules/pi-lens/scripts/install-selftest.mjs +58 -2
  279. package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +129 -0
  280. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
  281. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  282. package/node_modules/pi-web-access/README.md +62 -15
  283. package/node_modules/pi-web-access/curator-page.ts +3 -1
  284. package/node_modules/pi-web-access/curator-server.ts +5 -1
  285. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  286. package/node_modules/pi-web-access/github-extract.ts +242 -1
  287. package/node_modules/pi-web-access/index.ts +118 -64
  288. package/node_modules/pi-web-access/mistral-search.ts +281 -0
  289. package/node_modules/pi-web-access/package.json +2 -2
  290. package/node_modules/pi-web-access/perplexity.ts +14 -1
  291. package/node_modules/pi-web-access/utils.ts +23 -6
  292. package/node_modules/pi-web-access/xai-search.ts +96 -33
  293. package/package.json +5 -5
@@ -10,16 +10,16 @@
10
10
  */
11
11
  import * as fs from "node:fs";
12
12
  import * as path from "node:path";
13
+ import { incrementDegradationCount, recordDegradationOnce, } from "../../degradation-ledger.js";
13
14
  import { loadAstGrepNapi, } from "../../deps/ast-grep-napi.js";
14
15
  import { minimatch } from "../../deps/minimatch.js";
15
- import { getAstGrepRuleSources, } from "../../sgconfig.js";
16
16
  import { logLatency } from "../../latency-logger.js";
17
+ import { hasAuxiliaryLspPublishedForRoot } from "../../lsp/index.js";
18
+ import { clearPendingAuxiliaryCoverage, hasPendingAuxiliaryCoverage, recordNapiFallbackCoverage, } from "../../lsp/pending-aux-coverage.js";
19
+ import { getAstGrepRuleSources, } from "../../sgconfig.js";
17
20
  import { hasEslintConfig } from "../../tool-policy.js";
18
21
  import { enabledAuxiliaryLspServerIds } from "../auxiliary-lsp.js";
19
22
  import { classifyDefect } from "../diagnostic-taxonomy.js";
20
- import { incrementDegradationCount, recordDegradationOnce, } from "../../degradation-ledger.js";
21
- import { hasAuxiliaryLspPublishedForRoot } from "../../lsp/index.js";
22
- import { clearPendingAuxiliaryCoverage, hasPendingAuxiliaryCoverage, recordNapiFallbackCoverage, } from "../../lsp/pending-aux-coverage.js";
23
23
  import { PRIORITY } from "../priorities.js";
24
24
  import { calculateRuleComplexity, isOverlyBroadPattern, isStructuredRule, loadYamlRules, loadYamlRulesFresh, MAX_BLOCKING_RULE_COMPLEXITY, } from "./yaml-rule-parser.js";
25
25
  const defaultUnsupportedLanguageLog = new Set();
@@ -436,6 +436,218 @@ export function getLang(filePath, sgModule) {
436
436
  }
437
437
  return lang;
438
438
  }
439
+ /**
440
+ * Budget for embedded-`<script>` evaluation (#2347 review F2/F4). Every nonempty
441
+ * script body is reparsed as JS and EVERY `language: JavaScript` rule runs
442
+ * against it, so the work is `rules * bodies * body-size`, all multiplied by
443
+ * the native addon's per-call overhead. Measured on this seam (full catalog,
444
+ * real addon, 2026-08-30): ~8.5 ms per small body, ~9 s for 500 blocks, and
445
+ * ~19.5 s for one ~1 MiB dense body (the shape that made the byte axis the
446
+ * real bound). The caps apply to EVERY body — first one included — so an
447
+ * oversized single inline script is omitted and recorded like any other
448
+ * over-budget body. Hand-authored HTML carries a handful of small inline
449
+ * scripts, so the caps only ever trip on generated/pathological pages, where a
450
+ * bounded, recorded partial evaluation beats a seconds-long synchronous stall
451
+ * on the per-edit hook. Budget truncation is a coverage loss and is recorded
452
+ * (see `emitHtmlScriptDegradations`).
453
+ */
454
+ export const MAX_SCRIPT_BODIES_EVALUATED = 64;
455
+ /**
456
+ * Cumulative parsed script-body size cap; bounds the `rules * bytes` work.
457
+ * Every body — including the first — must fit within the running total.
458
+ */
459
+ export const MAX_SCRIPT_BODY_BYTES_EVALUATED = 128 * 1024;
460
+ /**
461
+ * UTF-16 code-unit indexes, in the original file, of every line start, newest
462
+ * line last. `@ast-grep/napi` reports line/column/index in UTF-16 code units
463
+ * (verified against 0.45.1 with `é` and emoji), so the line table must be
464
+ * built in the SAME unit; a UTF-8 byte walk would shift every coordinate that
465
+ * follows a multibyte character.
466
+ */
467
+ function computeLineStartsUtf16(content) {
468
+ const starts = [0];
469
+ for (let i = 0; i < content.length; i++) {
470
+ if (content.charCodeAt(i) === 0x0a)
471
+ starts.push(i + 1);
472
+ }
473
+ return starts;
474
+ }
475
+ /** 0-based line and code-unit column for a UTF-16 index, via binary search. */
476
+ function filePositionForIndex(lineStarts, index) {
477
+ let lo = 0;
478
+ let hi = lineStarts.length - 1;
479
+ while (lo < hi) {
480
+ const mid = (lo + hi + 1) >> 1;
481
+ if (lineStarts[mid] <= index)
482
+ lo = mid;
483
+ else
484
+ hi = mid - 1;
485
+ }
486
+ return { line: lo, column: index - lineStarts[lo] };
487
+ }
488
+ /**
489
+ * Extract every `<script>` body from an HTML root and parse it as JavaScript
490
+ * (#2347). Mirrors the ast-grep CLI/LSP: the injection is unconditional —
491
+ * `type` and `src` attributes do not suppress it (verified against the 0.45.1
492
+ * CLI with `text/template`, `application/ld+json`, and `src`-bearing script
493
+ * tags, all injected). Whitespace-only bodies are skipped (nothing to match).
494
+ * A body the JS grammar cannot parse is dropped the way an unparseable `.js`
495
+ * file would be; the failure is counted, never silent. The evaluation budget
496
+ * (count + cumulative bytes) is applied BEFORE any grammar parse. The caller
497
+ * emits the bounded degradation records from the result — collection stays
498
+ * pure so the count evidence is directly testable.
499
+ */
500
+ export function collectHtmlScriptInjections(htmlRoot, sgModule) {
501
+ // SAFETY: `AstGrepNapi` is the loaded addon module's own (typed) shape, so
502
+ // its `js` accessor is guaranteed present while the addon lives; this
503
+ // narrowing only names the subshape this helper consumes (a `js` grammar
504
+ // whose parses expose `findAll`), and the absence check right below
505
+ // degrades to "no embedded coverage" rather than throwing when the addon
506
+ // ever drops the grammar.
507
+ const addon = sgModule;
508
+ if (!addon.js) {
509
+ return {
510
+ injections: [],
511
+ scriptElementCount: 0,
512
+ bodiesEvaluated: 0,
513
+ truncatedBodies: 0,
514
+ parseFailures: 0,
515
+ missingJsGrammar: true,
516
+ htmlScanFailure: false,
517
+ };
518
+ }
519
+ let scripts;
520
+ try {
521
+ scripts = htmlRoot.findAll({ rule: { kind: "script_element" } });
522
+ }
523
+ catch {
524
+ return {
525
+ injections: [],
526
+ scriptElementCount: 0,
527
+ bodiesEvaluated: 0,
528
+ truncatedBodies: 0,
529
+ parseFailures: 0,
530
+ missingJsGrammar: false,
531
+ htmlScanFailure: true,
532
+ };
533
+ }
534
+ // Extract every nonempty body first (text extraction is cheap) so the raw
535
+ // script-element count is exact, then apply the budget BEFORE parsing any
536
+ // of them.
537
+ let scriptElementCount = 0;
538
+ const candidates = [];
539
+ for (const element of scripts) {
540
+ scriptElementCount += 1;
541
+ let raw;
542
+ for (const child of element.children()) {
543
+ if (child.kind() === "raw_text") {
544
+ raw = child;
545
+ break;
546
+ }
547
+ }
548
+ if (!raw)
549
+ continue;
550
+ const body = raw.text();
551
+ if (!body.trim())
552
+ continue;
553
+ candidates.push({
554
+ body,
555
+ startIndex: raw.range().start.index,
556
+ });
557
+ }
558
+ let budgetedBytes = 0;
559
+ const selected = [];
560
+ let truncatedBodies = 0;
561
+ for (const candidate of candidates) {
562
+ const bytes = Buffer.byteLength(candidate.body, "utf8");
563
+ // EVERY body must fit inside both caps — including the first. There is
564
+ // no "one big script" allowance: a single over-cap body (a ~1 MiB dense
565
+ // inline script measured 19.5 s of synchronous rule traversal on this
566
+ // seam) is omitted like any other over-budget body, and the omission is
567
+ // recorded via `truncatedBodies`, so the bounded
568
+ // `ast-grep-napi-html-script-budget` degradation record always explains
569
+ // why that file lost embedded coverage.
570
+ if (selected.length >= MAX_SCRIPT_BODIES_EVALUATED ||
571
+ budgetedBytes + bytes > MAX_SCRIPT_BODY_BYTES_EVALUATED) {
572
+ truncatedBodies += 1;
573
+ continue;
574
+ }
575
+ selected.push(candidate);
576
+ budgetedBytes += bytes;
577
+ }
578
+ const injections = [];
579
+ let parseFailures = 0;
580
+ for (const candidate of selected) {
581
+ try {
582
+ const root = addon.js.parse(candidate.body).root();
583
+ injections.push({
584
+ body: candidate.body,
585
+ startIndex: candidate.startIndex,
586
+ root,
587
+ });
588
+ }
589
+ catch {
590
+ parseFailures += 1;
591
+ }
592
+ }
593
+ return {
594
+ injections,
595
+ scriptElementCount,
596
+ bodiesEvaluated: selected.length,
597
+ truncatedBodies,
598
+ parseFailures,
599
+ missingJsGrammar: false,
600
+ htmlScanFailure: false,
601
+ };
602
+ }
603
+ /**
604
+ * Emit bounded, discriminating degradation records for every embedded-script
605
+ * coverage loss (#2347 review F3). Each failure mode keeps its own kind so the
606
+ * ledger answers WHICH failure and WHICH file; subjects are the normalized file
607
+ * path, bounded by the ledger's own per-kind window. Collection failures
608
+ * (`missingJsGrammar`, `htmlScanFailure`) are once-per-file-per-session
609
+ * categorical events; parse failures and budget truncation are counted per file
610
+ * so the EXACT totals survive past the retained-entry window.
611
+ */
612
+ function emitHtmlScriptDegradations(filePath, result) {
613
+ if (result.missingJsGrammar) {
614
+ recordDegradationOnce({
615
+ kind: "ast-grep-napi-html-js-grammar-missing",
616
+ subject: filePath,
617
+ reason: "addon exposes no js grammar; embedded <script> coverage dropped",
618
+ });
619
+ }
620
+ if (result.htmlScanFailure) {
621
+ recordDegradationOnce({
622
+ kind: "ast-grep-napi-html-script-scan-failed",
623
+ subject: filePath,
624
+ reason: "script_element enumeration failed; embedded <script> coverage dropped",
625
+ });
626
+ }
627
+ if (result.parseFailures > 0) {
628
+ incrementDegradationCount({
629
+ kind: "ast-grep-napi-html-script-parse-failed",
630
+ subject: filePath,
631
+ reason: `${result.parseFailures} of ${result.bodiesEvaluated} script bodies refused to parse as JS`,
632
+ metadata: {
633
+ scriptElementCount: result.scriptElementCount,
634
+ parseFailures: result.parseFailures,
635
+ },
636
+ });
637
+ }
638
+ if (result.truncatedBodies > 0) {
639
+ incrementDegradationCount({
640
+ kind: "ast-grep-napi-html-script-budget",
641
+ subject: filePath,
642
+ reason: `script budget truncated coverage: ${result.bodiesEvaluated}/${result.scriptElementCount} bodies evaluated, ${result.truncatedBodies} dropped`,
643
+ metadata: {
644
+ scriptElementCount: result.scriptElementCount,
645
+ bodiesEvaluated: result.bodiesEvaluated,
646
+ truncatedBodies: result.truncatedBodies,
647
+ },
648
+ });
649
+ }
650
+ }
439
651
  function duplicateRuleIds(rules) {
440
652
  const counts = new Map();
441
653
  for (const rule of rules) {
@@ -512,6 +724,38 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
512
724
  const seenRuleIds = new Set();
513
725
  const suppressLinterOverlap = kind === "jsts" && hasEslintConfig(cwd);
514
726
  const fileLang = ruleLanguageForFile(filePath);
727
+ // Embedded `<script>` coverage (#2347): on an HTML file, every script body
728
+ // is parsed as JavaScript and `language: JavaScript` rules run inside it —
729
+ // the exact behavior the ast-grep CLI/LSP has (verified against 0.45.1).
730
+ // `content` + `sgModule` are only needed for HTML; other callers of this
731
+ // shared seam (the per-edit runner and the project scanner both now pass
732
+ // them) cost a no-op on non-HTML files. The collection is budget-bounded
733
+ // and every silent-failure mode plus the budget cut is recorded, so "no
734
+ // embedded findings" stays distinguishable from "coverage was dropped"
735
+ // (#2347 review F2/F3).
736
+ const htmlCollection = fileLang === "html" &&
737
+ options.content !== undefined &&
738
+ options.sgModule !== undefined
739
+ ? collectHtmlScriptInjections(rootNode, options.sgModule)
740
+ : {
741
+ injections: [],
742
+ scriptElementCount: 0,
743
+ bodiesEvaluated: 0,
744
+ truncatedBodies: 0,
745
+ parseFailures: 0,
746
+ missingJsGrammar: false,
747
+ htmlScanFailure: false,
748
+ };
749
+ const htmlInjections = htmlCollection.injections;
750
+ emitHtmlScriptDegradations(filePath, htmlCollection);
751
+ // UTF-16 code-unit index of each line start in the ORIGINAL file, used to
752
+ // translate an injected match's body-relative UTF-16 index back to file
753
+ // line/column. The unit matters: napi positions are UTF-16, so a UTF-8 byte
754
+ // table would shift every coordinate after a multibyte character (#2347
755
+ // review F1).
756
+ const fileLineStarts = htmlInjections.length > 0 && options.content !== undefined
757
+ ? computeLineStartsUtf16(options.content)
758
+ : [];
515
759
  // Unsupported-language skips are expected in bulk (every non-jsts rule in the
516
760
  // catalog, e.g. ~30 Python rules) — aggregate them into ONE latency-log entry
517
761
  // per evaluation instead of per-rule terminal lines (#282 follow-up).
@@ -547,6 +791,18 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
547
791
  // ship for a language nobody decided a route for, which is the
548
792
  // class this issue closed regrowing.
549
793
  route: skipRouteFor(language),
794
+ // #2347 observability: on an HTML file the per-language skip
795
+ // count is only part of the picture — `mismatch:*->html`
796
+ // entries name a rule family that never enters scripts, and
797
+ // `htmlInlineScriptCount` says whether the file offered any
798
+ // script bodies to enter. A `javascript->html` mismatch here
799
+ // is necessarily `0` (JS rules RUN when scripts exist), so the
800
+ // field makes "no injection target" distinguishable from the
801
+ // same key on a plain non-HTML file, keeping the residual
802
+ // coverage gap countable in production.
803
+ ...(fileLang === "html"
804
+ ? { htmlInlineScriptCount: htmlInjections.length }
805
+ : {}),
550
806
  },
551
807
  ])),
552
808
  },
@@ -627,9 +883,20 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
627
883
  // rules) goes dark on every .tsx file. `language: TSX` rules
628
884
  // stay tsx-exclusive — they're already scoped to fileLang
629
885
  // "tsx" by the exact-match check.
886
+ // #2347: `language: JavaScript` rules run INSIDE an HTML file's
887
+ // embedded `<script>` bodies instead of being filtered out as a
888
+ // language mismatch — that filter is what closed napi's embedded
889
+ // coverage entirely while the ast-grep CLI/LSP resolves the
890
+ // injections itself. Only when the file has at least one inline
891
+ // script body; with none, a `javascript->html` rule stays a
892
+ // genuine mismatch with nothing to run against (countable via
893
+ // `htmlInlineScriptCount` in the skip record).
894
+ const runsInsideHtmlScript = fileLang === "html" &&
895
+ lang === "javascript" &&
896
+ htmlInjections.length > 0;
630
897
  if (lang && fileLang && lang !== fileLang) {
631
898
  const runsAsTsOnTsx = fileLang === "tsx" && lang === "typescript";
632
- if (!runsAsTsOnTsx) {
899
+ if (!runsAsTsOnTsx && !runsInsideHtmlScript) {
633
900
  const key = `mismatch:${lang}->${fileLang}`;
634
901
  if (!unsupportedLanguageLog.has(key)) {
635
902
  const ids = newlyUnsupported.get(key) ?? [];
@@ -648,7 +915,31 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
648
915
  if (!rule.rule)
649
916
  continue;
650
917
  try {
651
- let matches = [];
918
+ // A `language: JavaScript` rule on an HTML file with inline
919
+ // scripts runs against EACH parsed script body; every other rule
920
+ // runs against the file root. `scope.position` maps a match onto
921
+ // 0-based FILE line/column — injection matches are body-relative
922
+ // and must be translated via the injection's `startIndex` and the
923
+ // file's line-start table, all in UTF-16 code units (#2347); the
924
+ // file-root scope is the node's own range, so its derived
925
+ // id/diagnostic stay byte-identical to the pre-#2347 path.
926
+ const scopes = runsInsideHtmlScript
927
+ ? htmlInjections.map((injection) => ({
928
+ root: injection.root,
929
+ position(match) {
930
+ const start = match.range().start;
931
+ return filePositionForIndex(fileLineStarts, injection.startIndex + start.index);
932
+ },
933
+ }))
934
+ : [
935
+ {
936
+ root: rootNode,
937
+ position(match) {
938
+ const start = match.range().start;
939
+ return { line: start.line, column: start.column };
940
+ },
941
+ },
942
+ ];
652
943
  // Delegate matching to napi's native engine, which handles the
653
944
  // full ast-grep rule grammar (pattern, kind, has/inside/follows/
654
945
  // precedes/stopBy/field/nthChild, any/all/not) plus metavariable
@@ -657,28 +948,41 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
657
948
  // (#663; `NapiConfig.utils: Record<string, Rule>` per
658
949
  // @ast-grep/napi's types, same shape napi already expects for
659
950
  // `rule`/`constraints`). A faithful js-yaml parse feeds the rule
660
- // object straight through. If napi rejects the rule (a malformed
661
- // or invalid-kind rule, or an unresolved `matches:` reference),
662
- // skip it — never silently match nothing through a partial
663
- // interpreter.
951
+ // object straight through. If napi rejects the rule for a scope
952
+ // (a malformed or invalid-kind rule, or an unresolved `matches:`
953
+ // reference), skip that scope — never silently match nothing
954
+ // through a partial interpreter. The reject log fires once per
955
+ // rule; a grammar-level rejection is uniform across scopes.
664
956
  const nativeConfig = { rule: rule.rule };
665
957
  if (rule.constraints)
666
958
  nativeConfig.constraints = rule.constraints;
667
959
  if (rule.utils)
668
960
  nativeConfig.utils = rule.utils;
669
- try {
670
- matches = rootNode.findAll(nativeConfig);
671
- }
672
- catch (err) {
673
- matches = [];
674
- log?.(`ast-grep-napi: rule "${rule.id}" rejected by native engine (${err instanceof Error ? err.message : String(err)})`);
961
+ const collected = [];
962
+ let rejectLogged = false;
963
+ for (const scope of scopes) {
964
+ let found;
965
+ try {
966
+ found = scope.root.findAll(nativeConfig);
967
+ }
968
+ catch (err) {
969
+ if (!rejectLogged) {
970
+ rejectLogged = true;
971
+ log?.(`ast-grep-napi: rule "${rule.id}" rejected by native engine (${err instanceof Error ? err.message : String(err)})`);
972
+ }
973
+ continue;
974
+ }
975
+ for (const match of found) {
976
+ if (collected.length >= maxMatchesPerRule)
977
+ break;
978
+ collected.push({ match, position: scope.position(match) });
979
+ }
980
+ if (collected.length >= maxMatchesPerRule)
981
+ break;
675
982
  }
676
- const limitedMatches = matches.slice(0, maxMatchesPerRule);
677
- for (const match of limitedMatches) {
983
+ for (const { position } of collected) {
678
984
  if (diagnostics.length >= maxTotalDiagnostics)
679
985
  break;
680
- const node = match;
681
- const range = node.range();
682
986
  // #1777: carry the rule's own tier through. The old collapse
683
987
  // (`=== "error" ? "error" : "warning"`) erased hint and info,
684
988
  // so the quiet tier the #1727 anti-slop rules ship at did not
@@ -691,11 +995,11 @@ export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}
691
995
  const defectClass = classifyDefect(rule.id, "ast-grep-napi", rule.message || rule.id);
692
996
  const ruleFix = explicitRuleFixSuggestion(rule);
693
997
  diagnostics.push({
694
- id: `ast-grep-napi-${range.start.line}-${rule.id}`,
998
+ id: `ast-grep-napi-${position.line}-${rule.id}`,
695
999
  message: `[${rule.metadata?.category || "slop"}] ${rule.message || rule.id}`,
696
1000
  filePath,
697
- line: range.start.line + 1,
698
- column: range.start.column + 1,
1001
+ line: position.line + 1,
1002
+ column: position.column + 1,
699
1003
  severity,
700
1004
  semantic,
701
1005
  tool: "ast-grep-napi",
@@ -725,7 +1029,6 @@ const astGrepNapiRunner = {
725
1029
  id: "ast-grep-napi",
726
1030
  appliesTo: ["jsts", "css", "html"],
727
1031
  priority: PRIORITY.SPECIALIZED_ANALYSIS,
728
- enabledByDefault: true,
729
1032
  skipTestFiles: true,
730
1033
  async run(ctx) {
731
1034
  if (!canHandle(ctx.filePath)) {
@@ -812,7 +1115,12 @@ const astGrepNapiRunner = {
812
1115
  catch {
813
1116
  return { status: "skipped", diagnostics: [], semantic: "none" };
814
1117
  }
815
- if (astGrepLspEnabled && !astGrepLspPublished) {
1118
+ // #2336: napi is standing in for the ast-grep auxiliary LSP exactly when
1119
+ // that server is expected but has not published for this root. Gate B
1120
+ // above already returned for the published case, so reaching here with
1121
+ // the auxiliary enabled IS the substitute role.
1122
+ const runningAsLspSubstitute = astGrepLspEnabled && !astGrepLspPublished;
1123
+ if (runningAsLspSubstitute) {
816
1124
  // #2324 F3/R2-A/R2-B: napi is about to ACTUALLY EVALUATE RULES —
817
1125
  // every early-return skip above (load failure, missing file,
818
1126
  // unresolved language, stat/size/read/parse failure) is now behind
@@ -837,11 +1145,57 @@ const astGrepNapiRunner = {
837
1145
  recordNapiFallbackCoverage(ctx.filePath);
838
1146
  clearPendingAuxiliaryCoverage(ctx.filePath, "ast-grep");
839
1147
  }
1148
+ // #2336: the substitute runs at the severity floor the server it replaces
1149
+ // would have used. The ast-grep auxiliary profile states that floor in
1150
+ // words — "the rule severity is deliberate, so preserve ast-grep's
1151
+ // severity semantics: ERROR can block, WARNING/INFO stay advisory"
1152
+ // (clients/dispatch/auxiliary-lsp.ts:179-183). `blockingOnly` drops every
1153
+ // rule whose declared severity is not `error`, which is 380 of the 481
1154
+ // bundled rules, so the substitute delivered a fifth of the coverage the
1155
+ // LSP delivers and the runner reported zero diagnostics in all 255
1156
+ // retained dispatch records. Nothing downstream needs the filter for
1157
+ // noise control: `dispatcher.ts` already shows only `semantic:
1158
+ // "blocking"` diagnostics inline and routes warning-tier ones to
1159
+ // lens_diagnostics, and `tree-sitter.ts:525` already runs its full query
1160
+ // set under `blockingOnly` for the same reason.
1161
+ //
1162
+ // Scoped to the substitute role deliberately. Evaluating the full catalog
1163
+ // costs ~6x more per file (measured on this repo: 2.4 ms -> 23 ms at 68
1164
+ // lines, 19 ms -> 188 ms at 1275 lines), and outside the substitute role
1165
+ // either the LSP is publishing (Gate B skipped napi already) or the user
1166
+ // retired ast-grep with `no-ast-grep`. Paying the cost only when napi is
1167
+ // the sole ast-grep surface buys coverage that nothing else provides.
840
1168
  const diagnostics = evaluateAstGrepRules(ctx.filePath, rootNode, ctx.cwd, ctx.kind, {
841
- blockingOnly: ctx.blockingOnly,
1169
+ blockingOnly: runningAsLspSubstitute ? false : ctx.blockingOnly,
842
1170
  projectRoot: ctx.projectRoot,
843
1171
  log: (message) => ctx.log(message),
1172
+ content,
1173
+ sgModule,
844
1174
  });
1175
+ if (runningAsLspSubstitute) {
1176
+ // #2336 observability: the dispatcher's own runner record carries
1177
+ // `diagnosticCount`, which is what showed 0 of 255. It cannot say WHICH
1178
+ // severity floor produced that count. One line per substitute run —
1179
+ // the same cadence as the runner record it annotates — names the floor
1180
+ // and the tier mix, so a future "napi found nothing" reading can tell
1181
+ // an empty catalog pass from a filtered one.
1182
+ const bySeverity = {};
1183
+ for (const d of diagnostics) {
1184
+ bySeverity[d.severity] = (bySeverity[d.severity] ?? 0) + 1;
1185
+ }
1186
+ logLatency({
1187
+ type: "phase",
1188
+ phase: "astgrep_napi_substitute_floor",
1189
+ filePath: ctx.filePath,
1190
+ durationMs: 0,
1191
+ metadata: {
1192
+ floor: "lsp-equivalent",
1193
+ ctxBlockingOnly: ctx.blockingOnly === true,
1194
+ diagnosticCount: diagnostics.length,
1195
+ bySeverity,
1196
+ },
1197
+ });
1198
+ }
845
1199
  const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
846
1200
  let semantic = "none";
847
1201
  if (hasBlocking) {
@@ -197,7 +197,6 @@ const biomeCheckJsonRunner = {
197
197
  id: "biome-check-json",
198
198
  appliesTo: ["jsts"],
199
199
  priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
200
- enabledByDefault: true,
201
200
  async run(ctx) {
202
201
  const cwd = ctx.cwd || path.dirname(ctx.filePath);
203
202
  const policy = getJstsLintPolicyForCwd(cwd);
@@ -175,7 +175,6 @@ const cppCheckRunner = {
175
175
  id: "cpp-check",
176
176
  appliesTo: ["cxx"],
177
177
  priority: PRIORITY.GENERAL_ANALYSIS,
178
- enabledByDefault: true,
179
178
  skipTestFiles: false,
180
179
  async run(ctx) {
181
180
  const cwd = ctx.cwd || process.cwd();
@@ -48,7 +48,6 @@ const credoRunner = {
48
48
  id: "credo",
49
49
  appliesTo: ["elixir"],
50
50
  priority: PRIORITY.GENERAL_ANALYSIS,
51
- enabledByDefault: true,
52
51
  skipTestFiles: false,
53
52
  async run(ctx) {
54
53
  const cwd = ctx.cwd || process.cwd();
@@ -278,7 +278,6 @@ const cueVetRunner = {
278
278
  id: "cue-vet",
279
279
  appliesTo: ["cue"],
280
280
  priority: PRIORITY.GENERAL_ANALYSIS,
281
- enabledByDefault: true,
282
281
  skipTestFiles: false,
283
282
  timeoutMs: 30_000,
284
283
  async run(ctx) {
@@ -145,7 +145,6 @@ const dartAnalyzeRunner = {
145
145
  id: "dart-analyze",
146
146
  appliesTo: ["dart"],
147
147
  priority: PRIORITY.GENERAL_ANALYSIS,
148
- enabledByDefault: true,
149
148
  skipTestFiles: false,
150
149
  async run(ctx) {
151
150
  const cwd = ctx.cwd || process.cwd();
@@ -126,7 +126,6 @@ const detektRunner = {
126
126
  id: "detekt",
127
127
  appliesTo: ["kotlin"],
128
128
  priority: PRIORITY.GENERAL_ANALYSIS,
129
- enabledByDefault: true,
130
129
  timeoutMs: 90_000,
131
130
  skipTestFiles: false,
132
131
  async run(ctx) {
@@ -115,7 +115,6 @@ const dotnetBuildRunner = {
115
115
  id: "dotnet-build",
116
116
  appliesTo: ["csharp"],
117
117
  priority: PRIORITY.GENERAL_ANALYSIS,
118
- enabledByDefault: true,
119
118
  timeoutMs: 90_000,
120
119
  skipTestFiles: false,
121
120
  async run(ctx) {
@@ -139,7 +139,6 @@ const elixirCheckRunner = {
139
139
  id: "elixir-check",
140
140
  appliesTo: ["elixir"],
141
141
  priority: PRIORITY.GENERAL_ANALYSIS,
142
- enabledByDefault: true,
143
142
  skipTestFiles: false,
144
143
  async run(ctx) {
145
144
  const cwd = ctx.cwd || process.cwd();
@@ -78,7 +78,6 @@ const eslintRunner = {
78
78
  id: "eslint",
79
79
  appliesTo: ["jsts"],
80
80
  priority: PRIORITY.LINT_SECONDARY,
81
- enabledByDefault: true,
82
81
  async run(ctx) {
83
82
  const cwd = ctx.cwd || process.cwd();
84
83
  const userHasConfig = hasEslintConfig(cwd);
@@ -13,7 +13,6 @@ const factRulesRunner = {
13
13
  id: "fact-rules",
14
14
  appliesTo: ["jsts", "python", "go", "rust", "ruby", "shell", "cmake"],
15
15
  priority: PRIORITY.GENERAL_ANALYSIS + 1,
16
- enabledByDefault: true,
17
16
  async run(ctx) {
18
17
  const diagnostics = evaluateRules(ctx);
19
18
  if (diagnostics.length === 0) {
@@ -7,7 +7,6 @@ const fishIndentRunner = {
7
7
  id: "fish-indent",
8
8
  appliesTo: ["fish"],
9
9
  priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
10
- enabledByDefault: true,
11
10
  skipTestFiles: false,
12
11
  async run(ctx) {
13
12
  const cwd = ctx.cwd || process.cwd();
@@ -39,7 +39,6 @@ const gleamCheckRunner = {
39
39
  id: "gleam-check",
40
40
  appliesTo: ["gleam"],
41
41
  priority: PRIORITY.GENERAL_ANALYSIS,
42
- enabledByDefault: true,
43
42
  skipTestFiles: false,
44
43
  async run(ctx) {
45
44
  const cwd = ctx.cwd || process.cwd();
@@ -4,18 +4,16 @@
4
4
  * Runs `go vet` for Go files to catch common mistakes.
5
5
  */
6
6
  import { relative, resolve, sep, posix } from "node:path";
7
- import { GoClient } from "../../go-client.js";
7
+ import { goClient } from "../../go-client.js";
8
8
  import { safeSpawnAsync } from "../../safe-spawn.js";
9
9
  import { stripAnsi } from "../../sanitize.js";
10
10
  import { skipUnlessToolRan } from "./utils/tool-failure.js";
11
11
  import { parseGoVetOutput } from "./utils/diagnostic-parsers.js";
12
12
  import { PRIORITY } from "../priorities.js";
13
- const goClient = new GoClient();
14
13
  const goVetRunner = {
15
14
  id: "go-vet",
16
15
  appliesTo: ["go"],
17
16
  priority: PRIORITY.SPECIALIZED_ANALYSIS,
18
- enabledByDefault: true,
19
17
  timeoutMs: 40_000,
20
18
  async run(ctx) {
21
19
  // Resolve go path using platform-aware lookup (handles system install paths on Windows)
@@ -78,7 +78,6 @@ const golangciRunner = {
78
78
  id: "golangci-lint",
79
79
  appliesTo: ["go"],
80
80
  priority: PRIORITY.GENERAL_ANALYSIS,
81
- enabledByDefault: true,
82
81
  timeoutMs: 90_000,
83
82
  async run(ctx) {
84
83
  const cwd = ctx.cwd || process.cwd();
@@ -35,7 +35,6 @@ const hadolintRunner = {
35
35
  id: "hadolint",
36
36
  appliesTo: ["docker"],
37
37
  priority: PRIORITY.GENERAL_ANALYSIS,
38
- enabledByDefault: true,
39
38
  skipTestFiles: false,
40
39
  async run(ctx) {
41
40
  const cwd = ctx.cwd || process.cwd();
@@ -144,7 +144,6 @@ const helmLintRunner = {
144
144
  id: "helm-lint",
145
145
  appliesTo: ["yaml", "helm-template"],
146
146
  priority: PRIORITY.GENERAL_ANALYSIS,
147
- enabledByDefault: true,
148
147
  skipTestFiles: false,
149
148
  timeoutMs: 35_000,
150
149
  async run(ctx) {