@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
@@ -1,10 +1,12 @@
1
1
  import * as nodeFs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { loadBootstrapClients } from "./bootstrap.js";
3
+ import { loadBootstrapClients, requestBootstrapClients } from "./bootstrap.js";
4
+ import { getAmbientAbortSignal } from "./safe-spawn.js";
4
5
  import { recordDegradationOnce } from "./degradation-ledger.js";
5
6
  import { detectFileKind } from "./file-kinds.js";
6
7
  import { isPathIgnoredByProject } from "./file-utils.js";
7
8
  import { evaluateGitGuard, isGitCommitOrPushAttempt } from "./git-guard.js";
9
+ import { dropHashlineAnchorMemo } from "./hashline-anchor.js";
8
10
  import { evaluateSharedCheckoutGuard } from "./shared-checkout-guard.js";
9
11
  import { logLatency } from "./latency-logger.js";
10
12
  import { normalizeMapKey } from "./path-utils.js";
@@ -12,6 +14,10 @@ import { captureFileStats, getOpaqueBaselineStore, isGitWorktree, } from "./opaq
12
14
  import { normalizeForGuardMatch } from "./host-edit-normalize.js";
13
15
  import { retargetReplacementIndentation } from "./indent-retarget.js";
14
16
  import { LANGUAGE_POLICY } from "./language-policy.js";
17
+ import { isComplexitySupportedFile } from "./tree-sitter-shared.js";
18
+ import { classifyMutatingTool, readMutationPathField, } from "./mutating-tool.js";
19
+ import { isProvisionalLearnedAttribution } from "./mutation-attribution.js";
20
+ import { armObservedMutation } from "./observed-mutation.js";
15
21
  import { getLSPService } from "./lsp/index.js";
16
22
  import { findDocumentSymbolAtLine, getOpenDocumentSymbols, lspSymbolKindName, qualifiedLspSymbolName, } from "./lsp-document-symbols.js";
17
23
  import { computeTrailingWhitespaceOldTextPatch, findUniqueMatchLineRange, } from "./oldtext-autopatch.js";
@@ -19,21 +25,45 @@ import { applyPartiallyApplicableEdits } from "./partial-edit-apply.js";
19
25
  import { isExternalOrVendorFile, resolveHostPathVariants, resolveHostToolPath, } from "./path-utils.js";
20
26
  import { EXPANSION_BUDGET_MS, EXPANSION_LIMIT_LINES, tryExpandRead, } from "./read-expansion.js";
21
27
  import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
22
- import { countFileLines, getTouchedLinesForGuard, relocateEditRange, tryCorrectIndentationMismatch, tryCorrectIndentationMismatchFromContent, } from "./read-guard-tool-lines.js";
28
+ import { countFileLines, formatAlreadyAppliedNotes, getTouchedLinesForGuard, relocateEditRange, tryCorrectIndentationMismatch, tryCorrectIndentationMismatchFromContent, } from "./read-guard-tool-lines.js";
23
29
  import { handleToolResult } from "./runtime-tool-result.js";
24
- import { isToolCallEventType, resolveToolCallCorrelationId, } from "./tool-event.js";
30
+ import { resolveToolCallCorrelationId } from "./tool-event.js";
25
31
  import { getSharedTreeSitterClient } from "./tree-sitter-shared.js";
26
32
  const LSP_TOOLCALL_NAV_TOUCH_BUDGET_MS = Math.max(0, Number.parseInt(process.env.PI_LENS_TOOLCALL_NAV_TOUCH_MS ??
27
33
  process.env.PI_LENS_LSP_NAV_CLIENT_WAIT_MS ??
28
34
  "1500", 10) || 1500);
29
35
  const LSP_TOOLCALL_TOUCH_BUDGET_MS = Math.max(0, Number.parseInt(process.env.PI_LENS_TOOLCALL_TOUCH_MS ?? "750", 10) || 750);
