@herbertgao/pi-extensions 2026.9.0 → 2026.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/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/@narumitw/pi-btw/README.md +57 -141
  11. package/node_modules/@narumitw/pi-btw/dist/index.ts +466 -41
  12. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
  13. package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
  14. package/node_modules/@narumitw/pi-btw/package.json +2 -1
  15. package/node_modules/@narumitw/pi-btw/src/btw.ts +15 -1
  16. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
  17. package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
  18. package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
  19. package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
  20. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
  21. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
  22. package/node_modules/@pi-plugins/fast-mode/README.md +5 -3
  23. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
  24. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +20 -55
  25. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  26. package/node_modules/@pi-plugins/fast-mode/package.json +1 -1
  27. package/node_modules/pi-lens/CHANGELOG.md +1072 -0
  28. package/node_modules/pi-lens/README.md +3 -0
  29. package/node_modules/pi-lens/config/biome/core.jsonc +11 -2
  30. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +13 -1
  31. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -9
  32. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
  33. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
  34. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +13 -4
  35. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +123 -3
  36. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +60 -5
  37. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +2 -9
  38. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
  39. package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -3
  40. package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
  41. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -6
  42. package/node_modules/pi-lens/dist/clients/bootstrap.js +509 -73
  43. package/node_modules/pi-lens/dist/clients/bounded-cache.js +152 -12
  44. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
  45. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -9
  46. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
  47. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +3 -11
  48. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +31 -4
  49. package/node_modules/pi-lens/dist/clients/cache-manager.js +105 -6
  50. package/node_modules/pi-lens/dist/clients/cache-observability.js +40 -19
  51. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
  52. package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -9
  53. package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
  54. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +13 -3
  55. package/node_modules/pi-lens/dist/clients/complexity-client.js +16 -5
  56. package/node_modules/pi-lens/dist/clients/config-core/deny.js +221 -0
  57. package/node_modules/pi-lens/dist/clients/config-core/index.js +50 -0
  58. package/node_modules/pi-lens/dist/clients/config-core/merge.js +357 -0
  59. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +340 -0
  60. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +248 -0
  61. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +164 -0
  62. package/node_modules/pi-lens/dist/clients/config-core/records.js +218 -0
  63. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +125 -0
  64. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +78 -0
  65. package/node_modules/pi-lens/dist/clients/config-core/schema.js +165 -0
  66. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +281 -0
  67. package/node_modules/pi-lens/dist/clients/config-locations.js +160 -0
  68. package/node_modules/pi-lens/dist/clients/config-resolve.js +789 -0
  69. package/node_modules/pi-lens/dist/clients/config-schema.js +234 -0
  70. package/node_modules/pi-lens/dist/clients/config-warn.js +407 -0
  71. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -14
  72. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +2 -6
  73. package/node_modules/pi-lens/dist/clients/deadline-utils.js +178 -0
  74. package/node_modules/pi-lens/dist/clients/debug-handles.js +2 -2
  75. package/node_modules/pi-lens/dist/clients/debug-heap.js +3 -3
  76. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +106 -0
  77. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +113 -7
  78. package/node_modules/pi-lens/dist/clients/dependency-checker.js +8 -19
  79. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
  80. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
  81. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +15 -5
  82. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
  83. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -44
  84. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +27 -8
  86. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
  87. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
  88. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
  89. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
  90. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +383 -27
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -1
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -1
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -1
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -1
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -1
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +1 -3
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +1 -2
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -1
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -1
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -1
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +14 -18
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -1
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +6 -3
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +7 -4
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +1 -2
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -3
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +1 -2
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +4 -3
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -1
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -1
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -1
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -1
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -1
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -1
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -67
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +194 -80
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +84 -15
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
  144. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +1 -1
  145. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
  146. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
  147. package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -10
  148. package/node_modules/pi-lens/dist/clients/effective-config.js +403 -0
  149. package/node_modules/pi-lens/dist/clients/error-class.js +23 -0
  150. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +274 -0
  151. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
  152. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -2
  153. package/node_modules/pi-lens/dist/clients/feature-hints.js +2 -1
  154. package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
  155. package/node_modules/pi-lens/dist/clients/file-time.js +7 -2
  156. package/node_modules/pi-lens/dist/clients/file-utils.js +117 -10
  157. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
  158. package/node_modules/pi-lens/dist/clients/format-service.js +6 -2
  159. package/node_modules/pi-lens/dist/clients/formatters.js +385 -104
  160. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
  161. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +116 -22
  162. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
  163. package/node_modules/pi-lens/dist/clients/git-guard.js +6 -1
  164. package/node_modules/pi-lens/dist/clients/go-client.js +39 -0
  165. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +252 -0
  166. package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
  167. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +424 -0
  168. package/node_modules/pi-lens/dist/clients/hook-budgets.js +76 -0
  169. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +5 -2
  170. package/node_modules/pi-lens/dist/clients/host-ports.js +1 -1
  171. package/node_modules/pi-lens/dist/clients/installer/index.js +289 -59
  172. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
  173. package/node_modules/pi-lens/dist/clients/instance-reaper.js +110 -236
  174. package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
  175. package/node_modules/pi-lens/dist/clients/language-profile.js +0 -9
  176. package/node_modules/pi-lens/dist/clients/language-registry.js +599 -0
  177. package/node_modules/pi-lens/dist/clients/latency-logger.js +165 -9
  178. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +34 -1
  179. package/node_modules/pi-lens/dist/clients/lens-config.js +160 -30
  180. package/node_modules/pi-lens/dist/clients/lens-engine.js +33 -41
  181. package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
  182. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +77 -6
  183. package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
  184. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -38
  185. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
  186. package/node_modules/pi-lens/dist/clients/lsp/client.js +172 -33
  187. package/node_modules/pi-lens/dist/clients/lsp/config.js +484 -158
  188. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
  189. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +1 -1
  190. package/node_modules/pi-lens/dist/clients/lsp/edits.js +18 -5
  191. package/node_modules/pi-lens/dist/clients/lsp/index.js +892 -96
  192. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
  193. package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -177
  194. package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
  195. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  196. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -18
  197. package/node_modules/pi-lens/dist/clients/lsp/server.js +284 -147
  198. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +116 -23
  199. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +2 -7
  200. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
  201. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +14 -7
  202. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
  203. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
  204. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
  205. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
  206. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +163 -21
  207. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +36 -0
  208. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +33 -4
  209. package/node_modules/pi-lens/dist/clients/mcp/session.js +5 -16
  210. package/node_modules/pi-lens/dist/clients/memory-sampler.js +8 -3
  211. package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
  212. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +3 -5
  213. package/node_modules/pi-lens/dist/clients/module-report.js +21 -46
  214. package/node_modules/pi-lens/dist/clients/mutating-tool.js +651 -0
  215. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +368 -0
  216. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +240 -0
  217. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +247 -24
  218. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +101 -0
  219. package/node_modules/pi-lens/dist/clients/observed-mutation.js +1215 -0
  220. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +70 -28
  221. package/node_modules/pi-lens/dist/clients/opengrep-config.js +5 -1
  222. package/node_modules/pi-lens/dist/clients/package-manager.js +195 -26
  223. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +359 -80
  224. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +23 -7
  225. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +21 -2
  226. package/node_modules/pi-lens/dist/clients/path-utils.js +451 -15
  227. package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
  228. package/node_modules/pi-lens/dist/clients/persist-debounce.js +8 -1
  229. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +114 -0
  230. package/node_modules/pi-lens/dist/clients/pipeline.js +79 -18
  231. package/node_modules/pi-lens/dist/clients/probe-home-state.js +228 -0
  232. package/node_modules/pi-lens/dist/clients/process-bridge.js +66 -0
  233. package/node_modules/pi-lens/dist/clients/process-snapshot.js +68 -0
  234. package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
  235. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
  236. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
  237. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
  238. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
  239. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
  240. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
  241. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +28 -4
  242. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
  243. package/node_modules/pi-lens/dist/clients/project-lens-config.js +438 -122
  244. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
  245. package/node_modules/pi-lens/dist/clients/project-snapshot.js +52 -24
  246. package/node_modules/pi-lens/dist/clients/python-environment.js +217 -0
  247. package/node_modules/pi-lens/dist/clients/python-provenance.js +639 -0
  248. package/node_modules/pi-lens/dist/clients/quiet-window.js +6 -1
  249. package/node_modules/pi-lens/dist/clients/read-bridge.js +13 -21
  250. package/node_modules/pi-lens/dist/clients/read-expansion.js +9 -46
  251. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +16 -5
  252. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
  253. package/node_modules/pi-lens/dist/clients/read-guard.js +26 -2
  254. package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
  255. package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
  256. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +155 -114
  257. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
  258. package/node_modules/pi-lens/dist/clients/review-graph/service.js +55 -3
  259. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +7 -15
  260. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +10 -74
  261. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +9 -3
  262. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +19 -3
  263. package/node_modules/pi-lens/dist/clients/runtime-context.js +49 -16
  264. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +25 -6
  265. package/node_modules/pi-lens/dist/clients/runtime-session.js +184 -32
  266. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +179 -36
  267. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +797 -243
  268. package/node_modules/pi-lens/dist/clients/runtime-turn.js +1028 -53
  269. package/node_modules/pi-lens/dist/clients/rust-client.js +31 -0
  270. package/node_modules/pi-lens/dist/clients/safe-spawn.js +33 -10
  271. package/node_modules/pi-lens/dist/clients/sanitize.js +7 -12
  272. package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
  273. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +1 -3
  274. package/node_modules/pi-lens/dist/clients/security-scan-client.js +3 -0
  275. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +1 -1
  276. package/node_modules/pi-lens/dist/clients/session-start-observability.js +79 -0
  277. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
  278. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
  279. package/node_modules/pi-lens/dist/clients/sgconfig.js +7 -6
  280. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
  281. package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
  282. package/node_modules/pi-lens/dist/clients/smells-rollup.js +4 -4
  283. package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
  284. package/node_modules/pi-lens/dist/clients/string-utils.js +13 -0
  285. package/node_modules/pi-lens/dist/clients/subagent-mode.js +17 -4
  286. package/node_modules/pi-lens/dist/clients/test-runner-client.js +176 -39
  287. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +244 -0
  288. package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
  289. package/node_modules/pi-lens/dist/clients/tool-policy.js +92 -22
  290. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
  291. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +87 -100
  292. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  293. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +81 -1
  294. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +51 -46
  295. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +28 -0
  296. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
  297. package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
  298. package/node_modules/pi-lens/dist/clients/user-notify.js +6 -6
  299. package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
  300. package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -9
  301. package/node_modules/pi-lens/dist/clients/word-index-store.js +23 -12
  302. package/node_modules/pi-lens/dist/clients/word-index.js +252 -47
  303. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
  304. package/node_modules/pi-lens/dist/clients/zizmor-config.js +4 -1
  305. package/node_modules/pi-lens/dist/index.js +65899 -55340
  306. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
  307. package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
  308. package/node_modules/pi-lens/dist/mcp/server.js +127 -5
  309. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +583 -0
  310. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +129 -0
  311. package/node_modules/pi-lens/dist/tools/effective-config.js +89 -0
  312. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +96 -25
  313. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +104 -86
  314. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
  315. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
  316. package/node_modules/pi-lens/dist/tools/render-compact.js +1 -1
  317. package/node_modules/pi-lens/dist/tools/shared.js +0 -1
  318. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -2
  319. package/node_modules/pi-lens/docs/agent-guide.md +64 -1
  320. package/node_modules/pi-lens/docs/configuration.md +222 -0
  321. package/node_modules/pi-lens/docs/dependencies.md +3 -3
  322. package/node_modules/pi-lens/docs/features.md +44 -5
  323. package/node_modules/pi-lens/docs/globalconfig.md +20 -0
  324. package/node_modules/pi-lens/docs/language-coverage.md +2 -2
  325. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
  326. package/node_modules/pi-lens/docs/pi-lens-fixer.md +25 -0
  327. package/node_modules/pi-lens/docs/pi-lens-investigator.md +25 -0
  328. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +33 -0
  329. package/node_modules/pi-lens/docs/pi-lens-subagent.md +49 -0
  330. package/node_modules/pi-lens/docs/pi-lens-warden.md +55 -0
  331. package/node_modules/pi-lens/docs/public-api-stability.md +359 -0
  332. package/node_modules/pi-lens/docs/release-qa-baseline.md +190 -0
  333. package/node_modules/pi-lens/docs/servercapabilities.md +7 -3
  334. package/node_modules/pi-lens/docs/subagent-compat.md +110 -30
  335. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +2 -2
  336. package/node_modules/pi-lens/docs/word-index.md +1 -1
  337. package/node_modules/pi-lens/package.json +18 -35
  338. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
  339. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
  340. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
  341. package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
  342. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +192 -1
  343. package/node_modules/pi-lens/scripts/install-selftest.mjs +58 -2
  344. package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +129 -0
  345. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
  346. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
  347. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
  348. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  349. package/node_modules/pi-web-access/README.md +62 -15
  350. package/node_modules/pi-web-access/curator-page.ts +3 -1
  351. package/node_modules/pi-web-access/curator-server.ts +5 -1
  352. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  353. package/node_modules/pi-web-access/github-extract.ts +242 -1
  354. package/node_modules/pi-web-access/index.ts +118 -64
  355. package/node_modules/pi-web-access/mistral-search.ts +281 -0
  356. package/node_modules/pi-web-access/package.json +2 -2
  357. package/node_modules/pi-web-access/perplexity.ts +14 -1
  358. package/node_modules/pi-web-access/utils.ts +23 -6
  359. package/node_modules/pi-web-access/xai-search.ts +96 -33
  360. package/package.json +6 -6
