@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
@@ -23,39 +23,7 @@ import { isBlocking, reconcileScanDiagnostics, } from "../clients/widget-state.j
23
23
  import { baseName, compactRenderResult } from "./render-compact.js";
24
24
  import { makeProgressReporter, scanningSummaryLine } from "./scan-progress.js";
25
25
  import { isWarmAttached, tryWarmAttachedDiagnostics, } from "../clients/warm-attach.js";
26
- const LANG_EXTENSIONS = {
27
- ".ts": [".ts", ".tsx", ".mts", ".cts"],
28
- ".tsx": [".ts", ".tsx", ".mts", ".cts"],
29
- ".js": [".js", ".jsx", ".mjs", ".cjs"],
30
- ".py": [".py", ".pyi"],
31
- ".rs": [".rs"],
32
- ".go": [".go"],
33
- ".rb": [".rb", ".rake", ".gemspec"],
34
- ".java": [".java"],
35
- ".kt": [".kt", ".kts"],
36
- ".swift": [".swift"],
37
- ".cs": [".cs"],
38
- ".cpp": [".cpp", ".cc", ".cxx", ".hpp", ".hxx"],
39
- ".c": [".c", ".h"],
40
- ".zig": [".zig", ".zon"],
41
- ".hs": [".hs", ".lhs"],
42
- ".ex": [".ex", ".exs"],
43
- ".gleam": [".gleam"],
44
- ".tf": [".tf", ".tfvars"],
45
- ".nix": [".nix"],
46
- ".sh": [".sh", ".bash", ".zsh"],
47
- ".php": [".php"],
48
- ".lua": [".lua"],
49
- ".dart": [".dart"],
50
- ".vue": [".vue"],
51
- ".svelte": [".svelte"],
52
- ".css": [".css", ".scss", ".less"],
53
- ".html": [".html", ".htm"],
54
- ".json": [".json", ".jsonc"],
55
- ".yaml": [".yaml", ".yml"],
56
- ".toml": [".toml"],
57
- ".prisma": [".prisma"],
58
- };
26
+ import { extensionsForLanguage, SCAN_LANGUAGE_PRIORITY, } from "../clients/language-registry.js";
59
27
  const MAX_FILES = 100;
60
28
  const MAX_BATCH_FILES = 100;
61
29
  const MAX_DIAGNOSTICS = 200;
@@ -192,9 +160,10 @@ function projectIgnorePredicate(root) {
192
160
  * This walk was fully synchronous with NO yielding of any kind, bounded only by
193
161
  * `maxFiles` *kept* — an ignored-heavy or cloud-backed (OneDrive/network) tree
194
162
  * could traverse unboundedly many entries, and a single stalled `readdirSync`
195
- * held the loop for the whole stall. It is also called once PER LANGUAGE in
196
- * `runDirectoryDiagnostics`'s `LANG_EXTENSIONS` loop, so a directory-mode
197
- * `lsp_diagnostics` could pay that cost several times over.
163
+ * held the loop for the whole stall. It is also called once PER FAMILY in
164
+ * `runDirectoryDiagnostics`'s `SCAN_LANGUAGE_PRIORITY` loop (#2434, grouped by
165
+ * family since #2458 fix-round F1), so a directory-mode `lsp_diagnostics`
166
+ * could pay that cost several times over.
198
167
  *
199
168
  * The traversal is deliberately still **depth-first with immediate descent**
200
169
  * (not the shared stack-based `walkTreeStackAsync`): the `maxFiles` cap makes
@@ -456,13 +425,17 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
456
425
  // `touchFile` is the authoritative collection boundary for every scope: it
457
426
  // preserves per-touch timeout, content-binding, and silent-clean confirmation
458
427
  // metadata while returning diagnostics from only the requested clients. The
459
- // legacy openFile/getDiagnostics path remains only for an older/mock service
460
- // without touchFile, or when touchFile cannot resolve any clients.
428
+ // getDiagnostics fallback below remains for the two states a REAL service
429
+ // still reaches: the file read threw (no content to touch with), or the
430
+ // touch resolved no clients and returned `undefined` (clients/lsp/index.ts
431
+ // `touchFile`'s `no_clients`/`destroyed` returns). #2598 deleted the third
432
+ // reason — "an older/mock service without touchFile" — because the real
433
+ // `LSPService` has always defined the method unconditionally, so that arm
434
+ // was reachable only from a partial test double (AGENTS.md shape 7).
461
435
  // #1179: the result is an explicit wrapper so side-channel fields survive
462
436
  // array copies; confirmation was added when Marksman's lower-level clean verdict
463
437
  // proved that a successful empty collection also needs explicit provenance.
464
438
  let touched;
465
- let usedTouch = false;
466
439
  try {
467
440
  content = fs.readFileSync(absPath, "utf-8");
468
441
  if (isWarmAttached()) {
@@ -501,35 +474,25 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
501
474
  };
502
475
  }
503
476
  }
