@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
@@ -160,6 +160,41 @@ export function resetSinkWriteFailures() {
160
160
  for (const state of ndjsonGlobalState.writers.values())
161
161
  state.writeFailures = 0;
162
162
  }
163
+ /**
164
+ * Snapshot of mid-session rotations, one entry per sink that has rotated
165
+ * at least once (#2505). Pure in-memory read — no I/O — so a caller
166
+ * (`degradation-ledger.ts`) can fold this into a durable ledger entry the
167
+ * same way it folds `getSinkWriteFailures()`, without this module importing
168
+ * the ledger back (see `NdjsonWriterState.rotationCount`'s doc comment).
169
+ */
170
+ export function getSinkRotations() {
171
+ if (!ndjsonGlobalState)
172
+ return [];
173
+ const result = [];
174
+ for (const state of ndjsonGlobalState.writers.values()) {
175
+ if (state.rotationCount > 0 || state.rotationFailures > 0) {
176
+ result.push({
177
+ file: state.file,
178
+ rotationCount: state.rotationCount,
179
+ failureCount: state.rotationFailures,
180
+ });
181
+ }
182
+ }
183
+ return result;
184
+ }
185
+ /**
186
+ * Session-boundary reset (catalog shape 17), same shape as
187
+ * `resetSinkWriteFailures`. Wired into `resetDegradationLedger()`.
188
+ */
189
+ export function resetSinkRotations() {
190
+ if (!ndjsonGlobalState)
191
+ return;
192
+ for (const state of ndjsonGlobalState.writers.values()) {
193
+ state.rotationCount = 0;
194
+ state.rotationFailures = 0;
195
+ state.rotationRetryAfterMs = 0;
196
+ }
197
+ }
163
198
  function requireCurrentGlobalState() {
164
199
  if (ndjsonGlobalState)
165
200
  return ndjsonGlobalState;
@@ -191,10 +226,14 @@ function assertCompatibleWriterOptions(existing, maxBytes, backupPath) {
191
226
  function writeQueueItemSync(state, item) {
192
227
  if (item.kind === "truncate") {
193
228
  fs.writeFileSync(state.file, "");
229
+ noteTruncated(state);
194
230
  }
195
231
  else {
196
- rotateIfNeeded(state);
197
- fs.appendFileSync(state.file, item.line);
232
+ // One line, so the batch cap has nothing to cap: the plan is only
233
+ // ever "rotate first if this line no longer fits".
234
+ const plan = planBoundedWrite(state, [item.line]);
235
+ fs.appendFileSync(state.file, plan.joined);
236
+ noteWriteSucceeded(state, plan.bytes);
198
237
  }
199
238
  }
200
239
  /**
@@ -269,6 +308,20 @@ function createWriterState(file, maxBytes, backupPath) {
269
308
  // A state adopted from a pre-#1970 module graph predates this field.
270
309
  if (typeof existing.writeFailures !== "number")
271
310
  existing.writeFailures = 0;
311
+ // A state adopted from a pre-#2505 module graph predates these fields.
312
+ // (`knownSize` itself needs no adoption shim: its type is
313
+ // `number | undefined`, so a value that is neither is unreachable —
314
+ // #2515 review S2.)
315
+ if (typeof existing.writesSinceStatSync !== "number")
316
+ existing.writesSinceStatSync = 0;
317
+ if (typeof existing.lastStatSyncMs !== "number")
318
+ existing.lastStatSyncMs = 0;
319
+ if (typeof existing.rotationCount !== "number")
320
+ existing.rotationCount = 0;
321
+ if (typeof existing.rotationFailures !== "number")
322
+ existing.rotationFailures = 0;
323
+ if (typeof existing.rotationRetryAfterMs !== "number")
324
+ existing.rotationRetryAfterMs = 0;
272
325
  return existing;
273
326
  }
274
327
  const state = {};
@@ -282,6 +335,12 @@ function createWriterState(file, maxBytes, backupPath) {
282
335
  state.ensuredDir = false;
283
336
  state.exitFlusher = () => flushStateSync(state);
284
337
  state.writeFailures = 0;
338
+ state.knownSize = undefined;
339
+ state.writesSinceStatSync = 0;
340
+ state.lastStatSyncMs = 0;
341
+ state.rotationCount = 0;
342
+ state.rotationFailures = 0;
343
+ state.rotationRetryAfterMs = 0;
285
344
  globalState.writers.set(file, state);
286
345
  registerWriter(state);
287
346
  return state;
@@ -305,32 +364,191 @@ async function ensureDirAsync(state) {
305
364
  // telemetry is best-effort
306
365
  }
307
366
  }
308
- function rotateIfNeeded(state) {
309
- if (state.maxBytes === undefined)
367
+ // Rotation-check cadence (#2505): the real `fs.statSync` reconciliation below
368
+ // is throttled to at most once per this many writes OR this many elapsed ms,
369
+ // whichever comes first — never once per individual write. Between
370
+ // reconciliations, `state.knownSize` (updated cheaply, no I/O, after every
371
+ // successful write) is trusted. A short window in both axes bounds how far a
372
+ // concurrent writer to the same global log (another pi-lens process sharing
373
+ // ~/.pi-lens) can drift `knownSize` from the real file before the next
374
+ // reconciliation self-heals it.
375
+ const ROTATION_STAT_RESYNC_WRITES = 25;
376
+ const ROTATION_STAT_RESYNC_MS = 2_000;
377
+ /** Reconcile `state.knownSize` with a real stat, gated by the cadence above. */
378
+ function syncKnownSizeIfDue(state, now) {
379
+ const due = state.knownSize === undefined ||
380
+ state.writesSinceStatSync >= ROTATION_STAT_RESYNC_WRITES ||
381
+ now - state.lastStatSyncMs >= ROTATION_STAT_RESYNC_MS;
382
+ if (!due)
310
383
  return;
384
+ state.writesSinceStatSync = 0;
385
+ state.lastStatSyncMs = now;
386
+ try {
387
+ state.knownSize = fs.statSync(state.file).size;
388
+ }
389
+ catch {
390
+ // No file yet (first write) or a transient stat error — treat as
391
+ // empty; the next successful write/rotate re-establishes the truth.
392
+ state.knownSize = 0;
393
+ }
394
+ }
395
+ /**
396
+ * A rotation attempt that FAILS (an unwritable backup path, or the Windows
397
+ * sharing violation another process holding the file open produces) must not
398
+ * be re-attempted by every subsequent write: that is a syscall storm that
399
+ * never succeeds. After a failure the next attempt is deferred by this many
400
+ * ms. The sink keeps writing during the window — dropping lines would be a
401
+ * worse trade than an oversized file — and the failure is reported through
402
+ * `getSinkRotations()` as `log-sink-rotate-failed`, so an unbounded log is
403
+ * visible in `pilens_health` instead of silent (#2505 review F2).
404
+ */
405
+ const ROTATION_FAILURE_BACKOFF_MS = 10_000;
406
+ /**
407
+ * Move the active file aside, and report whether that actually happened.
408
+ *
409
+ * The in-memory size check that gets us here is deliberately cheap and
410
+ * therefore fallible: another process writing the SAME global log (a pi
411
+ * session and the warm MCP server share one global read-guard.log) moves the
412
+ * real file under us, so a cached size can be stale in either direction.
413
+ * Believing a stale-HIGH size is destructive, not merely wasteful — it
414
+ * force-removes the other process backup and renames that process freshly
415
+ * rotated (tiny) file on top of it, losing real log data. So the decision is
416
+ * CONFIRMED against a real stat here, on the rare path where a rotation is
417
+ * believed due, instead of on the hot path where every write would pay for
418
+ * it (#2505 review F4).
419
+ */
420
+ function rotateNow(state, incomingBytes, now) {
421
+ if (state.maxBytes === undefined)
422
+ return false;
423
+ if (now < state.rotationRetryAfterMs)
424
+ return false;
425
+ let actualSize;
426
+ try {
427
+ actualSize = fs.statSync(state.file).size;
428
+ }
429
+ catch {
430
+ // No file yet — nothing to rotate, and the next write creates it.
431
+ state.knownSize = 0;
432
+ state.writesSinceStatSync = 0;
433
+ state.lastStatSyncMs = now;
434
+ return false;
435
+ }
436
+ state.knownSize = actualSize;
437
+ state.writesSinceStatSync = 0;
438
+ state.lastStatSyncMs = now;
439
+ // The real file disagrees with the cached belief: nothing to do. This is
440
+ // the cross-process case above, and declining here is exactly what
441
+ // preserves the other process backup.
442
+ if (actualSize === 0)
443
+ return false;
444
+ if (actualSize + incomingBytes < state.maxBytes)
445
+ return false;
446
+ const backup = state.backupPath ?? `${state.file}.1`;
311
447
  try {
312
- const size = fs.statSync(state.file).size;
313
- if (size < state.maxBytes)
314
- return;
315
- const backup = state.backupPath ?? `${state.file}.1`;
316
448
  runBestEffort(() => fs.rmSync(backup, { force: true }));
317
449
  fs.renameSync(state.file, backup);
318
450
  }
319
451
  catch {
320
- // no file yet, or rename raced — nothing to rotate
452
+ // The rename failed and the file is still there at `actualSize` (which
453
+ // `knownSize` now holds — no guessing, the stat above just confirmed
454
+ // it). Counted rather than swallowed so `log-sink-rotate-failed` can
455
+ // surface an unbounded sink, and backed off so the next write does not
456
+ // re-run the same failing syscall.
457
+ state.rotationFailures += 1;
458
+ state.rotationRetryAfterMs = now + ROTATION_FAILURE_BACKOFF_MS;
459
+ return false;
321
460
  }
461
+ state.knownSize = 0;
462
+ state.rotationCount += 1;
463
+ state.rotationRetryAfterMs = 0;
464
+ return true;
465
+ }
466
+ function takeAll(lines) {
467
+ const joined = lines.join("");
468
+ return { count: lines.length, joined, bytes: Buffer.byteLength(joined) };
469
+ }
470
+ /**
471
+ * Decide what this append writes, rotating first when the file already on
472
+ * disk leaves no room. Two things have to hold, and the pre-#2505 write path
473
+ * did neither:
474
+ *
475
+ * 1. The bound is checked against the size this write PRODUCES, not only
476
+ * the size already on disk — otherwise the write that crosses the bound
477
+ * is always allowed through and only the NEXT one rotates (one write
478
+ * late), which on a long-lived or idle-tailed session (the warm MCP
479
+ * server never re-runs the session-start sweep in `log-cleanup.ts`) may
480
+ * be a long time or never.
481
+ * 2. The batch ITSELF is capped at the bound. Rotation only ever moves
482
+ * PRE-EXISTING content aside, so an oversized batch written whole into
483
+ * an empty (or just-rotated) file lands past the bound with nothing left
484
+ * to rotate away: a 500-line drain against a 1KB bound landed at ~107KB,
485
+ * 106x over, with zero rotations. Capping makes the drain loop come back
486
+ * around for the remainder instead.
487
+ *
488
+ * A single NDJSON line is atomic and cannot be split, so at least one line
489
+ * is always taken: the enforced invariant is "the bound plus at most one
490
+ * line", never "the bound plus an unbounded batch".
491
+ */
492
+ function planBoundedWrite(state, lines) {
493
+ if (state.maxBytes === undefined || lines.length === 0)
494
+ return takeAll(lines);
495
+ const now = Date.now();
496
+ syncKnownSizeIfDue(state, now);
497
+ state.writesSinceStatSync += 1;
498
+ const firstBytes = Buffer.byteLength(lines[0] ?? "");
499
+ let known = state.knownSize ?? 0;
500
+ if (known > 0 && known + firstBytes >= state.maxBytes) {
501
+ rotateNow(state, firstBytes, now);
502
+ known = state.knownSize ?? 0;
503
+ if (known > 0 && known + firstBytes >= state.maxBytes) {
504
+ // Rotation is unavailable (a failing rename, or its backoff window).
505
+ // Capping cannot bound a file that cannot be rotated — it would only
506
+ // shred each drain into one append per line for the rest of the
507
+ // window. Write the whole batch; the reason the bound is not holding
508
+ // is reported through `log-sink-rotate-failed`.
509
+ return takeAll(lines);
510
+ }
511
+ }
512
+ let bytes = 0;
513
+ let count = 0;
514
+ for (const line of lines) {
515
+ const lineBytes = Buffer.byteLength(line);
516
+ if (count > 0 && known + bytes + lineBytes >= state.maxBytes)
517
+ break;
518
+ bytes += lineBytes;
519
+ count += 1;
520
+ }
521
+ if (count === lines.length)
522
+ return takeAll(lines);
523
+ return { count, joined: lines.slice(0, count).join(""), bytes };
524
+ }
525
+ /** Cheap in-memory bookkeeping after a write actually lands (#2505). */
526
+ function noteWriteSucceeded(state, bytes) {
527
+ if (state.maxBytes === undefined)
528
+ return;
529
+ state.knownSize = (state.knownSize ?? 0) + bytes;
530
+ }
531
+ /** The file is now definitively empty — no guessing needed (#2505). */
532
+ function noteTruncated(state) {
533
+ if (state.maxBytes === undefined)
534
+ return;
535
+ state.knownSize = 0;
536
+ state.writesSinceStatSync = 0;
537
+ state.lastStatSyncMs = Date.now();
322
538
  }
323
539
  async function writeQueueItemAsync(state, item) {
324
540
  if (item.kind === "truncate") {
325
541
  await fs.promises.writeFile(state.file, "");
542
+ noteTruncated(state);
326
543
  }
327
544
  else {
328
545
  // Rotation is deliberately synchronous here. This function is only
329
546
  // reached from the already-deferred drain, and keeping stat/rm/rename
330
547
  // in one synchronous section prevents flushSync from racing a late
331
548
  // async rename after it has written new data.
332
- rotateIfNeeded(state);
333
- await fs.promises.appendFile(state.file, item.line);
549
+ const plan = planBoundedWrite(state, [item.line]);
550
+ await fs.promises.appendFile(state.file, plan.joined);
551
+ noteWriteSucceeded(state, plan.bytes);
334
552
  }
335
553
  }
336
554
  /** See `applyQueueItemSync`'s doc comment for the reopen-and-retry-once shape. */
@@ -363,20 +581,29 @@ async function drainLoop(state) {
363
581
  ? state.queue.findIndex((queued) => queued.kind === "truncate")
364
582
  : 0;
365
583
  const pendingEnd = truncateIndex === -1 ? state.queue.length : truncateIndex;
366
- const pending = item.kind === "truncate" ? [item] : state.queue.slice(0, pendingEnd);
584
+ const offered = item.kind === "truncate" ? [item] : state.queue.slice(0, pendingEnd);
585
+ // Rotation and the batch cap are decided synchronously, BEFORE this
586
+ // batch is published as in-flight: rotation stays inside the already-
587
+ // deferred drain (only the append remains async), so no awaited
588
+ // rotation step can run after flushSync has written to the active file.
589
+ const plan = item.kind === "truncate"
590
+ ? null
591
+ : planBoundedWrite(state, offered.map((queued) => queued.line));
592
+ // Only the lines the plan actually takes belong to THIS write. A batch
593
+ // that would itself cross `maxBytes` is cut at the bound and the loop
594
+ // comes back around for the remainder (#2505) — writing it whole would
595
+ // sail past a bound that rotation cannot recover, because rotation only
596
+ // moves pre-existing content aside.
597
+ const pending = plan === null ? offered : offered.slice(0, plan.count);
367
598
  state.inFlightBatch = pending;
368
599
  const writeBatch = async () => {
369
- if (item.kind === "truncate") {
600
+ if (plan === null) {
370
601
  await fs.promises.writeFile(state.file, "");
602
+ noteTruncated(state);
371
603
  }
372
604
  else {
373
- // Rotation is kept synchronous inside the deferred drain. The
374
- // append remains async, but no awaited rotation step can run after
375
- // flushSync has written to the active file.
376
- rotateIfNeeded(state);
377
- await fs.promises.appendFile(state.file, pending
378
- .map((queued) => queued.line)
379
- .join(""));
605
+ await fs.promises.appendFile(state.file, plan.joined);
606
+ noteWriteSucceeded(state, plan.bytes);
380
607
  }
381
608
  };
382
609
  try {
@@ -0,0 +1,101 @@
1
+ /**
2
+ * What pi-lens ALREADY tracks, and where an observed change is replayed to
3
+ * (#2430).
4
+ *
5
+ * The observational net has to answer one question in three places — the
6
+ * `tool_call` pre-snapshot, the `tool_result` diff, and the `agent_settled`
7
+ * sweep — and the answer must be the same set every time, or a file drifts in
8
+ * and out of coverage depending on which seam asked. This module is that single
9
+ * source: the read-guard's read/write set, the widget's diagnostic files, and
10
+ * the documents open on any live language server rooted at the workspace.
11
+ *
12
+ * There is deliberately NO workspace walk here. The whole point of #2430 item 3
13
+ * is that the turn-boundary net costs a bounded number of stats over files
14
+ * pi-lens has already seen; a walk would make the settle boundary pay for the
15
+ * project's size on every run.
16
+ *
17
+ * The replay recorder is the mutation bridge. Nothing in this module writes
18
+ * bookkeeping itself: an observed change goes through exactly the seam an
19
+ * in-process producer uses, so the read-guard stamp, the `turn-state.json`
20
+ * entry, the attributed change-log receipt and the deferred format at
21
+ * `agent_settled` are the SAME code path a `write` takes.
22
+ */
23
+ import { getLSPService } from "./lsp/index.js";
24
+ import { getMutationBridge } from "./mutation-bridge.js";
25
+ import { getFileDiagnosticSummaries } from "./widget-state.js";
26
+ /**
27
+ * Files pi-lens has read, written, diagnosed, or opened on a language server.
28
+ *
29
+ * Order is deliberate and the cap is applied ACROSS the whole union: the
30
+ * read-guard set is the most direct evidence the agent is working on a file,
31
+ * so it is added first and a truncating cap never drops it in favour of a
32
+ * cascade neighbour some server happened to open.
33
+ */
34
+ export function collectTrackedPaths(args) {
35
+ const tracked = new Set();
36
+ const add = (paths) => {
37
+ for (const filePath of paths) {
38
+ if (tracked.size >= args.limit)
39
+ return;
40
+ if (typeof filePath === "string" && filePath.length > 0)
41
+ tracked.add(filePath);
42
+ }
43
+ };
44
+ try {
45
+ add(args.readGuard?.getTrackedPaths?.() ?? []);
46
+ }
47
+ catch {
48
+ // A guard mid-eviction contributes nothing; the sweep stays advisory.
49
+ }
50
+ try {
51
+ add(getFileDiagnosticSummaries().map((summary) => summary.filePath));
52
+ }
53
+ catch {
54
+ // Widget state is display state; it must never break the net.
55
+ }
56
+ if (args.cwd) {
57
+ try {
58
+ add(getLSPService().getOpenDocumentPaths(args.cwd));
59
+ }
60
+ catch {
61
+ // No pool, or a client torn down mid-enumeration.
62
+ }
63
+ }
64
+ return [...tracked];
65
+ }
66
+ /**
67
+ * Read-guard stored per-line hashes for a file, newest record first.
68
+ *
69
+ * This is the "content diff against the read-guard's stored content" #2430
70
+ * asks for: #505 already keeps an FNV-1a hash per line for every read, so a
71
+ * post-mutation re-hash names exactly the lines that changed without pi-lens
72
+ * having to have kept the bytes.
73
+ */
74
+ export function storedLineHashesFor(readGuard, filePath) {
75
+ try {
76
+ const history = readGuard?.getReadHistory?.(filePath) ?? [];
77
+ for (let index = history.length - 1; index >= 0; index -= 1) {
78
+ const hashes = history[index]?.lineHashes;
79
+ if (hashes && Object.keys(hashes).length > 0)
80
+ return hashes;
81
+ }
82
+ }
83
+ catch {
84
+ // No history is the same answer as no hashes: derive no ranges.
85
+ }
86
+ return undefined;
87
+ }
88
+ /**
89
+ * Replay an observed change through the mutation bridge.
90
+ *
91
+ * Returns `false` when the bridge is not mounted (pi-lens not activated, or a
92
+ * unit test that never registered one) or when the bridge itself declined the
93
+ * entry — out of scope, ignored, or a bookkeeping failure. A `false` is a real
94
+ * answer the caller acts on: it does NOT count as evidence the tool was clean.
95
+ */
96
+ export function replayThroughMutationBridge(entry) {
97
+ const bridge = getMutationBridge();
98
+ if (!bridge)
99
+ return false;
100
+ return bridge.recordMutation(entry);
101
+ }