@@ -223,7 +223,7 @@ export function validateAdvisoryProvenance(record, cwd, runtime) {
223
223
  // of which any #1461 slice writes yet, so nothing here currently touches
224
224
  // it.
225
225
  /** Stat budget: one per unique cited path, sharing the envelope's own cap. */
226
- export const MAX_FINDING_PATH_STATS = MAX_ADVISORY_AFFECTED_FILES;
226
+ const MAX_FINDING_PATH_STATS = MAX_ADVISORY_AFFECTED_FILES;
227
227
  /** How many dead paths a single drop record names before it stops. */
228
228
  const MAX_LOGGED_DEAD_PATHS = 3;
229
229
  /**
@@ -8,9 +8,18 @@
8
8
  *
9
9
  * No external dependencies — purely tracks tool call history.
10
10
  */
11
+ import { isMutatingToolName } from "./mutating-tool.js";
11
12
  import { normalizeMapKey } from "./path-utils.js";
12
13
  // --- Constants ---
13
- const WRITE_OPS = new Set(["edit", "write", "multiedit"]);
14
+ // #2423: mutating-tool membership comes from the seam
15
+ // (`clients/mutating-tool.ts`), the single source of truth for the built-in
16
+ // table. The hand-maintained set this replaced also carried a dead
17
+ // `"multiedit"` entry that no host emits.
18
+ //
19
+ // Known gap, stated rather than hidden: this client is handed a tool NAME and a
20
+ // path, never the event, so it cannot see a third-party mutating tool the way
21
+ // the shape adapters can. Blind-write and thrash detection covers pi's
22
+ // built-ins only.
14
23
  const READ_OPS = new Set(["read", "bash", "grep", "glob", "find", "rg"]);
15
24
  const BLIND_WRITE_WINDOW = 5; // Check last N tool calls for a read
16
25
  const THRASH_THRESHOLD = 3; // Flag after N consecutive identical tool+file pairs
@@ -63,19 +72,19 @@ export class AgentBehaviorClient {
63
72
  });