504
- const serviceWithTouch = lspService;
505
- if (typeof serviceWithTouch.touchFile === "function") {
506
- usedTouch = true;
507
- touched = await serviceWithTouch.touchFile(absPath, content, {
508
- diagnostics: "document",
509
- collectDiagnostics: true,
510
- maxClientWaitMs: waitMs,
511
- source: "lsp_diagnostics",
512
- clientScope: serverScope,
513
- });
514
- timedOut = touched?.inconclusive === true;
515
- }
516
- else {
517
- await lspService.openFile(absPath, content, {
518
- preserveDiagnostics: false,
519
- });
520
- }
477
+ touched = await lspService.touchFile(absPath, content, {
478
+ diagnostics: "document",
479
+ collectDiagnostics: true,
480
+ maxClientWaitMs: waitMs,
481
+ source: "lsp_diagnostics",
482
+ clientScope: serverScope,
483
+ });
484
+ timedOut = touched?.inconclusive === true;
521
485
  }
522
486
  catch {
523
487
  // Non-fatal: getDiagnostics may still have stale/health information.
524
488
  }
525
489
  // Only fall through to the unscoped getDiagnostics() read when the touch
526
- // branch wasn't taken (openFile-only path, which never collected anything
527
- // and genuinely needs the follow-up call) or couldn't resolve any clients
528
- // at all (touched stays undefined despite usedTouch). When touched IS
529
- // defined it's already the answer reusing it is what makes
530
- // serverScope:"primary" actually skip auxiliary scanners and drops the
531
- // common case back to a single LSP round trip instead of two.
532
- const diagnostics = usedTouch && touched !== undefined
490
+ // produced nothing to read — it threw, the file read threw before it ran, or
491
+ // it resolved no clients at all. When touched IS defined it's already the
492
+ // answer reusing it is what makes serverScope:"primary" actually skip
493
+ // auxiliary scanners and drops the common case back to a single LSP round
494
+ // trip instead of two.
495
+ const diagnostics = touched !== undefined
533
496
  ? touched.diags
534
497
  : await lspService.getDiagnostics(absPath, waitMs !== undefined ? "document" : "full");
535
498
  // #586: honor each auxiliary profile's native inline-suppression comment
@@ -546,25 +509,25 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
546
509
  fileRole: detectFileRole(absPath, content),
547
510
  })
548
511
  : diagnostics;
549
- // #1095: surface the touch's content binding (only the touch path carries
550
- // one; the openFile-only / getDiagnostics fallback leaves it undefined →
512
+ // #1095: surface the touch's content binding (only a touch that resolved
513
+ // clients carries one; the getDiagnostics fallback leaves it undefined →
551
514
  // "unknown", no demotion).
552
- const binding = usedTouch ? touched?.binding : undefined;
515
+ const binding = touched?.binding;
553
516
  // #1470: `"partial"` counts here. `confirmedByTouch` feeds
554
517
  // `canTrustTouchConfirmation`, which asks about the PRIMARY's own verdict —
555
518
  // and a partial touch is one whose primary confirmed while an auxiliary was
556
519
  // cut off. Excluding it would render "Primary LSP: unconfirmed" for a primary
557
520
  // that did confirm. The coverage gap is carried separately, below.
558
- const confirmedByTouch = usedTouch && touchCompletedConfirmationPolicy(touched);
521
+ const confirmedByTouch = touchCompletedConfirmationPolicy(touched);
559
522
  return {
560
523
  diagnostics: filtered,
561
524
  timedOut,
562
525
  skipReason: touched?.skipReason,
563
526
  confirmedByTouch,
564
- // #1470: only a touch actually contributes a coverage gap; the
565
- // openFile+getDiagnostics fallback never reports one, which is honest —
566
- // that path claims no confirmation at all.
567
- unconfirmedServerIds: usedTouch ? touchCoverageGap(touched) : [],
527
+ // #1470: only a touch that resolved clients contributes a coverage gap;
528
+ // the getDiagnostics fallback never reports one, which is honest — that
529
+ // path claims no confirmation at all.
530
+ unconfirmedServerIds: touchCoverageGap(touched),
568
531
  content,
569
532
  binding,
570
533
  };
@@ -1350,18 +1313,42 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
1350
1313
  },
1351
1314
  };
1352
1315
  }