36
+ /**
37
+ * Composes the final block reason for a partial apply whose commit landed
38
+ * (#2402). The committed bytes lead the message; the preflight's per-edit
39
+ * failure bodies follow UNCHANGED, so they still describe exactly the edits
40
+ * that were NOT applied. The preflight header (šŸ”„/šŸ›‘) is never reused here —
41
+ * relabelling committed edits as a retryable oldText miss is the #2402 defect.
42
+ */
43
+ function composePartialApplyReason(args) {
44
+ const parts = [];
45
+ const editSuffix = args.appliedCount === 1 ? "" : "s";
46
+ parts.push(args.postEditStatus === "failed"
47
+ ? `āš ļø PARTIAL APPLY — ${args.appliedCount} edit${editSuffix} committed (${args.appliedIndices}). Post-edit analysis failed after the commit; the committed bytes stand and were not reverted. Do NOT resubmit the applied edits.`
48
+ : `āš ļø PARTIAL APPLY — ${args.appliedCount} edit${editSuffix} committed (${args.appliedIndices}). Do NOT resubmit the applied edits.`);
49
+ if (args.preflightDetails && args.preflightDetails.length > 0) {
50
+ parts.push(args.preflightDetails.join("\n\n"));
51
+ }
52
+ const alreadyNotes = formatAlreadyAppliedNotes(args.alreadyAppliedEdits);
53
+ if (alreadyNotes)
54
+ parts.push(alreadyNotes.trimStart());
55
+ if (args.postEditOutput && args.postEditStatus === "succeeded") {
56
+ parts.push(`Post-apply analysis:\n${args.postEditOutput}`);
57
+ }
58
+ return parts.join("\n\n");
59
+ }
30
60
  function getToolCallRawFilePath(toolName, event) {
31
61
  const inputObj = (event.input ?? {});
32
- if (isToolCallEventType("write", event) ||
33
- isToolCallEventType("edit", event)) {
34
- const filePath = event.input.path;
35
- return typeof filePath === "string" ? filePath : undefined;
36
- }
62
+ // #2423: the seam owns "does this tool target a file it mutates". No ctx is
63
+ // passed — the path is not resolved yet, so adapters must not log here.
64
+ const mutation = classifyMutatingTool({ ...event, toolName });
65
+ if (mutation)
66
+ return mutation.path;
37
67
  if (toolName === "read") {
38
68
  if (typeof inputObj.path === "string")
39
69
  return inputObj.path;
@@ -163,11 +193,12 @@ function isIndentationOnlyChange(before, after) {
163
193
  return beforeLines.every((line, index) => line.trim() === afterLines[index].trim());
164
194
  }
165
195
  function getNewContentFromToolCall(event) {
166
- if (isToolCallEventType("write", event)) {
196
+ const mutation = classifyMutatingTool(event);
197
+ if (mutation?.kind === "write") {
167
198
  return event.input
168
199
  .content;
169
200
  }
170
- if (isToolCallEventType("edit", event)) {
201
+ if (mutation?.kind === "edit") {
171
202
  const edits = event.input.edits;
172
203
  return edits?.map((edit) => edit.newText ?? "").join("\n");
173
204
  }
@@ -274,10 +305,20 @@ export async function handleToolCall(deps) {
274
305
  }
275
306
  async function handleToolCallImpl(deps) {
276
307
  const { event, ctx, lensEnabled, getFlag, dbg, runtime, cacheManager, ensureLSPConfigInitialized, updateLspStatus, resetLSPService, getTreeSitterClient = getSharedTreeSitterClient, } = deps;
308
+ // #2423 review round 4, finding F5: the hashline anchor memo is keyed by
309
+ // mtime+size, which a same-size rewrite inside one mtime tick cannot
310
+ // distinguish from stale content. It only ever needs to survive the
311
+ // several `classifyMutatingTool` asks WITHIN this one tool_call, so drop
312
+ // it here at the boundary rather than trusting mtime+size across calls.
313
+ dropHashlineAnchorMemo();
277
314
  const readGuardCorrelationId = getReadGuardCorrelationId(event);
278
315
  let filePath;
279
316
  const logToolReadGuardEvent = (entry) => logReadGuardEvent({ ...entry, correlationId: readGuardCorrelationId });
280
317
  const toolName = event.toolName ?? "";
318
+ // #2423: one classification per tool_call, reused by every branch below that
319
+ // used to compare `toolName` to the `"write"` / `"edit"` literals. No ctx —
320
+ // `filePath` is not resolved yet, and adapters stay silent without one.
321
+ const mutation = classifyMutatingTool(event);
281
322
  const editInputForTelemetry = event.input;
282
323
  // #1655 item 3: SNAPSHOT the requested batch width here, at handler entry.
283
324
  // `input` is a live, mutable, extension-ordered object — pi types it
@@ -291,12 +332,12 @@ async function handleToolCallImpl(deps) {
291
332
  // object hundreds of lines and several `await`s later, so a batch that
292
333
  // changed width in between produced an internally inconsistent summary —
293
334
  // indexes from the call-time array, totals from the mutated one.
294
- const requestedEditIndexes = toolName === "write"
335
+ const requestedEditIndexes = mutation?.kind === "write"
295
336
  ? [0]
296
337
  : Array.isArray(editInputForTelemetry?.edits)
297
338
  ? boundedIndexesForCount(editInputForTelemetry.edits.length)
298
339
  : [0];
299
- const requestedEditTotal = toolName === "write"
340
+ const requestedEditTotal = mutation?.kind === "write"
300
341
  ? 1
301
342
  : Array.isArray(editInputForTelemetry?.edits)
302
343
  ? editInputForTelemetry.edits.length
@@ -374,6 +415,46 @@ async function handleToolCallImpl(deps) {
374
415
  }
375
416
  }
376
417
  }
418
+ // #2430: the observational net. A call the seam could NOT classify, whose
419
+ // input still names a file, gets a bounded pre-snapshot so the tool_result
420
+ // side can see whether it actually wrote anything. `bash` is excluded
421
+ // because it already has its own (wider, git-first) baseline above, and a
422
+ // classified mutation never reaches here at all — that is what keeps the
423
+ // cost of a plain write/edit at zero.
424
+ //
425
+ // `isProvisionalLearnedAttribution` is the ONE exception (#2449 review round
426
+ // 2, F2): a tool attributed from a single observation IS classified from
427
+ // here on, but its attribution has not earned persistence yet, and the only
428
+ // thing that can earn it is a second real disk diff. Without this clause the
429
+ // tool is classified on call two and never observed again, so
430
+ // `PERSIST_AFTER_OBSERVATIONS = 2` is unreachable and nothing is ever
431
+ // written to disk for the next session to learn from.
432
+ //
433
+ // The eligibility check inside `armObservedMutation` is a map lookup, so an
434
+ // ineligible tool (durably attributed, or twice observed clean) pays that
435
+ // and nothing else. The universe is the TARGET PATH alone, so an armed call
436
+ // costs one stat plus one hash of the file it named — not a directory walk.
437
+ if ((mutation === undefined || isProvisionalLearnedAttribution(toolName)) &&
438
+ toolName !== "bash" &&
439
+ !getFlag("no-read-guard")) {
440
+ const observedRawPath = readMutationPathField(event);
441
+ const observedPath = observedRawPath
442
+ ? resolveToolCallFilePath(observedRawPath, ctx.cwd, runtime.projectRoot)
443
+ ?.path
444
+ : undefined;
445
+ if (observedPath) {
446
+ await armObservedMutation({
447
+ toolCallId: resolveToolCallCorrelationId(event),
448
+ toolName,
449
+ targetPath: observedPath,
450
+ cwd: ctx.cwd ?? runtime.projectRoot,
451
+ sessionGeneration: runtime.sessionGeneration,
452
+ turnIndex: runtime.turnIndex,
453
+ signal: ctx.signal,
454
+ dbg,
455
+ });
456
+ }
457
+ }
377
458
  if (getFlag("lens-guard") &&
378
459
  isGitCommitOrPushAttempt(toolName, event.input)) {
379
460
  const guard = evaluateGitGuard(runtime, cacheManager, ctx.cwd ?? runtime.projectRoot);
@@ -419,7 +500,7 @@ async function handleToolCallImpl(deps) {
419
500
  return;
420
501
  dbg(`tool_call fired for: ${filePath} (exists: ${nodeFs.existsSync(filePath)})`);
421
502
  const toolCallId = resolveToolCallCorrelationId(event);
422
- const attributesMutationTarget = toolCallId !== undefined && (toolName === "write" || toolName === "edit");
503
+ const attributesMutationTarget = toolCallId !== undefined && mutation !== undefined;
423
504
  const targetMissing = !nodeFs.existsSync(filePath);
424
505
  // #1642 F1: a brand-new file's WRITE is never a "skip" — `tool_call`
425
506
  // fires PRE-execution, so `existsSync` is false for every path a write
@@ -457,7 +538,7 @@ async function handleToolCallImpl(deps) {
457
538
  // those paths have no quote and no AM/PM, so every stage-2 candidate
458
539
  // collapses onto the base path and nothing is "tried". `unresolved` is
459
540
  // the whole condition; the tried list is detail for the reason string.
460
- if (toolName !== "write" && pathResolution?.unresolved) {
541
+ if (mutation?.kind !== "write" && pathResolution?.unresolved) {
461
542
  const tried = pathResolution.triedVariants.length > 0
462
543
  ? `tried ${pathResolution.triedVariants.join(", ")}`
463
544
  : "no variant differed from the resolved path";
@@ -480,8 +561,7 @@ async function handleToolCallImpl(deps) {
480
561
  const shouldWarmReadLsp = toolName === "read" &&
481
562
  lspAutoTouchEligible &&
482
563
  runtime.shouldWarmLspOnRead(filePath);
483
- const shouldAutoTouch = (toolName === "write" ||
484
- toolName === "edit" ||
564
+ const shouldAutoTouch = (mutation !== undefined ||
485
565
  toolName === "lsp_navigation" ||
486
566
  shouldWarmReadLsp) &&
487
567
  !getFlag("no-lsp") &&
@@ -675,13 +755,42 @@ async function handleToolCallImpl(deps) {
675
755
  timestamp: Date.now(),
676
756
  });
677
757
  }
678
- const { complexityClient } = await loadBootstrapClients();
679
758
  // Record complexity baseline for historical tracking (booboo/tdi).
680
759
  // Not shown inline - just captured for delta analysis.
681
- if (!isExternalOrVendor &&
682
- complexityClient.isSupportedFile(filePath) &&
683
- !runtime.complexityBaselines.has(filePath)) {
684
- const baseline = await complexityClient.analyzeFile(filePath);
760
+ //
761
+ // #2467: every client-free guard runs FIRST, so a tool call that cannot
762
+ // produce a baseline never loads the analyzer graph. This await used to sit
763
+ // above them and fire on EVERY tool_call — a bash command, a grep, a read
764
+ // of a vendored file, a second read of an already-baselined file all paid
765
+ // the seventeen-module load.
766
+ //
767
+ // `isComplexitySupportedFile` is the LAST of those guards and the one that
768
+ // matters most in a real repo: complexity has node mappings for six
769
+ // grammars, so every .md/.json/.yaml/.css/.java/.sh read is unsupported.
770
+ // Asking the CLIENT (`isSupportedFile`) would mean loading the graph to
771
+ // learn the answer is no — and because only a produced baseline memoizes
772
+ // the file, the same read would pay it again on every repeat. The predicate
773
+ // is the client's own answer, hoisted into `tree-sitter-shared.ts` where it
774
+ // needs nothing but the extension registry; `ComplexityClient.isSupportedFile`
775
+ // delegates to it, so this is not a second copy.
776
+ if (!getFlag("no-complexity") &&
777
+ !isExternalOrVendor &&
778
+ filePath &&
779
+ !runtime.complexityBaselines.has(filePath) &&
780
+ isComplexitySupportedFile(filePath)) {
781
+ // Fail open: no clients means no baseline for this call, counted once in
782
+ // the ledger. A complexity baseline is delta-analysis bookkeeping — it
783
+ // must never be the reason a user's tool call fails or stalls.
784
+ const complexityClient = (await requestBootstrapClients({
785
+ reason: "tool-call-complexity-baseline",
786
+ // The pre-dispatch hook. It carries no wall budget in #2523's
787
+ // contract, which is why `LedgerHookKey` names it alongside the
788
+ // budgeted families rather than leaving this site to spell its
789
+ // own axis value (#2557 review F7).
790
+ hook: "tool_call",
791
+ signal: getAmbientAbortSignal(),
792
+ }))?.complexityClient;
793
+ const baseline = await complexityClient?.analyzeFile(filePath);
685
794
  if (baseline) {
686
795
  runtime.complexityBaselines.set(filePath, baseline);
687
796
  const { captureSnapshot } = await import("./metrics-history.js");
@@ -695,11 +804,20 @@ async function handleToolCallImpl(deps) {
695
804
  });
696
805
  }
697
806
  }
807
+ else if (getFlag("no-complexity") &&
808
+ filePath &&
809
+ isComplexitySupportedFile(filePath)) {
810
+ recordDegradationOnce({
811
+ kind: "startup-analyzer-disabled",
812
+ subject: "complexity",
813
+ reason: "skipped (disabled by config)",
814
+ });
815
+ }
698
816
  // --- Read-Before-Edit Guard: check edits ---
699
817
  // write = full replacement; no prior read needed (you're starting fresh).
700
818
  // edit = partial modification; guard enforced to prevent blind overwrites.
701
- const isEditOnly = isToolCallEventType("edit", event);
702
- const isWriteOrEdit = isToolCallEventType("write", event) || isEditOnly;
819
+ const isEditOnly = mutation?.kind === "edit";
820
+ const isWriteOrEdit = mutation !== undefined;
703
821
  // Track any Write so recordWritten can inject a synthetic read afterward.
704
822
  // The agent authored the content (new or overwritten), so it trivially "knows" the file.
705
823
  if (!isEditOnly && isWriteOrEdit && filePath && !getFlag("no-read-guard")) {
@@ -912,7 +1030,7 @@ async function handleToolCallImpl(deps) {
912
1030
  const isExistingFile = typeof readGuard?.isNewFile !== "function" ||
913
1031
  !readGuard.isNewFile(filePath);
914
1032
  if (readGuard && isExistingFile && !isExternalOrVendor) {
915
- const { touchedLines, editRanges, preflightError, partiallyApplicable, contentMatchValidated, editBatchSummary, } = getTouchedLinesForGuard(event, filePath, runtime.telemetrySessionId, readGuardCorrelationId);
1033
+ const { touchedLines, editRanges, preflightError, preflightDetails, alreadyAppliedEdits, partiallyApplicable, contentMatchValidated, editBatchSummary, } = getTouchedLinesForGuard(event, filePath, runtime.telemetrySessionId, readGuardCorrelationId, runtime.partialApplyRecords);
916
1034
  if (preflightError) {
917
1035
  if (partiallyApplicable && partiallyApplicable.length > 0) {
918
1036
  try {
@@ -921,6 +1039,7 @@ async function handleToolCallImpl(deps) {
921
1039
  edits: partiallyApplicable,
922
1040
  summary: editBatchSummary,
923
1041
  correlationId: readGuardCorrelationId,
1042
+ recordStore: runtime.partialApplyRecords,
924
1043
  afterWrite: async () => {
925
1044
  const { biomeClient, ruffClient, metricsClient, agentBehaviorClient, } = await loadBootstrapClients();
926
1045
  const result = await handleToolResult({
@@ -962,10 +1081,32 @@ async function handleToolCallImpl(deps) {
962
1081
  .join("\n\n");
963
1082
  },
964
1083
  });
1084
+ if (partial.rejected) {
1085
+ // Nothing was written and no post-edit dispatch ran. The
1086
+ // preflight verdict still describes the whole batch; append
1087
+ // the structured rejection so the agent rebuilds from a
1088
+ // fresh read instead of retrying the stale payload.
1089
+ if (!editBatchSummary)
1090
+ logBlockedEditSummary("preflight");
1091
+ return {
1092
+ block: true,
1093
+ reason: `${preflightError}\n\nšŸ›‘ Batch not applied: ${partial.rejected.detail}`,
1094
+ };
1095
+ }
965
1096
  if (partial.postEditStatus === "failed") {
1097
+ // The commit stands; the post-edit analysis does not. The
1098
+ // committed bytes must never be re-labelled by the preflight
1099
+ // header (a RETRYABLE/RE-READ line here sends the agent into
1100
+ // the #2402 retry loop against already-applied edits).
966
1101
  return {
967
1102
  block: true,
968
- reason: `${preflightError}\n\nPartial apply pipeline failed after ${partial.appliedCount} edit${partial.appliedCount === 1 ? "" : "s"} committed.`,
1103
+ reason: composePartialApplyReason({
1104
+ appliedCount: partial.appliedCount,
1105
+ appliedIndices: partial.appliedIndices,
1106
+ postEditStatus: "failed",
1107
+ preflightDetails,
1108
+ alreadyAppliedEdits,
1109
+ }),
969
1110
  };
970
1111
  }
971
1112
  if (partial.appliedCount > 0) {
@@ -977,23 +1118,25 @@ async function handleToolCallImpl(deps) {
977
1118
  appliedCount: partial.appliedCount,
978
1119
  appliedTotal: partial.appliedTotal,
979
1120
  appliedIndices: partial.appliedIndices,
980
- skippedCount: partial.skippedCount ?? 0,
981
- skippedTotal: partial.skippedTotal ?? 0,
982
- skippedIndices: partial.skippedIndices ?? "",
983
- indexesTruncated: partial.indexesTruncated ?? false,
984
1121
  editBatchSummary: partial.summary,
985
1122
  routedThroughPostEditPipeline: true,
986
1123
  },
987
1124
  });
988
- let reason = preflightError.replace("šŸ”„ RETRYABLE — Edit target not found", `āš ļø PARTIAL APPLY — ${partial.appliedCount} edit${partial.appliedCount !== 1 ? "s" : ""} applied (${partial.appliedIndices})`);
989
- if (partial.postEditOutput) {
990
- reason += `\n\nPost-apply analysis:\n${partial.postEditOutput}`;
991
- }
992
- return { block: true, reason };
1125
+ return {
1126
+ block: true,
1127
+ reason: composePartialApplyReason({
1128
+ appliedCount: partial.appliedCount,
1129
+ appliedIndices: partial.appliedIndices,
1130
+ postEditStatus: "succeeded",
1131
+ postEditOutput: partial.postEditOutput,
1132
+ preflightDetails,
1133
+ alreadyAppliedEdits,
1134
+ }),
1135
+ };
993
1136
  }
994
1137
  }
995
1138
  catch {
996
- // fall through to full block
1139
+ // commit write failure — fall through to the full preflight block
997
1140
  }
998
1141
  }
999
1142
  if (!editBatchSummary)
@@ -1005,7 +1148,7 @@ async function handleToolCallImpl(deps) {
1005
1148
  sessionId: runtime.telemetrySessionId,
1006
1149
  filePath,
1007
1150
  metadata: {
1008
- tool: isToolCallEventType("write", event) ? "write" : "edit",
1151
+ tool: mutation?.kind ?? "edit",
1009
1152
  touchedLines: touchedLines ?? null,
1010
1153
  isExistingFile,
1011
1154
  },