@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
@@ -190,6 +190,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
190
190
  changed: [],
191
191
  failed: [],
192
192
  skipped: [],
193
+ unavailable: [],
193
194
  };
194
195
  // #502 fix provenance: per-path {tool, kind} entries accumulated across the
195
196
  // deferred-format loop below, passed as `fixes` on the batch
@@ -348,7 +349,8 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
348
349
  return !disabled;
349
350
  });
350
351
  if (formatRecords.length > 0) {
351
- const work = new Array(formatRecords.length);
352
+ const work = [];
353
+ work.length = formatRecords.length;
352
354
  const started = new Set();
353
355
  let nextIndex = 0;
354
356
  const worker = async () => {
@@ -430,6 +432,18 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
430
432
  },
431
433
  ], "format-failed");
432
434
  }
435
+ // #2413: an unavailable formatter is durable, not transient — record it
436
+ // once and DO NOT requeue. Requeuing here is exactly what made
437
+ // `spawn oxfmt ENOENT` re-fire on every agent_end for the same files.
438
+ if (result.formatUnavailable.length > 0) {
439
+ for (const u of result.formatUnavailable) {
440
+ summary.unavailable.push({
441
+ filePath,
442
+ formatter: u.formatter,
443
+ reason: u.reason,
444
+ });
445
+ }
446
+ }
433
447
  if (result.formatChanged) {
434
448
  summary.changed.push(filePath);
435
449
  for (const tool of result.formattersUsed) {
@@ -663,6 +677,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
663
677
  changed: summary.changed.length,
664
678
  failed: summary.failed.length,
665
679
  skipped: summary.skipped.length,
680
+ unavailable: summary.unavailable.length,
666
681
  },
667
682
  });
668
683
  logLatency({
@@ -676,9 +691,10 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
676
691
  changed: summary.changed.length,
677
692
  failed: summary.failed.length,
678
693
  skipped: summary.skipped.length,
694
+ unavailable: summary.unavailable.length,
679
695
  },
680
696
  });
681
- dbg(`agent_end deferred_format complete: formatted=${summary.formatted} changed=${summary.changed.length} failed=${summary.failed.length} skipped=${summary.skipped.length}`);
697
+ dbg(`agent_end deferred_format complete: formatted=${summary.formatted} changed=${summary.changed.length} failed=${summary.failed.length} skipped=${summary.skipped.length} unavailable=${summary.unavailable.length}`);
682
698
  if (summary.failed.length > 0) {
683
699
  notify(`pi-lens deferred format: ${summary.changed.length} changed, ${summary.failed.length} failed`, "warning");
684
700
  }
@@ -103,12 +103,58 @@ export function peekTestFindings(cacheManager, cwd, runtime, logDelivery = false
103
103
  {
104
104
  role: "user",
105
105
  content: current
106
- ? `${AUTOMATION_FRAMING}Test failures detected last turn — fix before continuing:\n\n${findings.data.content}`
106
+ ? `${AUTOMATION_FRAMING}${testFindingsCurrentPrefix(findings.data.runnerErrorOnly)}\n\n${findings.data.content}`
107
107
  : `${AUTOMATION_FRAMING}${historicalTestContent(findings.data.content, findings.data.provenance)}`,
108
108
  },
109
109
  ],
110
110
  };
111
111
  }