1316
+ /**
1317
+ * The scan-language DECISION `runDirectoryDiagnostics` makes, pulled out as
1318
+ * its own function so `tests/tools/lsp-diagnostics-scan-family.test.ts` can
1319
+ * pin it against the golden `LANG_EXTENSIONS` table for every 1- and
1320
+ * 2-extension combination in that table's universe without spinning up one
1321
+ * real directory (and the full LSP-mocked tool) per combination — `hasMatch`
1322
+ * is the only I/O-shaped seam, so the caller decides whether it is backed by
1323
+ * a real `collectFiles` walk (production) or an in-memory extension-set probe
1324
+ * (tests).
1325
+ *
1326
+ * Walks `SCAN_LANGUAGE_PRIORITY`'s FAMILIES in order and unions each member
1327
+ * id's {@link extensionsForLanguage} into ONE `hasMatch` call — the first
1328
+ * family with any match wins the whole directory for this pass. Grouping by
1329
+ * family (not trying each id alone) is what makes a directory mixing BOTH
1330
+ * extensions of a registry-split pair (`.ts`+`.tsx`, `.css`+`.scss`, ...)
1331
+ * behavior-preserving vs the pre-#2434 bundled-key table: a flat per-id loop
1332
+ * stopped at the first id with ANY match, silently losing the sibling half of
1333
+ * a split pair present in the same directory (#2458 fix-round F1).
1334
+ */
1335
+ export async function resolveDirectoryScanExtensions(hasMatch) {
1336
+ for (const family of SCAN_LANGUAGE_PRIORITY) {
1337
+ const exts = family.flatMap((languageId) => extensionsForLanguage(languageId));
1338
+ if (await hasMatch(exts)) {
1339
+ return exts;
1340
+ }
1341
+ }
1342
+ return undefined;
1343
+ }
1353
1344
  async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
1354
- let extension;
1355
1345
  let collectedFiles = [];
1356
1346
  const isIgnored = projectIgnorePredicate(absPath);