64
73
  }
65
74
  // Check for blind writes
66
- if (WRITE_OPS.has(toolName)) {
75
+ if (isMutatingToolName(toolName)) {
67
76
  const recentWindow = this.toolHistory.slice(-BLIND_WRITE_WINDOW);
68
77
  // A read in the window proves file knowledge; so does a same-session
69
78
  // write/edit of THIS path — the agent authored the content, so the
70
79
  // write-then-edit loop on a self-authored file is not a blind write.
71
80
  const hasRecentRead = recentWindow.some((r) => READ_OPS.has(r.toolName) ||
72
- (WRITE_OPS.has(r.toolName) &&
81
+ (isMutatingToolName(r.toolName) &&
73
82
  r.filePath !== undefined &&
74
83
  normalizedPath !== null &&
75
84
  normalizeMapKey(r.filePath) === normalizedPath));
76
85
  if (!hasRecentRead && recentWindow.length > 0) {
77
86
  // Count how many writes in the window without reads
78
- const writesWithoutRead = recentWindow.filter((r) => WRITE_OPS.has(r.toolName)).length;
87
+ const writesWithoutRead = recentWindow.filter((r) => isMutatingToolName(r.toolName)).length;
79
88
  if (writesWithoutRead >= 2) {
80
89
  warnings.push({
81
90
  type: "blind-write",
@@ -11,10 +11,79 @@ import { createSubsystemLogger } from "./extension-log.js";
11
11
  import * as fs from "node:fs";
12
12
  import * as os from "node:os";
13
13
  import * as path from "node:path";
14
- import { AstGrepRuleManager } from "./ast-grep-rule-manager.js";
14
+ import { AstGrepRuleManager, checkAstGrepRulesHealth, } from "./ast-grep-rule-manager.js";
15
+ import { reportBundledResourceDirHealth } from "./bundled-resource-health.js";
16
+ import { getDegradationLedgerGeneration } from "./degradation-ledger.js";
17
+ import { logLatency } from "./latency-logger.js";
18
+ import { getMutationBridge } from "./mutation-bridge.js";
15
19
  import { resolvePackagePath } from "./package-root.js";
16
20
  import { truncatedByOutputCap } from "./spawn-output-cap.js";
17
21
  import { SgRunner, } from "./sg-runner.js";
22
+ /**
23
+ * #2636: `AstGrepClient`'s constructor falls back to the bundled `rules/`
24
+ * (`resolvePackagePath(import.meta.url, "rules")`) with no existence check
25
+ * when the project has none of its own — same managed-cache-relocation gap
26
+ * #2626 fixed for `skills/`. Purely observational: logs a `phase` record
27
+ * naming the resolved path + rule-description count on EVERY call that uses
28
+ * the bundled fallback (healthy or not, so an empty ledger is distinguishable
29
+ * from this never having run at all — #2626 review F5), and records a
30
+ * bounded `ast-grep-rules-dir-missing` degradation only when the bundled dir
31
+ * itself turns out absent, unreadable, or holds no `.yml` rule description.
32
+ * Called only when using the bundled fallback — never when the project
33
+ * provides its own `rules/` (a broken PROJECT override is a user config
34
+ * concern, not this bug's shape) — from `ensureRulesHealthReported` below,
35
+ * both at construction and again on the ledger's next generation (#2636
36
+ * review F3).
37
+ */
38
+ function reportAstGrepRulesHealth(bundledRuleDir) {
39
+ const health = checkAstGrepRulesHealth(bundledRuleDir);
40
+ logLatency({
41
+ type: "phase",
42
+ phase: "ast_grep_rules_resolved",
43
+ filePath: bundledRuleDir,
44
+ durationMs: 0,
45
+ metadata: {
46
+ status: health.status,
47
+ entryCount: health.status === "healthy" ? health.entryCount : 0,
48
+ },
49
+ });
50
+ reportBundledResourceDirHealth("ast-grep-rules-dir-missing", bundledRuleDir, health, "ast-grep rule descriptions");
51
+ }
52
+ /**
53
+ * Record an applied `ast_grep_replace` rewrite through the mutation bridge
54
+ * (#2423, acceptance criterion 3).
55
+ *
56
+ * ast-grep reports 0-based line numbers; the guard and the change log are
57
+ * 1-based, so every range is shifted by one. One record per FILE carries every
58
+ * range that file's matches covered, because the bridge's contract is
59
+ * per-file — the same shape a multi-hunk edit produces.
60
+ *
61
+ * Exported for tests: they drive it against a registered bridge instead of
62
+ * spawning ast-grep.
63
+ */
64
+ function recordAstGrepApply(matches) {
65
+ const bridge = getMutationBridge();
66
+ if (!bridge || matches.length === 0)
67
+ return;
68
+ const rangesByFile = new Map();
69
+ for (const match of matches) {
70
+ const start = (match.range?.start?.line ?? 0) + 1;
71
+ const end = Math.max(start, (match.range?.end?.line ?? 0) + 1);
72
+ const existing = rangesByFile.get(match.file);
73
+ if (existing)
74
+ existing.push([start, end]);
75
+ else
76
+ rangesByFile.set(match.file, [[start, end]]);
77
+ }
78
+ for (const [filePath, editRanges] of rangesByFile) {
79
+ bridge.recordMutation({
80
+ filePath,
81
+ kind: "edit",
82
+ editRanges,
83
+ consumer: "ast_grep_replace",
84
+ });
85
+ }
86
+ }
18
87
  // --- Client ---
19
88
  function extractDebugAst(raw) {
20
89
  const lines = raw.split(/\r?\n/);
@@ -107,21 +176,65 @@ export class AstGrepClient {
107
176
  log;
108
177
  ruleManager;
109
178
  runner;
179
+ // #2636 review F3/F7:
180
+ usingBundledRuleDirFallback;
181
+ rulesHealthReportedGeneration;
110
182
  constructor(ruleDir, verbose = false) {
111
183
  const projectRuleDir = path.join(process.cwd(), "rules");
184
+ // F7: ONE existsSync call, reused for both the fallback decision and the
185
+ // ruleDir choice — two separate calls let the directory appear (or a
186
+ // concurrent watcher/installer create it) between them, making
187
+ // `usingBundledRuleDirFallback` true while `this.ruleDir` ends up being
188
+ // the now-existing PROJECT dir: the health check would then classify a
189
+ // project override's own directory against `reportAstGrepRulesHealth`'s
190
+ // bundled-fallback doc contract.
191
+ const hasProjectRuleDir = fs.existsSync(projectRuleDir);
192
+ this.usingBundledRuleDirFallback = !ruleDir && !hasProjectRuleDir;
112
193
  this.ruleDir =
113
194
  ruleDir ||
114
- (fs.existsSync(projectRuleDir)
195
+ (hasProjectRuleDir
115
196
  ? projectRuleDir
116
197
  : resolvePackagePath(import.meta.url, "rules"));
117
198
  this.log = verbose ? createSubsystemLogger("ast-grep") : () => { };
199
+ this.ensureRulesHealthReported();
118
200
  this.ruleManager = new AstGrepRuleManager(this.ruleDir, this.log);
119
201
  this.runner = new SgRunner(verbose);
120
202
  }
203
+ /**
204
+ * #2636 review F3: `AstGrepClient` is a per-PROCESS singleton
205
+ * (`index.ts`/`mcp/server.ts`/`clients/mcp/session.ts` each construct it
206
+ * exactly once), but `resetDegradationLedger()` wipes the ledger's
207
+ * once-per-subject latch on EVERY `session_start`
208
+ * (`runtime-session.ts`'s `handleSessionStart`). A report that only ever
209
+ * fires at construction is therefore invisible after the first session
210
+ * boundary — `pilens_health` shows nothing for a bug that is still there
211
+ * (shape 17's inverse: `resolveSkillPaths`/`ruleFilesForLanguage` avoid
212
+ * this because pi calls them fresh per request, but `AstGrepClient` has
213
+ * no such per-request re-entry).
214
+ *
215
+ * Re-checked against the ledger's own generation counter at the START of
216
+ * every real scan entry point (`ensureAvailable`, called by every
217
+ * `tools/ast-grep-*`/`ast-dump` handler before doing any work) — the same
218
+ * pattern `clients/tree-sitter-client.ts`'s `refreshGrammarSessionLatches`
219
+ * uses for its own per-instance session latches, adapted here: the
220
+ * degradation ledger already re-arms its OWN once-per-subject dedup on
221
+ * reset, so this method only has to decide WHETHER to call
222
+ * `reportAstGrepRulesHealth` again, never re-implement the dedup itself.
223
+ */
224
+ ensureRulesHealthReported() {
225
+ const generation = getDegradationLedgerGeneration();
226
+ if (this.rulesHealthReportedGeneration === generation)
227
+ return;
228
+ this.rulesHealthReportedGeneration = generation;
229
+ if (this.usingBundledRuleDirFallback) {
230
+ reportAstGrepRulesHealth(this.ruleDir);
231
+ }
232
+ }
121
233
  /**
122
234
  * Check if ast-grep CLI is available, auto-install if not
123
235
  */
124
236
  ensureAvailable() {
237
+ this.ensureRulesHealthReported();
125
238
  return this.runner.ensureAvailable();
126
239
  }
127
240
  /**
@@ -468,6 +581,13 @@ export class AstGrepClient {
468
581
  error: applyResult.error,
469
582
  };
470
583
  }
584
+ // #2423: `--update-all` just rewrote these files, and no `tool_result`
585
+ // describes it — pi-lens's own tool was as invisible to the mutation
586
+ // bookkeeping as any third-party one. Record each rewritten file through
587
+ // the same seam an extension would use. Fire-and-forget: the bridge never
588
+ // throws, and a missing bridge (pi-lens not activated, guard disabled) is
589
+ // a silent no-op.
590
+ recordAstGrepApply(preCheck.matches);
471
591
  return {
472
592
  matches: preCheck.matches,
473
593
  totalMatches: preCheck.totalMatches,
@@ -514,7 +634,7 @@ message: found
514
634
  grouped.set(signature, group);
515
635
  }
516
636
  return Array.from(grouped.entries())
517
- .filter(([_, functions]) => functions.length > 1)
637
+ .filter(([, functions]) => functions.length > 1)
518
638
  .map(([pattern, functions]) => ({ pattern, functions }));
519
639
  }
520
640
  /**
@@ -1,5 +1,64 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
+ /**
4
+ * The candidate sub-paths under `ruleDir` that hold ast-grep rule
5
+ * descriptions — SINGLE source of truth shared by `loadRuleDescriptions`
6
+ * (the real read) and `checkAstGrepRulesHealth` (the #2636 observational
7
+ * probe), so the two can never drift apart on "where do rules live".
8
+ */
9
+ export function candidateAstGrepRulesPaths(ruleDir) {
10
+ return [
11
+ path.join(ruleDir, "ast-grep-rules", "rules"),
12
+ path.join(ruleDir, "rules"),
13
+ ruleDir,
14
+ ];
15
+ }
16
+ /**
17
+ * Classify whether `ruleDir` (the resolved ast-grep rules root, `rules/`
18
+ * inside the bundled package or the project override) yields any loadable
19
+ * `.yml` rule description — mirroring `loadRuleDescriptions`'s OWN
20
+ * resolution EXACTLY (first existing candidate wins, then its `.yml`
21
+ * files), so this never reports a status `loadRuleDescriptions` itself
22
+ * would disagree with. Purely observational: never throws, and does not
23
+ * gate what `ruleDir` `AstGrepClient` uses (#2636, following #2626 review
24
+ * F1 — the acceptance criteria ask for a RECORD, never a changed resolution).
25
+ */
26
+ export function checkAstGrepRulesHealth(ruleDir) {
27
+ const possiblePaths = candidateAstGrepRulesPaths(ruleDir);
28
+ let rulesPath;
29
+ for (const candidate of possiblePaths) {
30
+ if (fs.existsSync(candidate)) {
31
+ rulesPath = candidate;
32
+ break;
33
+ }
34
+ }
35
+ if (!rulesPath) {
36
+ // None of the three candidates exist — distinguish `ruleDir` itself
37
+ // being unreadable (EACCES and friends) from it simply being absent
38
+ // (ENOENT), matching #2626 review F4's ENOENT/EACCES split.
39
+ try {
40
+ fs.readdirSync(ruleDir);
41
+ }
42
+ catch (error) {
43
+ const fsErrorCode = error?.code;
44
+ if (fsErrorCode && fsErrorCode !== "ENOENT") {
45
+ return { status: "unreadable", fsErrorCode };
46
+ }
47
+ }
48
+ return { status: "absent" };
49
+ }
50
+ let entries;
51
+ try {
52
+ entries = fs.readdirSync(rulesPath).filter((f) => f.endsWith(".yml"));
53
+ }
54
+ catch (error) {
55
+ const fsErrorCode = error?.code ?? "UNKNOWN";
56
+ return { status: "unreadable", fsErrorCode };
57
+ }
58
+ return entries.length > 0
59
+ ? { status: "healthy", entryCount: entries.length }
60
+ : { status: "empty" };
61
+ }
3
62
  export class AstGrepRuleManager {
4
63
  ruleDir;
5
64
  log;
@@ -12,11 +71,7 @@ export class AstGrepRuleManager {
12
71
  if (this.ruleDescriptions !== null)
13
72
  return this.ruleDescriptions;
14
73
  const descriptions = new Map();
15
- const possiblePaths = [
16
- path.join(this.ruleDir, "ast-grep-rules", "rules"),
17
- path.join(this.ruleDir, "rules"),
18
- this.ruleDir,
19
- ];
74
+ const possiblePaths = candidateAstGrepRulesPaths(this.ruleDir);
20
75
  const rulesPath = possiblePaths.find((p) => fs.existsSync(p));
21
76
  if (!rulesPath) {
22
77
  this.log(`Rule descriptions: no rules directory found in ${possiblePaths.join(", ")}`);
@@ -11,9 +11,9 @@
11
11
  */
12
12
  import * as path from "node:path";
13
13
  import { isTestMode } from "./env-utils.js";
14
- import { getGlobalPiLensDir } from "./file-utils.js";
14
+ import { getGlobalPiLensLogDir } from "./probe-home-state.js";
15
15
  import { createNdjsonLogger } from "./ndjson-logger.js";
16
- const AG_LOG_DIR = getGlobalPiLensDir();
16
+ const AG_LOG_DIR = getGlobalPiLensLogDir();
17
17
  const AG_LOG_FILE = path.join(AG_LOG_DIR, "ast-grep-tools.log");
18
18
  const AG_LOG_BACKUP_FILE = path.join(AG_LOG_DIR, "ast-grep-tools.log.1");
19
19
  const MAX_LOG_BYTES = Math.max(128 * 1024, Number.parseInt(process.env.PI_LENS_AST_GREP_LOG_MAX_BYTES ?? "1048576", 10) || 1048576);
@@ -115,11 +115,4 @@ export function logAstGrepToolEvent(event) {
115
115
  };
116
116
  writer.log({ ts: new Date().toISOString(), ...payload });
117
117
  }
118
- export function getAstGrepToolLogPath() {
119
- return AG_LOG_FILE;
120
- }
121
- /** Resolve once all enqueued ast-grep-tool writes are on disk. */
122
- export function flushAstGrepToolLog() {
123
- return writer.flush();
124
- }
125
118
  export { countLines as _countLinesForTest };
@@ -6,3 +6,5 @@
6
6
  * - ast-grep-rule-manager.ts
7
7
  */
8
8
  export {};
9
+ // =============================================================================
10
+ // JSON FORMAT (ast-grep CLI output)
@@ -18,6 +18,7 @@ import * as nodeFs from "node:fs";
18
18
  import * as path from "node:path";
19
19
  import { isReadableSourceFile } from "./file-kinds.js";
20
20
  import { countFileLines } from "./read-guard-tool-lines.js";
21
+ import { stripAnsi } from "./sanitize.js";
21
22
  function stripQuotes(token) {
22
23
  if (token.length >= 2) {
23
24
  const first = token[0];
@@ -28,11 +29,121 @@ function stripQuotes(token) {
28
29
  }
29
30
  return token;
30
31
  }
31
- function stripAnsi(value) {
32
- return value.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
32
+ function parseHeredocDelimiter(command, start) {
33
+ let i = start;
34
+ const stripTabs = command[i] === "-";
35
+ if (stripTabs)
36
+ i += 1;
37
+ while (/\s/.test(command[i] ?? ""))
38
+ i += 1;
39
+ let delimiter = "";
40
+ let quoted = false;
41
+ while (i < command.length && !/[\s;&|<>]/.test(command[i] ?? "")) {
42
+ const ch = command[i];
43
+ if (ch === "'" || ch === '"') {
44
+ quoted = true;
45
+ const quote = ch;
46
+ i += 1;
47
+ while (i < command.length && command[i] !== quote) {
48
+ delimiter += command[i++];
49
+ }
50
+ if (command[i] !== quote)
51
+ return undefined;
52
+ i += 1;
53
+ continue;
54
+ }
55
+ if (ch === "\\") {
56
+ quoted = true;
57
+ i += 1;
58
+ if (i >= command.length)
59
+ return undefined;
60
+ delimiter += command[i++];
61
+ continue;
62
+ }
63
+ delimiter += ch;
64
+ i += 1;
65
+ }
66
+ if (!delimiter)
67
+ return undefined;
68
+ return { heredoc: { delimiter, stripTabs, quoted }, end: i - 1 };
69
+ }
70
+ function heredocSubstitutionBodies(body) {
71
+ const substitutions = [];
72
+ for (let i = 0; i < body.length; i += 1) {
73
+ if (body.startsWith("$(", i)) {
74
+ let depth = 1;
75
+ let quote;
76
+ for (let end = i + 2; end < body.length; end += 1) {
77
+ const ch = body[end];
78
+ if (quote === "single") {
79
+ if (ch === "'")
80
+ quote = undefined;
81
+ continue;
82
+ }
83
+ if (quote === "double") {
84
+ if (ch === '"' && body[end - 1] !== "\\")
85
+ quote = undefined;
86
+ continue;
87
+ }
88
+ if (ch === "'" || ch === '"') {
89
+ quote = ch === "'" ? "single" : "double";
90
+ }
91
+ else if (body.startsWith("$(", end)) {
92
+ depth += 1;
93
+ end += 1;
94
+ }
95
+ else if (ch === ")") {
96
+ depth -= 1;
97
+ if (depth === 0) {
98
+ substitutions.push(body.slice(i + 2, end));
99
+ i = end;
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ }
105
+ else if (body[i] === "`" && body[i - 1] !== "\\") {
106
+ const end = body.indexOf("`", i + 1);
107
+ if (end >= 0) {
108
+ substitutions.push(body.slice(i + 1, end));
109
+ i = end;
110
+ }
111
+ }
112
+ }
113
+ return substitutions;
114
+ }
115
+ function consumeHeredocBodies(command, start, heredocs) {
116
+ let cursor = start;
117
+ const substitutions = [];
118
+ for (const heredoc of heredocs) {
119
+ const bodyStart = cursor;
120
+ let found = false;
121
+ while (cursor < command.length) {
122
+ const lineEnd = command.indexOf("\n", cursor);
123
+ const end = lineEnd < 0 ? command.length : lineEnd;
124
+ let line = command.slice(cursor, end);
125
+ if (heredoc.stripTabs)
126
+ line = line.replace(/^\t+/, "");
127
+ if (line.replace(/\r$/, "") === heredoc.delimiter) {
128
+ if (!heredoc.quoted)
129
+ substitutions.push(...heredocSubstitutionBodies(command.slice(bodyStart, cursor)));
130
+ cursor = lineEnd < 0 ? end : end + 1;
131
+ found = true;
132
+ break;
133
+ }
134
+ cursor = lineEnd < 0 ? end : end + 1;
135
+ }
136
+ if (!found) {
137
+ if (!heredoc.quoted)
138
+ substitutions.push(...heredocSubstitutionBodies(command.slice(bodyStart)));
139
+ return { end: command.length - 1, substitutions };
140
+ }
141
+ }
142
+ return { end: cursor - 1, substitutions };
33
143
  }
34
144
  export function tokenizeShellCommand(command) {
35
145
  const segments = [];
146
+ const pendingHeredocs = [];
36
147
  let tokens = [];
37
148
  let word = "";
38
149
  let quote;
@@ -116,12 +227,21 @@ export function tokenizeShellCommand(command) {
116
227
  i++;
117
228
  continue;
118
229
  }
119
- if (/\s/.test(ch)) {
230
+ if (/\s/.test(ch) && ch !== "\n") {
120
231
  flushWord();
121
232
  continue;
122
233
  }
123
234
  if (ch === ";" || ch === "\n" || ch === "|" || ch === "&") {
124
235
  flushWord();
236
+ if (ch === "\n" && pendingHeredocs.length > 0) {
237
+ const heredocs = pendingHeredocs.splice(0);
238
+ flushSegment();
239
+ const consumed = consumeHeredocBodies(command, i + 1, heredocs);
240
+ for (const substitution of consumed.substitutions)
241
+ segments.push(...tokenizeShellCommand(substitution));
242
+ i = consumed.end;
243
+ continue;
244
+ }
125
245
  let terminator;
126
246
  if (ch === "|" && next === "|")
127
247
  i++;
@@ -138,6 +258,16 @@ export function tokenizeShellCommand(command) {
138
258
  }
139
259
  if (ch === "<" || ch === ">") {
140
260
  flushWord();
261
+ if (ch === "<" &&
262
+ next === "<" &&
263
+ command[i - 1] !== "<" &&
264
+ command[i + 2] !== "<") {
265
+ const parsed = parseHeredocDelimiter(command, i + 2);
266
+ if (parsed) {
267
+ pendingHeredocs.push(parsed.heredoc);
268
+ i = parsed.end;
269
+ }
270
+ }
141
271
  unsupported = true;
142
272
  continue;
143
273
  }
@@ -75,8 +75,15 @@ export class BiomeClient {
75
75
  const cached = this.localBinaryByCwd.get(resolveCwd);
76
76
  if (cached)
77
77
  return { cmd: cached, args: [] };
78
- // Walk up from cwd looking for node_modules/.bin/biome BEFORE trusting
79
- // `autoInstalledBinaryPath` (#1731). That field is set once, the first
78
+ // Check `<cwd>/node_modules/.bin/biome` BEFORE trusting
79
+ // `autoInstalledBinaryPath` (#1731). NOT a walk, despite what this
80
+ // comment claimed until #2544 review F1 — the candidates below are
81
+ // joined onto `resolveCwd` and nothing climbs. Callers pass the edited
82
+ // file's own project/sub-package root (see above), which is where an
83
+ // npm-workspace install puts the shim; converting this to the shared
84
+ // ancestor walk is a behaviour change with no reported defect behind
85
+ // it, so it is deliberately NOT part of #2514's ceiling fold. That
86
+ // field is set once, the first
80
87
  // time `ensureAvailable()` auto-installs for ANY cwd this session, and
81
88
  // every later call for every OTHER cwd short-circuited on it — so a
82
89
  // project that ships its own biome never won once the session's first
@@ -61,6 +61,20 @@
61
61
  * reads distinctly from #1944's "retired, unrecoverable" — a capped record
62
62
  * COULD still resolve a fresh dispatch; it just stopped being handed one for
63
63
  * free.
64
+ *
65
+ * Widget-footer sibling (#2275). The turn-end blocker channel above is not
66
+ * the only surface that demotes on dependency drift — `widget-state.ts`'s
67
+ * own `files` map carries the identical demotion shape
68
+ * (`markWidgetFileBlockersStale`) through a completely separate store, with
69
+ * its own `WidgetDiagnostic.staleDeliveryCount` and its own retire helpers
70
+ * (`incrementWidgetDependencyDriftDelivery`,
71
+ * `retireWidgetDependencyDriftBlockers`). It counts RENDERS rather than
72
+ * turn ends — the footer draws one record per pass, so `renderWidget` marks
73
+ * what it served and the turn-end step drains those marks — and it retires
74
+ * by HIDING the row from the footer rather than dropping the record, since
75
+ * the widget store also backs `lens_diagnostics mode=all`. What it shares
76
+ * with this module is the one number both caps retire against,
77
+ * `DEPENDENCY_DRIFT_MAX_DELIVERIES`, rather than inventing a second one.
64
78
  */
65
79
  import * as fs from "node:fs";
66
80
  import { normalizeEphemeralMapKey } from "./path-utils.js";
@@ -153,12 +167,6 @@ async function resolveForwardImportsMemoized(cwd, filePath, resolveForwardImport
153
167
  });
154
168
  return imports;
155
169
  }
156
- /** Test-only: clear the extractor and import-resolution memos. */
157
- export function _resetBlockerFreshnessForTests() {
158
- extractorCache.clear();
159
- importResolutionMemo.clear();
160
- importResolutionMemoTurnIndex = undefined;
161
- }
162
170
  /**
163
171
  * Production forward-import resolver. Parses `filePath` with its tree-sitter grammar
164
172
  * and resolves every extracted import source to in-project files. Degrades to an