112
+ /**
113
+ * #2522: a batch made entirely of RUNNER errors (timeout, missing
114
+ * provider/binary — see `TestRunnerFindingsCache.runnerErrorOnly`) is not a
115
+ * failure the agent introduced, so it must not read as a blocker the way a
116
+ * genuine failing test does.
117
+ */
118
+ function testFindingsCurrentPrefix(runnerErrorOnly) {
119
+ return runnerErrorOnly
120
+ ? "Test runner could not complete last turn (advisory — not a failure introduced this turn):"
121
+ : "Test failures detected last turn — fix before continuing:";
122
+ }
123
+ /**
124
+ * Retire a delivered test-findings record: blank the content, keep everything a
125
+ * delivery does not settle.
126
+ *
127
+ * ONE function, called by both `consumeTestFindings` (the in-process context
128
+ * hook) and `acknowledgeTestFindings` (the MCP Stop-hook commit), because
129
+ * "what survives a retire" is exactly the kind of rule that rots when it is
130
+ * stated twice. It already had: round 2 taught the consume copy to preserve
131
+ * `deferredTargets` and left the acknowledge copy dropping them, and the
132
+ * acknowledge copy is the LIVE Stop-hook path — including the branch where
133
+ * `handleTurnEnd` never runs at all — so on that path the deferral set was
134
+ * wiped before anything could ever dispatch it (#2522 review round 3, F2).
135
+ *
136
+ * What survives, and why:
137
+ * - `testRunGeneration` — nulling the slot would let a still-in-flight OLDER
138
+ * batch read `undefined`, pass the strictly-greater suppression check, and
139
+ * resurrect a consumed one-shot advisory with stale results.
140
+ * - `deferredTargets` — delivering the advisory says the agent has SEEN the
141
+ * deferral, not that those targets ran. Dropping the list silently un-defers
142
+ * them and the cut batch is never finished.
143
+ * - `retiredTargets` — the session-scoped deferral cap. Dropping it re-arms a
144
+ * suite already measured as too slow for the batch budget, which puts the
145
+ * livelock back.
146
+ *
147
+ * An empty-content record peeks as undelivered while keeping all three intact.
148
+ */
149
+ function retireTestFindings(cacheManager, cwd) {
150
+ const prior = cacheManager.readCache("test-runner-findings", cwd)?.data;
151
+ cacheManager.writeCache("test-runner-findings", {
152
+ content: "",
153
+ testRunGeneration: prior?.testRunGeneration,
154
+ deferredTargets: prior?.deferredTargets,
155
+ retiredTargets: prior?.retiredTargets,
156
+ }, cwd);
157
+ }
112
158
  export function consumeTestFindings(cacheManager, cwd, runtime) {
113
159
  const record = cacheManager.readCache("test-runner-findings", cwd);
114
160
  if (!record?.data?.content)
@@ -116,16 +162,7 @@ export function consumeTestFindings(cacheManager, cwd, runtime) {
116
162
  const findings = peekTestFindings(cacheManager, cwd, runtime, true);
117
163
  if (!findings)
118
164
  return;
119
- // Retire the content but PRESERVE the generation high-water mark: nulling
120
- // the whole slot would let a still-in-flight OLDER batch see `undefined`,
121
- // pass the strictly-greater suppression check, and resurrect a consumed
122
- // one-shot advisory with stale results. An empty-content record peeks as
123
- // undelivered while keeping late-generation ordering intact.
124
- const priorGeneration = cacheManager.readCache("test-runner-findings", cwd)?.data?.testRunGeneration;
125
- cacheManager.writeCache("test-runner-findings", {
126
- content: "",
127
- testRunGeneration: priorGeneration,
128
- }, cwd);
165
+ retireTestFindings(cacheManager, cwd);
129
166
  return findings;
130
167
  }
131
168
  /** Complete an acknowledged MCP delivery without re-validating or re-rendering it. */
@@ -145,11 +182,7 @@ export function acknowledgeTestFindings(cacheManager, cwd) {
145
182
  const findings = cacheManager.readCache("test-runner-findings", cwd);
146
183
  if (!findings?.data?.content)
147
184
  return;
148
- // Same high-water-mark preservation as consumeTestFindings.
149
- cacheManager.writeCache("test-runner-findings", {
150
- content: "",
151
- testRunGeneration: findings.data.testRunGeneration,
152
- }, cwd);
185
+ retireTestFindings(cacheManager, cwd);
153
186
  }
154
187
  export function consumeSessionStartGuidance(cacheManager, cwd) {
155
188
  const guidance = cacheManager.readCache("session-start-guidance", cwd);
@@ -6,6 +6,7 @@ import { appendProjectChange, } from "./project-changes.js";
6
6
  import { normalizeMapKey, pathsEqual } from "./path-utils.js";
7
7
  import { PathKeyedMap } from "./path-keyed-map.js";
8
8
  import { BoundedLruCache } from "./bounded-cache.js";
9
+ import { PartialApplyRecordStore } from "./partial-edit-apply.js";
9
10
  import { ReadGuard } from "./read-guard.js";
10
11
  import { RUNTIME_CONFIG } from "./runtime-config.js";
11
12
  import { TurnSummaryCollector } from "./turn-summary.js";
@@ -111,6 +112,11 @@ export class RuntimeCoordinator {
111
112
  // (cheap, empty Map) but callers gate recording behind the
112
113
  // `lens-turn-summary` flag so it's a true no-op when the feature is off.
113
114
  _turnSummary = new TurnSummaryCollector();
115
+ // #2402/#1053: session-scoped applied-edit records for exact-retry
116
+ // recognition. Both producers (partial-apply commit, full native-edit
117
+ // success) write here; the preflight consults it before declaring an
118
+ // oldText miss, so an identical retry never re-executes a committed write.
119
+ partialApplyRecords = new PartialApplyRecordStore();
114
120
  resetForSession(startedAt = Date.now()) {
115
121
  this._sessionGeneration += 1;
116
122
  this._sessionStartedAt = startedAt;
@@ -159,6 +165,9 @@ export class RuntimeCoordinator {
159
165
  this._actionableWarningsThisTurn.clear();
160
166
  this._codeQualityWarningsThisTurn.clear();
161
167
  this._turnSummary.clear();
168
+ // #2402: an applied-edit record is a fact about the session that applied
169
+ // it; a new session must re-resolve identical payloads from content.
170
+ this.partialApplyRecords.clear();
162
171
  }
163
172
  get sessionStartedAt() {
164
173
  return this._sessionStartedAt;
@@ -317,9 +326,15 @@ export class RuntimeCoordinator {
317
326
  get droppedMutationReceiptCount() {
318
327
  return this._droppedMutationReceipts;
319
328
  }
320
- /** Atomically records write/edit ordering before debounce can coalesce it. */
321
- recordMutationToolReceipt(filePath, toolName) {
322
- if (toolName === "write") {
329
+ /**
330
+ * Atomically records write/edit ordering before debounce can coalesce it.
331
+ *
332
+ * Takes the classified {@link MutationKind}, not a raw tool name (#2423):
333
+ * an edit-shaped tool pi-lens does not name still demotes this file to the
334
+ * deferred pass, which is the safe timing.
335
+ */
336
+ recordMutationToolReceipt(filePath, kind) {
337
+ if (kind === "write") {
323
338
  this._writtenThisTurn.set(filePath, true);
324
339
  }
325
340
  else if (this._writtenThisTurn.has(filePath)) {
@@ -329,7 +344,7 @@ export class RuntimeCoordinator {
329
344
  this._fixedThisTurn.delete(filePath);
330
345
  }
331
346
  return {
332
- autofixMode: toolName === "edit" || this._autofixDemotedThisTurn.has(filePath)
347
+ autofixMode: kind === "edit" || this._autofixDemotedThisTurn.has(filePath)
333
348
  ? "deferred"
334
349
  : "immediate",
335
350
  };
@@ -999,7 +1014,9 @@ export class RuntimeCoordinator {
999
1014
  * for a same-kind re-touch. Callers publish each kind's first transition
1000
1015
  * without spamming repeated edits before `agent_end`.
1001
1016
  */
1002
- deferMutation(filePath, cwd, toolName, turnStateCwd, kind, ownerSessionId, originCwd) {
1017
+ deferMutation(filePath, cwd,
1018
+ /** Host tool name; any mutating tool, not just `write`/`edit` (#2423). */
1019
+ toolName, turnStateCwd, kind, ownerSessionId, originCwd) {
1003
1020
  const key = path.resolve(filePath);
1004
1021
  const now = Date.now();
1005
1022
  const resolvedOriginCwd = originCwd ?? turnStateCwd;
@@ -1030,7 +1047,9 @@ export class RuntimeCoordinator {
1030
1047
  });
1031
1048
  return true;
1032
1049
  }
1033
- deferFormat(filePath, cwd, toolName, turnStateCwd, ownerSessionId, originCwd) {
1050
+ deferFormat(filePath, cwd,
1051
+ /** Host tool name; any mutating tool, not just `write`/`edit` (#2423). */
1052
+ toolName, turnStateCwd, ownerSessionId, originCwd) {
1034
1053
  return this.deferMutation(filePath, cwd, toolName, turnStateCwd, "format", ownerSessionId, originCwd);
1035
1054
  }
1036
1055
  get pendingDeferredFormatCount() {
@@ -16,6 +16,7 @@ import { resetPendingRunnerFindings } from "./dispatch/pending-runner-findings.j
16
16
  import { clearAllSessions as clearFileTimeSessions } from "./file-time.js";
17
17
  import { getGlobalPiLensDir, getKnipIgnorePatterns, getProjectDataDir, } from "./file-utils.js";
18
18
  import { GitleaksClient } from "./gitleaks-client.js";
19
+ import { resetGoAvailability } from "./go-client.js";
19
20
  import { GovulncheckClient, } from "./govulncheck-client.js";
20
21
  import { sweepAtomicWriteStages } from "./instance-reaper.js";
21
22
  import { canRunStartupHeavyScans } from "./language-policy.js";
@@ -36,7 +37,9 @@ import { isPrintMode } from "./print-mode.js";
36
37
  import { readLatestProjectSequence, readLatestProjectSequenceAsync, } from "./project-changes.js";
37
38
  import { getProjectSnapshotPath, getProjectSnapshotLegacyPath, hydrateRuntimeFromProjectSnapshot, hydrateRuntimeFromProjectSnapshotIfIdle, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, loadProjectSnapshotExportsAndRules, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
38
39
  import { scanProjectRules } from "./rules-scanner.js";
40
+ import { resetRustAvailability } from "./rust-client.js";
39
41
  import { resetSafeSpawnWindowsCommandCache } from "./safe-spawn.js";
42
+ import { resetAnalyzerBootstrapSessionState, } from "./bootstrap.js";
40
43
  import { getSlowFsVerdict, isSlowFs, slowFsDegradationNotice, } from "./slow-fs.js";
41
44
  import { countRecentSmells, formatSmellsSessionStartLine, resetSmellsSessionState, } from "./smells-rollup.js";
42
45
  import { findNearestProjectRoot, getStartupScanMaxEntries, isStartupScanVerdictFresh, resolveStartupScanContext, } from "./startup-scan.js";
@@ -46,10 +49,29 @@ import { isWarmAttached } from "./warm-attach.js";
46
49
  import { setSessionLanguages } from "./widget-state.js";
47
50
  import { logWordIndex } from "./word-index-logger.js";
48
51
  import { resetOpaqueMutationState } from "./opaque-mutation-scan.js";
52
+ import { primePersistedMutationAttribution, resetMutationAttribution, } from "./mutation-attribution.js";
53
+ import { resetObservedMutationNet } from "./observed-mutation.js";
49
54
  import { resetPendingAuxiliaryCoverage } from "./lsp/pending-aux-coverage.js";
50
55
  import { resetWorkspaceTopology } from "./workspace-topology.js";
51
56
  import { resetZizmorTokenAvailability } from "./zizmor-config.js";
52
57
  import { resetSpawnTimeoutCooldowns } from "./spawn-timeout-cooldown.js";
58
+ import { resetTestRunnerDelivery } from "./test-runner-delivery.js";
59
+ import { resetLspMutationNoBridgeDbgLatch } from "./lsp-mutation.js";
60
+ /**
61
+ * `deps` with resolved analyzer clients merged in, or `null` when the
62
+ * bootstrap could not be served and the caller must proceed without them.
63
+ *
64
+ * No cast and no "is one representative field present?" probe: the seam
65
+ * answers with all seventeen clients or with `null`, so the two outcomes are
66
+ * the two branches. A skipped consumer is already counted in the ledger under
67
+ * `analyzer-bootstrap-unavailable`, so it is never mistaken for a clean one.
68
+ */
69
+ async function demandBootstrapDeps(deps, reason) {
70
+ const clients = await deps.bootstrap.request(reason);
71
+ if (!clients)
72
+ return null;
73
+ return { ...deps, ...clients };
74
+ }
53
75
  const HOST_STALL_THRESHOLD_MS = 30_000;
54
76
  function logHostReadyDelay(deps, cwd) {
55
77
  if (!deps.emitHostReadyDelay ||
@@ -772,6 +794,24 @@ async function buildOrRefreshWordIndex(args) {
772
794
  // Each consumer already handles the "not ready yet" case gracefully
773
795
  // (cachedExports.size > 0, cache miss paths).
774
796
  function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg) {
797
+ // #2467: the analyzers these scans drive are loaded HERE, on the deferred
798
+ // background path, instead of before the handler ran. This function was
799
+ // already fire-and-forget ("don't block session start"), so resolving them
800
+ // across one await adds no wait to the interactive path and changes no
801
+ // ordering its caller depends on — the caller never awaited it.
802
+ void (async () => {
803
+ const resolved = await demandBootstrapDeps(deps, "session-start-scans");
804
+ // Fail open: no analyzers means no scans, said out loud. The demand is
805
+ // already counted in the ledger, so this is not a silent skip.
806
+ if (!resolved) {
807
+ dbg("session_start scans: analyzer bootstrap unavailable — skipped");
808
+ return;
809
+ }
810
+ scheduleStartupScansWithClients(resolved, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg);
811
+ })();
812
+ }
813
+ /** The scan bodies, once the analyzers they need are resolved. */
814
+ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg) {
775
815
  const { todoScanner, cacheManager, knipClient, jscpdClient, deadCodeClients, govulncheckClient, gitleaksClient, trivyClient, opengrepClient, astGrepClient, depChecker, } = deps;
776
816
  // Some background scans are CPU-heavy and arrive on the event loop
777
817
  // just as the user is most likely typing (right after /new). Defer
@@ -1246,6 +1286,20 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
1246
1286
  });
1247
1287
  }
1248
1288
  function scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, startupScansWillRun, dbg) {
1289
+ // #2467: same deferral as `scheduleStartupScans` — the probes were already
1290
+ // fire-and-forget, so the analyzers they probe load here rather than before
1291
+ // the handler.
1292
+ void (async () => {
1293
+ const resolved = await demandBootstrapDeps(deps, "session-start-tool-probes");
1294
+ if (!resolved) {
1295
+ dbg("session_start tools: analyzer bootstrap unavailable — no probes");
1296
+ return;
1297
+ }
1298
+ scheduleDeferredToolProbesWithClients(resolved, languageProfile, startupDefaults, startupScansWillRun, dbg);
1299
+ })();
1300
+ }
1301
+ /** The probe bodies, once the analyzers they probe are resolved. */
1302
+ function scheduleDeferredToolProbesWithClients(deps, languageProfile, startupDefaults, startupScansWillRun, dbg) {
1249
1303
  const { biomeClient, ruffClient, depChecker } = deps;
1250
1304
  const defaultTools = new Set(startupDefaults);
1251
1305
  const probes = [];
@@ -1299,6 +1353,20 @@ export const SESSION_START_GUIDANCE = [
1299
1353
  ];
1300
1354
  export async function handleSessionStart(deps) {
1301
1355
  resetDegradationLedger();
1356
+ // #2467: re-arm the analyzer bootstrap's shutdown gate. The gate is a
1357
+ // per-SESSION claim ("this session is over") held in process-lived storage,
1358
+ // so without this a replacement session in the same process would find
1359
+ // every analyzer refused for the rest of the process — AGENTS.md defect
1360
+ // shape 17. The resident clients themselves are deliberately kept.
1361
+ resetAnalyzerBootstrapSessionState();
1362
+ resetTestRunnerDelivery();
1363
+ // #2450 fix round 3, catalog shape 17: the "bridge unavailable" dbg latch
1364
+ // (`clients/lsp-mutation.ts`) is a process-lifetime once-per-session flag,
1365
+ // same shape as the ledger's own once-per-subject bookkeeping above, but
1366
+ // kept as its own reset (not folded into `resetDegradationLedger`) to
1367
+ // avoid that module reaching back into this one — see the latch's own
1368
+ // comment for why.
1369
+ resetLspMutationNoBridgeDbgLatch();
1302
1370
  // #1743: the bounded-telemetry per-turn counters. The rising-edge state is
1303
1371
  // NOT here — it is the ledger's own tally, reset on the line above. These
1304
1372
  // counters are keyed by turn index, and a new session restarts turn
@@ -1309,23 +1377,16 @@ export async function handleSessionStart(deps) {
1309
1377
  // live anchor into one bounded previous slot so the queued event keeps the
1310
1378
  // replaced session's attribution until a newer live message_end is seen.
1311
1379
  rotateMessageEndAttribution();
1380
+ // #2526: the once-per-session `config_resolved` claim is NOT re-armed here.
1381
+ // index.ts resolves this session's config in `ensureLSPConfigInitialized`
1382
+ // BEFORE it calls this handler, so a re-arm on this line would fire between
1383
+ // the session's own two resolutions and the deferred `loadLSPConfig` below
1384
+ // would write a second row for one session (review round 2, F1). The re-arm
1385
+ // lives in index.ts's `session_start` closure, ahead of that ensure and
1386
+ // behind the #473 gate — see `resetOncePerSessionPhases`'s doc comment.
1312
1387
  const handlerEnteredAt = Date.now();
1313
1388
  const sessionStartMs = deps.sessionStartFiredAt ?? handlerEnteredAt;
1314
1389
  const cwdForTelemetry = deps.ctxCwd ?? process.cwd();
1315
- if (deps.bootstrapClientsStartedAt !== undefined &&
1316
- deps.bootstrapClientsDurationMs !== undefined) {
1317
- logLatency({
1318
- type: "phase",
1319
- filePath: cwdForTelemetry,
1320
- phase: "bootstrap_clients_load",
1321
- startedAt: new Date(deps.bootstrapClientsStartedAt).toISOString(),
1322
- durationMs: deps.bootstrapClientsDurationMs,
1323
- metadata: {
1324
- parent: "session_start_prehandler",
1325
- reason: deps.sessionReason,
1326
- },
1327
- });
1328
- }
1329
1390
  if (deps.sessionStartFiredAt !== undefined) {
1330
1391
  logLatency({
1331
1392
  type: "phase",
@@ -1605,7 +1666,7 @@ export async function handleSessionStart(deps) {
1605
1666
  }
1606
1667
  const allowBootstrapTasks = startupMode === "full";
1607
1668
  const quickMode = startupMode === "quick";
1608
- const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, knipClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
1669
+ const { ctxCwd, getFlag, notify, dbg, log, runtime, cacheManager, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
1609
1670
  // Lightweight phase timer — resets after each call so each log line shows
1610
1671
  // the cost of that phase alone, not cumulative time from session start.
1611
1672
  let _phaseT = Date.now();
@@ -1613,7 +1674,11 @@ export async function handleSessionStart(deps) {
1613
1674
  dbg(`session_start phase ${name}: ${Date.now() - _phaseT}ms`);
1614
1675
  _phaseT = Date.now();
1615
1676
  };
1616
- metricsClient.reset();
1677
+ // #2467: `peek`, never a load. A metrics client that was never constructed
1678
+ // holds no per-session state to re-arm, so the reset is vacuous — and
1679
+ // loading the analyzer graph in order to reset nothing is the interactive-
1680
+ // path cost this issue removes.
1681
+ deps.bootstrap.peek()?.metricsClient.reset();
1617
1682
  getDiagnosticTracker().reset();
1618
1683
  clearFileTimeSessions();
1619
1684
  runtime.complexityBaselines.clear();
@@ -1626,6 +1691,14 @@ export async function handleSessionStart(deps) {
1626
1691
  // after reset) and the git-worktree memo must re-probe after a session
1627
1692
  // that may have seen a non-git dir become one.
1628
1693
  resetOpaqueMutationState();
1694
+ // #2430: the observational net's pending baselines are keyed by tool-call
1695
+ // id and its content ledger describes the previous session's files; both
1696
+ // mis-answer forever without this. The learned attribution map is cleared
1697
+ // and then RE-PRIMED from this project's persisted file, so a tool an
1698
+ // earlier session observed is classified by name with no snapshot at all.
1699
+ resetObservedMutationNet();
1700
+ resetMutationAttribution();
1701
+ primePersistedMutationAttribution(ctxCwd);
1629
1702
  // #2026: pending auxiliary baselines are unreachable after generation bump.
1630
1703
  resetPendingAuxiliaryCoverage();
1631
1704
  // #817/#1199: Windows command resolution is cached per (command, canonical
@@ -1665,6 +1738,18 @@ export async function handleSessionStart(deps) {
1665
1738
  // login` and starts a fresh session still reads the previous session's
1666
1739
  // stale "no token" verdict until the cooldown (if any) happens to expire.
1667
1740
  resetZizmorTokenAvailability();
1741
+ // #2455: same #1496/#1535 process-lifetime-latch shape, one caller later —
1742
+ // the `goClient`/`rustClient` singletons each hold their own
1743
+ // `createAvailabilityLatch()` outside the dispatch generation counter above
1744
+ // (they predate `createCwdCachedProbe`). A "missing" verdict never expires
1745
+ // on its own, so without these a go/cargo install between sessions stayed
1746
+ // unobserved for the rest of the process's life. Found by hand while
1747
+ // auditing #2455's detector widening, NOT surfaced by it: the sweep skips
1748
+ // any file exporting no reset at all, and neither client module exported
1749
+ // one, so no container predicate could have yielded them (#2455 fix round 4,
1750
+ // F5 — an earlier draft of this comment had the causality backwards).
1751
+ resetGoAvailability();
1752
+ resetRustAvailability();
1668
1753
  // psscriptanalyzer's three latches (interpreter, module, -File exec) are
1669
1754
  // module-local, so the generation counter above does not reach them
1670
1755
  // (#1490, #1540).
@@ -1712,7 +1797,9 @@ export async function handleSessionStart(deps) {
1712
1797
  // Some embedders inject a capability-shaped Knip client rather than the
1713
1798
  // concrete KnipClient. Session reset is an optional lifecycle capability;
1714
1799
  // its absence must not make session_start fail.
1715
- knipClient.resetSessionState?.();
1800
+ // #2467: `peek` for the same reason as `metricsClient.reset()` above —
1801
+ // an unloaded knip client has no session state to clear.
1802
+ deps.bootstrap.peek()?.knipClient.resetSessionState?.();
1716
1803
  // #1910: the tier-3 cascade outstanding-touch registry and its
1717
1804
  // sweep-scoped expired/evicted counters (clients/lsp/cascade-tier.ts) are
1718
1805
  // a per-SESSION claim about touches THIS session fired. #1899 bounded the
@@ -1769,6 +1856,12 @@ export async function handleSessionStart(deps) {
1769
1856
  }
1770
1857
  const hasWorkspaceCwd = typeof ctxCwd === "string" && ctxCwd.length > 0;
1771
1858
  const cwd = ctxCwd ?? process.cwd();
1859
+ // #2526 review round 3, S1: this handler no longer predicts whether config
1860
+ // will resolve. `loadLSPConfig` itself publishes a `config_resolution_pending`
1861
+ // mark, from inside the function, at the instant a resolution is actually
1862
+ // attempted — see that function's doc comment (`clients/lsp/config.ts`) for
1863
+ // why a prediction mirrored against this handler's own gates drifted from
1864
+ // what index.ts and this handler's callers actually schedule.
1772
1865
  // #1228: generic atomic-write stages are shared by several project stores,
1773
1866
  // so the review-graph-specific sweep cannot own this namespace. Sweep the
1774
1867
  // project data roots and machine-global registry root once per session start;
@@ -1938,7 +2031,18 @@ export async function handleSessionStart(deps) {
1938
2031
  filePath: cwd,
1939
2032
  startedAt: new Date(sessionStartMs).toISOString(),
1940
2033
  durationMs: totalDurationMs,
1941
- metadata: { mode: startupMode, reason: deps.sessionReason },
2034
+ metadata: {
2035
+ mode: startupMode,
2036
+ reason: deps.sessionReason,
2037
+ // #2129: the root-identity input decideSessionStart consulted,
2038
+ // alongside `mode` — every start reaching this line already
2039
+ // classified `primary`/`sequential-replacement` (a `secondary-root`
2040
+ // start returns before `handleSessionStart` is ever called).
2041
+ classification: deps.sessionStartClassification,
2042
+ // `undefined` is omitted by JSON.stringify. Keep unknown explicit so
2043
+ // strict log readers can distinguish it from legacy omission.
2044
+ sameRoot: deps.sessionStartSameRoot ?? "unknown",
2045
+ },
1942
2046
  });
1943
2047
  logHostReadyDelay(deps, cwd);
1944
2048
  emitSmellsSessionStartLine(dbg, sessionStartMs);
@@ -2180,13 +2284,19 @@ export async function handleSessionStart(deps) {
2180
2284
  else {
2181
2285
  dbg("session_start: skipping prettier preinstall probe (startup mode)");
2182
2286
  }
2183
- const detectedRunner = testRunnerClient.detectRunner(analysisRoot);
2287
+ // #2467: the first point on the FULL-mode path that genuinely needs the
2288
+ // analyzer clients, so it is where the load is paid. Quick mode — the
2289
+ // process's first session, the one the user is waiting on — returns above
2290
+ // and never reaches here. Fail open: an unavailable bootstrap drops these
2291
+ // three entries from the "Active tools" line rather than failing the start.
2292
+ const summaryClients = await deps.bootstrap.request("session-start-tools");
2293
+ const detectedRunner = summaryClients?.testRunnerClient.detectRunner(analysisRoot);
2184
2294
  phase("test-runner-detect");
2185
2295
  if (detectedRunner)
2186
2296
  tools.push(`Test runner (${detectedRunner.runner})`);
2187
- if (await goClient.isGoAvailableAsync())
2297
+ if (await summaryClients?.goClient.isGoAvailableAsync())
2188
2298
  tools.push("Go (go vet)");
2189
- if (await rustClient.isAvailableAsync())
2299
+ if (await summaryClients?.rustClient.isAvailableAsync())
2190
2300
  tools.push("Rust (cargo)");
2191
2301
  log(`Active tools: ${tools.join(", ")}`);
2192
2302
  dbg(`session_start tools: ${tools.join(", ")}`);
@@ -2282,7 +2392,14 @@ export async function handleSessionStart(deps) {
2282
2392
  filePath: cwd,
2283
2393
  startedAt: new Date(sessionStartMs).toISOString(),
2284
2394
  durationMs: totalDurationMs,
2285
- metadata: { mode: startupMode, reason: deps.sessionReason },
2395
+ metadata: {
2396
+ mode: startupMode,
2397
+ reason: deps.sessionReason,
2398
+ // #2129: see the quick-mode session_start_total record above.
2399
+ classification: deps.sessionStartClassification,
2400
+ // Keep the full path's durable shape identical to quick mode.
2401
+ sameRoot: deps.sessionStartSameRoot ?? "unknown",
2402
+ },
2286
2403
  });
2287
2404
  logHostReadyDelay(deps, cwd);
2288
2405
  emitSmellsSessionStartLine(dbg, sessionStartMs);