1357
- for (const [ext, exts] of Object.entries(LANG_EXTENSIONS)) {
1358
- collectedFiles = await collectFiles(absPath, exts, MAX_FILES + 1, isIgnored);
1359
- if (collectedFiles.length > 0) {
1360
- extension = ext;
1361
- break;
1362
- }
1363
- }
1364
- if (!extension || collectedFiles.length === 0) {
1347
+ await resolveDirectoryScanExtensions(async (exts) => {
1348
+ collectedFiles = await collectFiles(absPath, [...exts], MAX_FILES + 1, isIgnored);
1349
+ return collectedFiles.length > 0;
1350
+ });
1351
+ if (collectedFiles.length === 0) {
1365
1352
  return {
1366
1353
  content: [
1367
1354
  {
@@ -10,6 +10,8 @@ import { Type } from "../clients/deps/typebox.js";
10
10
  import { logLatency } from "../clients/latency-logger.js";
11
11
  import { newLspMutationCorrelationId, recordLspMutationOutcome, } from "../clients/lsp-mutation.js";
12
12
  import { uriToPath } from "../clients/path-utils.js";
13
+ import { escapeRegExp } from "../clients/string-utils.js";
14
+ import { isRecordableProjectPath } from "../clients/file-utils.js";
13
15
  import { compactRenderResult } from "./render-compact.js";
14
16
  import { applyWorkspaceEdit, summarizeWorkspaceEdit, } from "../clients/lsp/edits.js";
15
17
  import { getLSPService, } from "../clients/lsp/index.js";
@@ -106,9 +108,6 @@ function emptyReasonForOperation(operation) {
106
108
  return "no-call-hierarchy-results";
107
109
  return "no-results";
108
110
  }
109
- function escapeRegExp(value) {
110
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
111
- }
112
111
  function parseSymbolSelector(symbol) {
113
112
  const trimmed = symbol.trim();
114
113
  const match = /^([^#]*)(?:#(-?\d+))?$/.exec(trimmed);
@@ -530,16 +529,16 @@ async function openFileBestEffort(lspService, filePath, waitForDiagnostics = fal
530
529
  if (!fileContent)
531
530
  return;
532
531
  try {
533
- if (typeof lspService.touchFile === "function") {
534
- await lspService.touchFile(filePath, fileContent, {
535
- diagnostics: waitForDiagnostics ? "document" : "none",
536
- source: "lsp_navigation",
537
- clientScope: waitForDiagnostics ? "all" : "primary",
538
- });
539
- }
540
- else {
541
- await lspService.openFile(filePath, fileContent);
542
- }
532
+ // #2598: `touchFile` is defined unconditionally on the real `LSPService`
533
+ // (clients/lsp/index.ts), so the former `typeof … === "function"` hedge
534
+ // and its `openFile` arm were reachable only from a partial test double
535
+ // (AGENTS.md shape 7). Nothing here reads the result — a touch that
536
+ // resolves no clients is already the no-op this helper wants.
537
+ await lspService.touchFile(filePath, fileContent, {
538
+ diagnostics: waitForDiagnostics ? "document" : "none",
539
+ source: "lsp_navigation",
540
+ clientScope: waitForDiagnostics ? "all" : "primary",
541
+ });
543
542
  }
544
543
  catch {
545
544
  /* LSP server may not be ready yet — proceed anyway */
@@ -729,7 +728,7 @@ getFlag, mutationDeps) {
729
728
  },
730
729
  ],
731
730
  details: {
732
- ...(payload.details ?? {}),
731
+ ...payload.details,
733
732
  failureKind: meta.failureKind,
734
733
  },
735
734
  };
@@ -779,15 +778,37 @@ getFlag, mutationDeps) {
779
778
  if (requestedApply &&
780
779
  ["rename", "rename_file", "executeCommand"].includes(operation)) {
781
780
  const cwd = ctx.cwd || ".";
781
+ // Name the specific LSP operation in the receipt rather than a
782
+ // generic "lsp-edit" tag, so a rename's change-log entry reads
783
+ // differently from an executeCommand-solicited edit (#2450).
784
+ const mutationSource = operation === "executeCommand" ? "lsp-execute-command" : "lsp-rename";
782
785
  mutationContext = {
783
786
  cwd,
784
787
  correlationId: newLspMutationCorrelationId(_toolCallId),
785
- tool: "lsp_navigation",
786
- source: "lsp-edit",
788
+ tool: `lsp_navigation:${operation}`,
789
+ source: mutationSource,
787
790
  ...mutationDeps,
788
791
  readGuard: getFlag("no-read-guard", cwd)
789
792
  ? undefined
790
793
  : mutationDeps?.readGuard,
794
+ // #2450 review round 2 (F4)/round 3 (F2, F4): the SAME gate
795
+ // `registerMutationBridge` applies internally in `index.ts`, so
796
+ // this directly-threaded path and the bridge fallback
797
+ // (`clients/lsp-mutation.ts`, reached when `mutationDeps` is
798
+ // absent/partial — e.g. the MCP server) agree on which files
799
+ // count as project source, rather than the direct path
800
+ // recording an ignored/vendor write the fallback would drop.
801
+ // `no-read-guard` is intentionally NOT checked here (round 3
802
+ // F2): it gates only the read-guard stamp above, the same
803
+ // canonical split `clients/runtime-tool-result.ts` applies
804
+ // (`:1120`, `:1485`) — bookkeeping (turn-state / receipts)
805
+ // still runs under `--no-read-guard`. Judge against the
806
+ // project root, not the request `cwd` (round 3 F4): a
807
+ // sub-package `cwd` must not read a sibling-package rename as
808
+ // external.
809
+ isRecordable: (filePath) => {
810
+ return isRecordableProjectPath(filePath, mutationDeps?.runtime?.projectRoot ?? cwd);
811
+ },
791
812
  };
792
813
  }
793
814
  const isCallHierarchyTraversal = operation === "incomingCalls" || operation === "outgoingCalls";
@@ -22,7 +22,6 @@ export const LANGUAGES = [
22
22
  "ruby",
23
23
  "rust",
24
24
  "scala",
25
- "solidity",
26
25
  "swift",
27
26
  "tsx",
28
27
  "typescript",
@@ -45,10 +45,20 @@ On every write/edit, and at session/turn boundaries, pi-lens runs — without yo
45
45
  | **Structural rules** | ast-grep (NAPI engine) + tree-sitter rules flag correctness/security smells. |
46
46
  | **Opengrep security scan** | Always-on: per-edit via an auxiliary LSP, plus a cached project-wide CLI scan for `mode=full`. |
47
47
  | **Other scanners** | Config-/presence-gated: gitleaks (secrets), trivy (CVEs/IaC/license), govulncheck (Go), knip/jscpd/madge (JS/TS dead-code/dupes/cycles), vulture (Python), zizmor (GH Actions), typos. |
48
- | **Test-runner-on-write** | Related/affected tests are run asynchronously for the next turn's findings (edit-scoped, not a full-suite run). |
48
+ | **Test-runner-on-write** | Related/affected tests are run asynchronously for the next turn's findings (edit-scoped, not a full-suite run). Integration/e2e tests are never auto-fired — see below. |
49
49
  | **Read-guard** | Tracks that you read a file before editing it; blocks/warns zero-read or stale-range edits. |
50
50
  | **Context injection** | Injects session-start guidance and turn-end findings into your context (see §2). |
51
51
 
52
+ **Test-runner-on-write scope.** A built-in exclusion list keeps integration/e2e
53
+ suites out of the auto-fired batch — `**/integration/**`, `**/e2e/**`,
54
+ `**/*.integration.*`, `**/*.e2e.*` — since those commonly spawn external
55
+ processes (another CLI, a browser, a live provider) that don't belong on an
56
+ unattended per-edit turn. This is a fixed, built-in list; there is no
57
+ per-project config knob for it. If a runner itself fails to complete (a
58
+ timeout, or a missing provider/binary — not a failing assertion), pi-lens
59
+ delivers it as an advisory ("could not complete last turn"), not as a
60
+ "fix before continuing" blocker — you didn't introduce anything to fix.
61
+
52
62
  You don't invoke these. They happen. Your job is to **read the results** and **respond**.
53
63
 
54
64
  ---
@@ -185,9 +195,62 @@ pi-lens writes to files **outside your own tool calls** (`docs/features.md`
185
195
  - **`write` then `edit` on the same file, same turn:** the write's autofix
186
196
  demotes to deferred too, so the file's mutation history stays coherent. This
187
197
  resets at the next turn.
198
+ - **Any other tool that edits a file:** pi-lens recognizes it by the SHAPE of
199
+ its arguments rather than its name (`clients/mutating-tool.ts`), so a host or
200
+ extension tool called `replace` or `insert` gets the same chain `edit` gets:
201
+ a turn-state entry, a change-log receipt attributed to that tool, and a
202
+ *deferred* auto-fix. Its lines are resolved when the anchor is unambiguous
203
+ (roughly two-thirds of anchors in practice — `clients/hashline-anchor.ts`);
204
+ otherwise the mutation is recorded whole-file with lines unknown, and the
205
+ read-before-edit guard takes its no-line-info arm rather than guessing.
206
+ Deferred is the default for every edit-shaped tool pi-lens cannot place,
207
+ because formatting between the steps of a multi-call rewrite fights the tool
208
+ that is still writing.
209
+ - **A tool whose shape is unrecognized too:** pi-lens watches instead of
210
+ guessing (`clients/observed-mutation.ts`). A call that names a file gets a
211
+ bounded pre/post snapshot of THAT PATH — the file itself, or a directory's own
212
+ entries — and nothing else, so a write landing on a neighbouring file is never
213
+ attributed to it. Anything that changed is replayed through the same chain,
214
+ and the tool is then remembered as mutating: for this session on the first
215
+ sighting, persisted under the project's data directory on the second, so a
216
+ later session classifies it by name with no snapshot at all. Three quiet
217
+ observations in a row withdraw a session attribution again, and a withdrawn
218
+ tool can be learned back from a later real edit. An observation pi-lens could
219
+ not finish — a directory with more entries than it watches — counts as
220
+ neither, so a wide codemod is never written off on a look it never took. A
221
+ call that names
222
+ no file is caught at `agent_settled` by an incremental content check over the
223
+ files pi-lens has already read, written, diagnosed or opened on a language
224
+ server — a rotating window per turn, reading only what actually moved; a file
225
+ it has never seen has no baseline, so that last-resort net does not cover it,
226
+ and a file it cannot verify is reported as such rather than reformatted on a
227
+ timestamp alone.
188
228
  - The conservative actionable-warnings autofix (LSP quickfixes, hard-capped)
189
229
  is unchanged: it always runs at `agent_end`.
190
230
 
231
+ **Extension authors: record your own writes.** If your extension writes files
232
+ outside pi-lens's tool events — its own registered tool, a spawned rewriter —
233
+ tell pi-lens through the in-process mutation bridge, the write-side sibling of
234
+ the read bridge:
235
+
236
+ ```js
237
+ const bridge = globalThis[Symbol.for("pi-lens:mutation-bridge")];
238
+ if (bridge?.version === 1) {
239
+ bridge.recordMutation({
240
+ filePath, // absolute path
241
+ kind: "edit", // "write" replaces the whole file; "edit" is partial
242
+ editRanges: [[12, 18]], // optional, 1-based inclusive
243
+ consumer: "my-extension",
244
+ });
245
+ }
246
+ ```
247
+
248
+ Check `version` before calling; a version you do not recognize is unsupported.
249
+ Calling when pi-lens is absent or the guard is disabled is safe — the bridge is
250
+ missing or drops the call. `recordMutation` returns `true` when pi-lens took the
251
+ record and `false` when it dropped it, so you can count your own drops. pi-lens's
252
+ own `ast_grep_replace apply:true` records through this same bridge.
253
+
191
254
  Consequences for you:
192
255
 
193
256
  - Your exact written bytes may be reformatted/fixed. **This is expected pipeline
@@ -0,0 +1,222 @@
1
+ # Configuring pi-lens
2
+
3
+ There are **two** pi-lens config files:
4
+
5
+ | File | Scope | Notes |
6
+ | --- | --- | --- |
7
+ | `.pi-lens.json` | the project | Committed or not, your call. Nearest one wins **per field** — a package can override one setting without restating the repo root's. |
8
+ | `~/.pi-lens/config.json` | the machine | Your defaults across every project. `PI_LENS_CONFIG_PATH` relocates it. |
9
+
10
+ Both files have the same shape, with one exception noted below the example:
11
+ everything LSP-related lives under an `lsp` namespace inside them.
12
+
13
+ ```jsonc
14
+ {
15
+ "$schema": "https://raw.githubusercontent.com/apmantza/pi-lens/master/docs/schema/pi-lens-config-v1.json",
16
+ "ignore": ["dist/**"],
17
+ "maxProjectFiles": 8000,
18
+ "rules": { "high-complexity": { "threshold": 25 } },
19
+ "lsp": {
20
+ "disabledServers": ["typos"],
21
+ "warmFiles": ["src/main.rs"],
22
+ "servers": {
23
+ "my-server": {
24
+ "name": "My Custom LSP",
25
+ "extensions": [".myext"],
26
+ "command": "my-lsp-server",
27
+ "args": ["--stdio"]
28
+ }
29
+ },
30
+ "serverOverrides": {
31
+ "rust": {
32
+ "initializationOptions": { "check": { "command": "clippy" } }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ **Some settings are global-only.** A handful of switches — `lsp.enabled`
40
+ (`--no-lsp`), `tests.enabled`, `delta.enabled` and the other session-wide
41
+ toggles — are decided once for the machine, not per project, so writing one in a
42
+ `.pi-lens.json` does nothing. It is not ignored quietly: the project loader says
43
+ so, naming the key. `docs/settings.md` lists which flags are which.
44
+
45
+ ## Which file wins
46
+
47
+ One order, lowest precedence first. A later tier replaces an earlier tier's
48
+ value **for that field only** — objects are merged field-wise, never replaced
49
+ whole, so setting one key never silently drops the rest of a section.
50
+
51
+ 1. **global** — `~/.pi-lens/config.json`.
52
+ 2. **project root** — the outermost `.pi-lens.json` at or above your working
53
+ directory.
54
+ 3. **nested-project** — every `.pi-lens.json` between that root and your working
55
+ directory, outermost first. The nearest file wins, per field.
56
+
57
+ Those three are the tiers the config **files** resolve through, and they are the
58
+ only ones this resolution populates. Four more tiers are reserved in the
59
+ precedence table — `builtin` below them, and `env`, `cli`, `host` above — and
60
+ nothing writes into them yet; #2427 (env/CLI) and #2416 (host and project trust)
61
+ are what fill them in.
62
+
63
+ Until they do, environment variables and CLI flags are read by their own
64
+ accessors rather than through this resolution, and their effective precedence
65
+ for a pi-lens toggle is:
66
+
67
+ 1. a `PI_LENS_*` environment variable set to `1` — checked first, and it wins
68
+ outright;
69
+ 2. the matching `--lens-*` / `--no-*` CLI flag;
70
+ 3. the nearest project `.pi-lens.json`, then the outer ones (project-scoped
71
+ settings only);
72
+ 4. `~/.pi-lens/config.json`;
73
+ 5. the built-in default.
74
+
75
+ Subsystem-specific env overrides follow the same shape: a
76
+ `PI_LENS_REVIEW_GRAPH_MAX_FILES` beats a `.pi-lens.json`'s
77
+ `reviewGraph.maxFiles`. `docs/environment-variables.md` and `docs/settings.md`
78
+ are the per-setting references.
79
+
80
+ ### One exception: `lsp.disabledServers` is a denial, not a value
81
+
82
+ Ordinary settings are last-tier-wins. A **denial** is not, because the tier
83
+ that made it is usually the one you control and the tier that would override it
84
+ is usually one that arrived with somebody else's checkout.
85
+
86
+ `lsp.disabledServers` resolves as the **union of every tier's entries**. A
87
+ project `.pi-lens.json` can add to it and can never subtract from it, so a
88
+ repository cannot re-enable a server you turned off in
89
+ `~/.pi-lens/config.json`. There is no vocabulary for un-denying an entry: if
90
+ you change your mind, edit the file that denied. The provenance reports, per
91
+ denied server, the tier that contributed it.
92
+
93
+ ```console
94
+ $ # which servers run for this file, and why
95
+ $ pilens_effective_config file=src/main.rs
96
+ ✗ typos — disabled-by-config (global ~/.pi-lens/config.json → /lsp/disabledServers/0)
97
+ ```
98
+
99
+ The union spans **both spellings**: a document's deprecated root keys
100
+ (`servers`, `serverOverrides`, `disabledServers`, `warmFiles`) are read
101
+ into the `lsp` namespace before any tier is merged, so one setting is resolved
102
+ once no matter which spelling each file uses. Migrating does not change the
103
+ answer, staying un-migrated is not a way around the denial, and a half-migrated
104
+ pair of files merges rather than one clobbering the other.
105
+
106
+ Two rules make the rest of the table unambiguous:
107
+
108
+ - **The search stops at `$HOME`.** pi-lens never reads a config file in your
109
+ home directory or above it. A stray `pi-lens.json` in `$HOME` (or at `C:\`)
110
+ is not adopted by every project on the machine. The machine-global file is
111
+ read by its own path, so it is unaffected.
112
+ - **The canonical spelling wins.** Where a legacy file or a legacy key means the
113
+ same thing as the canonical one, the canonical one is used — otherwise the
114
+ migration below could never be completed.
115
+
116
+ ## Legacy locations (still read; being removed)
117
+
118
+ These are read for their deprecation window and then **removed**. Each one you
119
+ still have produces one warning per setting, naming exactly where to move it —
120
+ carrying the stable code `PILENS_CFG_0003` (a deprecated file) or
121
+ `PILENS_CFG_0002` (a deprecated key), so you can match or suppress on the code
122
+ rather than on the prose.
123
+
124
+ | Legacy | Move it to | Code |
125
+ | --- | --- | --- |
126
+ | `.pi-lens/lsp.json` | `.pi-lens.json` → `lsp.*` | `PILENS_CFG_0003` |
127
+ | `pi-lsp.json` | `.pi-lens.json` → `lsp.*` | `PILENS_CFG_0003` |
128
+ | `pi-lens.json` (undotted) | `.pi-lens.json` | `PILENS_CFG_0003` |
129
+ | `~/.pi-lens/lsp.json` | `~/.pi-lens/config.json` → `lsp.*` | `PILENS_CFG_0003` |
130
+ | `servers` at the file root | `lsp.servers` | `PILENS_CFG_0002` |
131
+ | `serverOverrides` at the file root | `lsp.serverOverrides` | `PILENS_CFG_0002` |
132
+ | `disabledServers` at the file root | `lsp.disabledServers` | `PILENS_CFG_0002` |
133
+ | `warmFiles` at the file root | `lsp.warmFiles` | `PILENS_CFG_0002` |
134
+
135
+ **Deprecated since 4.1.4. Read for the last time before 5.0.0.** The window is
136
+ declared as data in `clients/config-diagnostic-codes.ts`
137
+ (`DEPRECATED_CONFIG_SURFACES`) and enforced by test, so the schedule above and
138
+ the code cannot drift apart. `docs/public-api-stability.md` describes the policy
139
+ these dates instantiate.
140
+
141
+ A `.pi-lens.json` that mixes both spellings is fine while you migrate: the
142
+ canonical key wins, and the keys you have not moved yet keep working.
143
+
144
+ Only keys pi-lens actually recognizes get "move it to …" advice. A key in a
145
+ legacy file that is not a pi-lens setting at all — a typo, or a leftover from
146
+ another tool — cannot be migrated anywhere, so it gets the ordinary
147
+ unrecognized-key notice (`PILENS_CFG_0001`) and is counted in ONE whole-file
148
+ `PILENS_CFG_0003` notice for the file rather than being told to move.
149
+
150
+ ## When a config is ignored
151
+
152
+ A file that cannot be read or parsed is **ignored, never partially applied** —
153
+ pi-lens runs on defaults for it and says so once, with the code
154
+ `PILENS_CFG_0001`. A field whose value does not match its declared type is
155
+ dropped on its own (`PILENS_CFG_0005`), and an unrecognized field is dropped
156
+ with a message naming the key (`PILENS_CFG_0004`). If resolving a file fails
157
+ internally the whole file is ignored and said so under its own code
158
+ (`PILENS_CFG_0008`), so "one field went missing" and "none of this file is in
159
+ effect" are never the same code. Nothing about your config is ever ignored
160
+ silently.
161
+
162
+ The number of notices one file can produce is bounded PER NOTICE LIST, because
163
+ the number of keys in a file is not. There are two lists, split by who composes
164
+ them rather than by what they say — both are about values that were rejected:
165
+
166
+ - what **resolving** the file produced — the per-field rejections
167
+ (`PILENS_CFG_0004`, `PILENS_CFG_0005`, `PILENS_CFG_0006`) together with the
168
+ deprecation notices (`PILENS_CFG_0002`, `PILENS_CFG_0003`), which share this
169
+ list;
170
+ - what the **loader** reading the file produced on its own — unknown top-level
171
+ keys and settings it refused (`PILENS_CFG_0001`).
172
+
173
+ Each list is bounded at 20 records: up to 19 notices plus, when the bound bit,
174
+ a single `PILENS_CFG_0007` summary giving the count that was suppressed, so a
175
+ truncated list always says that it is truncated. That summary is about the
176
+ LIST, not about the file: a config whose every setting was applied can still
177
+ overflow the bound, so it is worded and recorded as a summary rather than as an
178
+ ignored config.
179
+
180
+ One notice is never suppressed by that bound: `PILENS_CFG_0008`, which says the
181
+ whole file is out of effect. It is not one more rejected key competing for a
182
+ slot — it is what tells you the rejections above it are no longer the whole
183
+ story — so it is kept however full the list already was.
184
+
185
+ ## Asking what is actually in effect
186
+
187
+ You never have to reconstruct the table above by hand. `pilens_effective_config`
188
+ (MCP) and `effective_config` (pi) return the resolved configuration with the
189
+ provenance of **every** leaf — the tier, the file, the key, and the trust
190
+ decision that applied — plus, for a file you name, its language, every LSP
191
+ server with the reason it was selected or denied, and the runners that would
192
+ dispatch. That is the answer to "why is this running" and to "why is this *not*
193
+ running", without reading a log.
194
+
195
+ Naming a `file` resolves the configuration **at that file's own directory**,
196
+ which is where the runtime decides from — so a nested `repo/sub/.pi-lens.json`
197
+ layer contributes to the answer, appears in the reported document list, and is
198
+ named as the file behind any decision it made. The walk runs upward and is
199
+ **confined to `cwd`**: a `file` that resolves outside `cwd` — including a
200
+ sibling package in the same monorepo — is rejected rather than answered from
201
+ its own unrelated tree, because the per-file answer is only ever correct when
202
+ it is a superset of the workspace's own; the rejection names the `cwd` it was
203
+ measured against and the remedy is to re-query with `cwd` set to that file's
204
+ own workspace. A confined `file` always passes back through the workspace's
205
+ own documents on its way up, so they are always included too.
206
+
207
+ It reports **sources, never values**. Environment values never appear, a custom
208
+ server's command line is cut to the binary itself, and every path is rewritten
209
+ `~`-relative. There is no un-redacted mode: the un-redacted data is the config
210
+ file you already have.
211
+
212
+ `pilens_health` embeds the same provenance as **counts per tier** — how many
213
+ settings each source decided, and which `PILENS_CFG_*` notices the resolution
214
+ produced — so a session's config posture is visible without the detail.
215
+
216
+ ## See also
217
+
218
+ - `docs/globalconfig.md` — every key of `~/.pi-lens/config.json`, in detail.
219
+ - `docs/settings.md` — the CLI flags and what they map to.
220
+ - `docs/environment-variables.md` — the `PI_LENS_*` tier.
221
+ - `docs/public-api-stability.md` — what `x-stability`, the `PILENS_CFG_*` codes,
222
+ and the deprecation windows commit pi-lens to.
@@ -40,9 +40,9 @@ Auto-install behavior depends on gate type:
40
40
  | `intelephense` | PHP LSP | Yes | Flow-gated |
41
41
  | `bash-language-server` | Bash LSP | Yes | Language-default |
42
42
  | `yaml-language-server` | YAML LSP | Yes | Language-default |
43
- | `vscode-langservers-extracted` | JSON/ESLint/CSS/HTML LSP | Yes | Language-default |
44
- | `vscode-css-languageserver` | CSS LSP | Yes | Language-default |
45
- | `vscode-html-languageserver-bin` | HTML LSP | Yes | Language-default |
43
+ | `vscode-json-language-server` | JSON LSP (`vscode-langservers-extracted`) | Yes | Language-default |
44
+ | `vscode-css-languageserver` | CSS LSP (`vscode-langservers-extracted`) | Yes | Language-default |
45
+ | `vscode-html-languageserver-bin` | HTML LSP (`vscode-langservers-extracted`) | Yes | Language-default |
46
46
  | `svelte-language-server` | Svelte LSP | Yes | Flow-gated |
47
47
  | `@vue/language-server` | Vue LSP | Yes | Flow-gated |
48
48
  | `opengrep` | Experimental security dispatch | Auto-install | Local config / explicit opt-in |