@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
@@ -5,7 +5,7 @@ import { rotateMessageEndAttribution } from "./message-end-attribution.js";
5
5
  import { createDeadline, yieldIfOverBudget } from "./cooperative-budget.js";
6
6
  import { deadCodeIssueCount } from "./dead-code-client.js";
7
7
  import { logDeadCodeScan } from "./dead-code-logger.js";
8
- import { incrementDegradationCount, resetDegradationLedger, } from "./degradation-ledger.js";
8
+ import { incrementDegradationCount, recordDegradationOnce, resetDegradationLedger, } from "./degradation-ledger.js";
9
9
  import { getDiagnosticTracker } from "./diagnostic-tracker.js";
10
10
  import { resetPsScriptAnalyzerAvailability } from "./dispatch/runners/psscriptanalyzer.js";
11
11
  import { resetInstallRetryLatches } from "./dispatch/runners/utils/availability-policy.js";
@@ -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 ||
@@ -234,11 +256,14 @@ function logProjectSnapshotProbe(args) {
234
256
  args.dbg(`project_snapshot: miss reason=${args.missReason}`);
235
257
  }
236
258
  }
237
- function resolveStartupMode() {
259
+ function resolveStartupMode(projectConfig, globalConfig) {
238
260
  const envMode = (process.env.PI_LENS_STARTUP_MODE ?? "").trim().toLowerCase();
239
261
  if (envMode === "full" || envMode === "minimal" || envMode === "quick") {
240
262
  return envMode;
241
263
  }
264
+ const configMode = projectConfig?.startup?.mode ?? globalConfig?.startup?.mode;
265
+ if (configMode)
266
+ return configMode;
242
267
  if (isPrintMode()) {
243
268
  return "quick";
244
269
  }
@@ -772,7 +797,34 @@ async function buildOrRefreshWordIndex(args) {
772
797
  // Each consumer already handles the "not ready yet" case gracefully
773
798
  // (cachedExports.size > 0, cache miss paths).
774
799
  function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg) {
800
+ // #2467: the analyzers these scans drive are loaded HERE, on the deferred
801
+ // background path, instead of before the handler ran. This function was
802
+ // already fire-and-forget ("don't block session start"), so resolving them
803
+ // across one await adds no wait to the interactive path and changes no
804
+ // ordering its caller depends on — the caller never awaited it.
805
+ void (async () => {
806
+ const resolved = await demandBootstrapDeps(deps, "session-start-scans");
807
+ // Fail open: no analyzers means no scans, said out loud. The demand is
808
+ // already counted in the ledger, so this is not a silent skip.
809
+ if (!resolved) {
810
+ dbg("session_start scans: analyzer bootstrap unavailable — skipped");
811
+ return;
812
+ }
813
+ scheduleStartupScansWithClients(resolved, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg);
814
+ })();
815
+ }
816
+ /** The scan bodies, once the analyzers they need are resolved. */
817
+ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg) {
775
818
  const { todoScanner, cacheManager, knipClient, jscpdClient, deadCodeClients, govulncheckClient, gitleaksClient, trivyClient, opengrepClient, astGrepClient, depChecker, } = deps;
819
+ const analyzerEnabled = (flag) => !deps.getFlag(flag);
820
+ if (!analyzerEnabled("no-complexity")) {
821
+ dbg("session_start complexity: skipped (disabled by config)");
822
+ recordDegradationOnce({
823
+ kind: "startup-analyzer-disabled",
824
+ subject: "complexity",
825
+ reason: "skipped (disabled by config)",
826
+ });
827
+ }
776
828
  // Some background scans are CPU-heavy and arrive on the event loop
777
829
  // just as the user is most likely typing (right after /new). Defer
778
830
  // those by a few seconds so the perceptible 50-100ms sync bursts they
@@ -829,7 +881,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
829
881
  scanNames.push("knip", "jscpd", "ast-grep exports", "project index");
830
882
  }
831
883
  dbg(`session_start: launching background scans (${scanNames.join(", ")})`);
832
- runTask("todo", async () => {
884
+ void runTask("todo", async () => {
833
885
  if (!runtime.isCurrentSession(sessionGeneration))
834
886
  return;
835
887
  // The original implementation called todoScanner.scanDirectory(), which
@@ -866,9 +918,19 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
866
918
  const isSubagent = isSubagentSession();
867
919
  const skipHeavyweightScans = isSlowFs(analysisRoot) || isSubagent;
868
920
  const runHeavyweightTask = (name, task) => {
921
+ const flag = `no-${name}`;
922
+ if (name !== "opengrep" && name !== "trivy" && !analyzerEnabled(flag)) {
923
+ dbg(`session_start ${name}: skipped (disabled by config)`);
924
+ recordDegradationOnce({
925
+ kind: "startup-analyzer-disabled",
926
+ subject: name,
927
+ reason: "skipped (disabled by config)",
928
+ });
929
+ return;
930
+ }
869
931
  if (skipHeavyweightScans)
870
932
  return;
871
- runTask(name, task);
933
+ void runTask(name, task);
872
934
  };
873
935
  if (skipHeavyweightScans) {
874
936
  dbg(`session_start: skipping knip/jscpd/madge/dead-code/govulncheck/gitleaks/trivy/opengrep (${isSubagent ? "subagent" : "slow-fs"})`);
@@ -1199,7 +1261,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
1199
1261
  // racing its independently deferred timer. Otherwise a slow graph build leaves
1200
1262
  // `runtime.callGraph` unset at this task's start and loses the model for the
1201
1263
  // entire session (#1070).
1202
- runTask("codebase-model", async () => {
1264
+ void runTask("codebase-model", async () => {
1203
1265
  await callGraphTask;
1204
1266
  if (!runtime.isCurrentSession(sessionGeneration))
1205
1267
  return;
@@ -1218,7 +1280,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
1218
1280
  `${model.totalTokens} tokens, top symbols: ${top3 || "(none)"}`);
1219
1281
  });
1220
1282
  // ast-grep — export scan for duplicate detection
1221
- runTask("ast-grep-exports", async () => {
1283
+ void runTask("ast-grep-exports", async () => {
1222
1284
  if (await astGrepClient.ensureAvailable()) {
1223
1285
  if (!runtime.isCurrentSession(sessionGeneration))
1224
1286
  return;
@@ -1235,7 +1297,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
1235
1297
  // word-index — identifier inverted index + BM25 for ranked symbol search
1236
1298
  // (#162). Load -> rebuild-if-stale -> persist lifecycle (#348), shared with
1237
1299
  // the quick-mode cold-start warmup pass below.
1238
- runTask("word-index", async () => {
1300
+ void runTask("word-index", async () => {
1239
1301
  await buildOrRefreshWordIndex({
1240
1302
  runtime,
1241
1303
  sessionGeneration,
@@ -1246,6 +1308,20 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
1246
1308
  });
1247
1309
  }
1248
1310
  function scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, startupScansWillRun, dbg) {
1311
+ // #2467: same deferral as `scheduleStartupScans` — the probes were already
1312
+ // fire-and-forget, so the analyzers they probe load here rather than before
1313
+ // the handler.
1314
+ void (async () => {
1315
+ const resolved = await demandBootstrapDeps(deps, "session-start-tool-probes");
1316
+ if (!resolved) {
1317
+ dbg("session_start tools: analyzer bootstrap unavailable — no probes");
1318
+ return;
1319
+ }
1320
+ scheduleDeferredToolProbesWithClients(resolved, languageProfile, startupDefaults, startupScansWillRun, dbg);
1321
+ })();
1322
+ }
1323
+ /** The probe bodies, once the analyzers they probe are resolved. */
1324
+ function scheduleDeferredToolProbesWithClients(deps, languageProfile, startupDefaults, startupScansWillRun, dbg) {
1249
1325
  const { biomeClient, ruffClient, depChecker } = deps;
1250
1326
  const defaultTools = new Set(startupDefaults);
1251
1327
  const probes = [];
@@ -1299,6 +1375,20 @@ export const SESSION_START_GUIDANCE = [
1299
1375
  ];
1300
1376
  export async function handleSessionStart(deps) {
1301
1377
  resetDegradationLedger();
1378
+ // #2467: re-arm the analyzer bootstrap's shutdown gate. The gate is a
1379
+ // per-SESSION claim ("this session is over") held in process-lived storage,
1380
+ // so without this a replacement session in the same process would find
1381
+ // every analyzer refused for the rest of the process — AGENTS.md defect
1382
+ // shape 17. The resident clients themselves are deliberately kept.
1383
+ resetAnalyzerBootstrapSessionState();
1384
+ resetTestRunnerDelivery();
1385
+ // #2450 fix round 3, catalog shape 17: the "bridge unavailable" dbg latch
1386
+ // (`clients/lsp-mutation.ts`) is a process-lifetime once-per-session flag,
1387
+ // same shape as the ledger's own once-per-subject bookkeeping above, but
1388
+ // kept as its own reset (not folded into `resetDegradationLedger`) to
1389
+ // avoid that module reaching back into this one — see the latch's own
1390
+ // comment for why.
1391
+ resetLspMutationNoBridgeDbgLatch();
1302
1392
  // #1743: the bounded-telemetry per-turn counters. The rising-edge state is
1303
1393
  // NOT here — it is the ledger's own tally, reset on the line above. These
1304
1394
  // counters are keyed by turn index, and a new session restarts turn
@@ -1309,23 +1399,16 @@ export async function handleSessionStart(deps) {
1309
1399
  // live anchor into one bounded previous slot so the queued event keeps the
1310
1400
  // replaced session's attribution until a newer live message_end is seen.
1311
1401
  rotateMessageEndAttribution();
1402
+ // #2526: the once-per-session `config_resolved` claim is NOT re-armed here.
1403
+ // index.ts resolves this session's config in `ensureLSPConfigInitialized`
1404
+ // BEFORE it calls this handler, so a re-arm on this line would fire between
1405
+ // the session's own two resolutions and the deferred `loadLSPConfig` below
1406
+ // would write a second row for one session (review round 2, F1). The re-arm
1407
+ // lives in index.ts's `session_start` closure, ahead of that ensure and
1408
+ // behind the #473 gate — see `resetOncePerSessionPhases`'s doc comment.
1312
1409
  const handlerEnteredAt = Date.now();
1313
1410
  const sessionStartMs = deps.sessionStartFiredAt ?? handlerEnteredAt;
1314
1411
  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
1412
  if (deps.sessionStartFiredAt !== undefined) {
1330
1413
  logLatency({
1331
1414
  type: "phase",
@@ -1362,7 +1445,7 @@ export async function handleSessionStart(deps) {
1362
1445
  // entirely — but only when PI_LENS_STARTUP_MODE is unset in the env
1363
1446
  // (an explicit env var still takes highest precedence).
1364
1447
  // Tunable: PI_LENS_WARMUP_DELAY_MS adjusts the warmup delay.
1365
- let startupMode = resolveStartupMode();
1448
+ let startupMode = resolveStartupMode(deps.projectConfig, deps.globalConfig);
1366
1449
  // SAFETY: these two flags are process-lifetime state pi-lens stashes on
1367
1450
  // `globalThis` so a second extension instance in the same process sees the
1368
1451
  // first one's warmup. There is no ambient declaration for them, and adding
@@ -1372,7 +1455,9 @@ export async function handleSessionStart(deps) {
1372
1455
  const isFirstSessionOfProcess = !processGlobals.__piLensFirstSessionDone;
1373
1456
  if (isFirstSessionOfProcess &&
1374
1457
  process.env.PI_LENS_COLD_START_QUICK !== "0" &&
1375
- !process.env.PI_LENS_STARTUP_MODE) {
1458
+ !process.env.PI_LENS_STARTUP_MODE &&
1459
+ !deps.projectConfig?.startup?.mode &&
1460
+ !deps.globalConfig?.startup?.mode) {
1376
1461
  // Apply host-provided override (e.g. MCP server forces "full") before
1377
1462
  // falling back to the TUI quick-mode heuristic.
1378
1463
  startupMode = deps.startupModeOverride ?? "quick";
@@ -1605,7 +1690,7 @@ export async function handleSessionStart(deps) {
1605
1690
  }
1606
1691
  const allowBootstrapTasks = startupMode === "full";
1607
1692
  const quickMode = startupMode === "quick";
1608
- const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, knipClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
1693
+ const { ctxCwd, getFlag, notify, dbg, log, runtime, cacheManager, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
1609
1694
  // Lightweight phase timer — resets after each call so each log line shows
1610
1695
  // the cost of that phase alone, not cumulative time from session start.
1611
1696
  let _phaseT = Date.now();
@@ -1613,7 +1698,11 @@ export async function handleSessionStart(deps) {
1613
1698
  dbg(`session_start phase ${name}: ${Date.now() - _phaseT}ms`);
1614
1699
  _phaseT = Date.now();
1615
1700
  };
1616
- metricsClient.reset();
1701
+ // #2467: `peek`, never a load. A metrics client that was never constructed
1702
+ // holds no per-session state to re-arm, so the reset is vacuous — and
1703
+ // loading the analyzer graph in order to reset nothing is the interactive-
1704
+ // path cost this issue removes.
1705
+ deps.bootstrap.peek()?.metricsClient.reset();
1617
1706
  getDiagnosticTracker().reset();
1618
1707
  clearFileTimeSessions();
1619
1708
  runtime.complexityBaselines.clear();
@@ -1626,6 +1715,14 @@ export async function handleSessionStart(deps) {
1626
1715
  // after reset) and the git-worktree memo must re-probe after a session
1627
1716
  // that may have seen a non-git dir become one.
1628
1717
  resetOpaqueMutationState();
1718
+ // #2430: the observational net's pending baselines are keyed by tool-call
1719
+ // id and its content ledger describes the previous session's files; both
1720
+ // mis-answer forever without this. The learned attribution map is cleared
1721
+ // and then RE-PRIMED from this project's persisted file, so a tool an
1722
+ // earlier session observed is classified by name with no snapshot at all.
1723
+ resetObservedMutationNet();
1724
+ resetMutationAttribution();
1725
+ primePersistedMutationAttribution(ctxCwd);
1629
1726
  // #2026: pending auxiliary baselines are unreachable after generation bump.
1630
1727
  resetPendingAuxiliaryCoverage();
1631
1728
  // #817/#1199: Windows command resolution is cached per (command, canonical
@@ -1665,6 +1762,18 @@ export async function handleSessionStart(deps) {
1665
1762
  // login` and starts a fresh session still reads the previous session's
1666
1763
  // stale "no token" verdict until the cooldown (if any) happens to expire.
1667
1764
  resetZizmorTokenAvailability();
1765
+ // #2455: same #1496/#1535 process-lifetime-latch shape, one caller later —
1766
+ // the `goClient`/`rustClient` singletons each hold their own
1767
+ // `createAvailabilityLatch()` outside the dispatch generation counter above
1768
+ // (they predate `createCwdCachedProbe`). A "missing" verdict never expires
1769
+ // on its own, so without these a go/cargo install between sessions stayed
1770
+ // unobserved for the rest of the process's life. Found by hand while
1771
+ // auditing #2455's detector widening, NOT surfaced by it: the sweep skips
1772
+ // any file exporting no reset at all, and neither client module exported
1773
+ // one, so no container predicate could have yielded them (#2455 fix round 4,
1774
+ // F5 — an earlier draft of this comment had the causality backwards).
1775
+ resetGoAvailability();
1776
+ resetRustAvailability();
1668
1777
  // psscriptanalyzer's three latches (interpreter, module, -File exec) are
1669
1778
  // module-local, so the generation counter above does not reach them
1670
1779
  // (#1490, #1540).
@@ -1712,7 +1821,9 @@ export async function handleSessionStart(deps) {
1712
1821
  // Some embedders inject a capability-shaped Knip client rather than the
1713
1822
  // concrete KnipClient. Session reset is an optional lifecycle capability;
1714
1823
  // its absence must not make session_start fail.
1715
- knipClient.resetSessionState?.();
1824
+ // #2467: `peek` for the same reason as `metricsClient.reset()` above —
1825
+ // an unloaded knip client has no session state to clear.
1826
+ deps.bootstrap.peek()?.knipClient.resetSessionState?.();
1716
1827
  // #1910: the tier-3 cascade outstanding-touch registry and its
1717
1828
  // sweep-scoped expired/evicted counters (clients/lsp/cascade-tier.ts) are
1718
1829
  // a per-SESSION claim about touches THIS session fired. #1899 bounded the
@@ -1769,6 +1880,12 @@ export async function handleSessionStart(deps) {
1769
1880
  }
1770
1881
  const hasWorkspaceCwd = typeof ctxCwd === "string" && ctxCwd.length > 0;
1771
1882
  const cwd = ctxCwd ?? process.cwd();
1883
+ // #2526 review round 3, S1: this handler no longer predicts whether config
1884
+ // will resolve. `loadLSPConfig` itself publishes a `config_resolution_pending`
1885
+ // mark, from inside the function, at the instant a resolution is actually
1886
+ // attempted — see that function's doc comment (`clients/lsp/config.ts`) for
1887
+ // why a prediction mirrored against this handler's own gates drifted from
1888
+ // what index.ts and this handler's callers actually schedule.
1772
1889
  // #1228: generic atomic-write stages are shared by several project stores,
1773
1890
  // so the review-graph-specific sweep cannot own this namespace. Sweep the
1774
1891
  // project data roots and machine-global registry root once per session start;
@@ -1938,7 +2055,18 @@ export async function handleSessionStart(deps) {
1938
2055
  filePath: cwd,
1939
2056
  startedAt: new Date(sessionStartMs).toISOString(),
1940
2057
  durationMs: totalDurationMs,
1941
- metadata: { mode: startupMode, reason: deps.sessionReason },
2058
+ metadata: {
2059
+ mode: startupMode,
2060
+ reason: deps.sessionReason,
2061
+ // #2129: the root-identity input decideSessionStart consulted,
2062
+ // alongside `mode` — every start reaching this line already
2063
+ // classified `primary`/`sequential-replacement` (a `secondary-root`
2064
+ // start returns before `handleSessionStart` is ever called).
2065
+ classification: deps.sessionStartClassification,
2066
+ // `undefined` is omitted by JSON.stringify. Keep unknown explicit so
2067
+ // strict log readers can distinguish it from legacy omission.
2068
+ sameRoot: deps.sessionStartSameRoot ?? "unknown",
2069
+ },
1942
2070
  });
1943
2071
  logHostReadyDelay(deps, cwd);
1944
2072
  emitSmellsSessionStartLine(dbg, sessionStartMs);
@@ -2167,7 +2295,10 @@ export async function handleSessionStart(deps) {
2167
2295
  else {
2168
2296
  dbg("session_start: no language defaults selected for pre-install");
2169
2297
  }
2170
- const startupScansWillRun = allowBootstrapTasks && startupScan.canWarmCaches;
2298
+ const startupScansEnabled = deps.projectConfig?.startup?.scans?.enabled ??
2299
+ deps.globalConfig?.startup?.scans?.enabled ??
2300
+ true;
2301
+ const startupScansWillRun = allowBootstrapTasks && startupScan.canWarmCaches && startupScansEnabled;
2171
2302
  const jstsHeavyScansWillRun = startupScansWillRun && canRunStartupHeavyScans(languageProfile, "jsts");
2172
2303
  if (allowBootstrapTasks) {
2173
2304
  scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, jstsHeavyScansWillRun, dbg);
@@ -2180,13 +2311,19 @@ export async function handleSessionStart(deps) {
2180
2311
  else {
2181
2312
  dbg("session_start: skipping prettier preinstall probe (startup mode)");
2182
2313
  }
2183
- const detectedRunner = testRunnerClient.detectRunner(analysisRoot);
2314
+ // #2467: the first point on the FULL-mode path that genuinely needs the
2315
+ // analyzer clients, so it is where the load is paid. Quick mode — the
2316
+ // process's first session, the one the user is waiting on — returns above
2317
+ // and never reaches here. Fail open: an unavailable bootstrap drops these
2318
+ // three entries from the "Active tools" line rather than failing the start.
2319
+ const summaryClients = await deps.bootstrap.request("session-start-tools");
2320
+ const detectedRunner = summaryClients?.testRunnerClient.detectRunner(analysisRoot);
2184
2321
  phase("test-runner-detect");
2185
2322
  if (detectedRunner)
2186
2323
  tools.push(`Test runner (${detectedRunner.runner})`);
2187
- if (await goClient.isGoAvailableAsync())
2324
+ if (await summaryClients?.goClient.isGoAvailableAsync())
2188
2325
  tools.push("Go (go vet)");
2189
- if (await rustClient.isAvailableAsync())
2326
+ if (await summaryClients?.rustClient.isAvailableAsync())
2190
2327
  tools.push("Rust (cargo)");
2191
2328
  log(`Active tools: ${tools.join(", ")}`);
2192
2329
  dbg(`session_start tools: ${tools.join(", ")}`);
@@ -2216,6 +2353,14 @@ export async function handleSessionStart(deps) {
2216
2353
  if (!allowBootstrapTasks) {
2217
2354
  dbg("session_start: skipping startup background scans (startup mode)");
2218
2355
  }
2356
+ else if (!startupScansEnabled) {
2357
+ dbg("session_start: skipping startup background scans (disabled by config)");
2358
+ recordDegradationOnce({
2359
+ kind: "startup-analyzer-disabled",
2360
+ subject: "startup-scans",
2361
+ reason: "skipped (disabled by config)",
2362
+ });
2363
+ }
2219
2364
  else if (!startupScan.canWarmCaches) {
2220
2365
  dbg(`session_start: skipping heavy scans (${startupScan.reason ?? "unknown"})`);
2221
2366
  dbg(`session_start: skipping TODO scan (${startupScan.reason ?? "unknown"})`);
@@ -2282,7 +2427,14 @@ export async function handleSessionStart(deps) {
2282
2427
  filePath: cwd,
2283
2428
  startedAt: new Date(sessionStartMs).toISOString(),
2284
2429
  durationMs: totalDurationMs,
2285
- metadata: { mode: startupMode, reason: deps.sessionReason },
2430
+ metadata: {
2431
+ mode: startupMode,
2432
+ reason: deps.sessionReason,
2433
+ // #2129: see the quick-mode session_start_total record above.
2434
+ classification: deps.sessionStartClassification,
2435
+ // Keep the full path's durable shape identical to quick mode.
2436
+ sameRoot: deps.sessionStartSameRoot ?? "unknown",
2437
+ },
2286
2438
  });
2287
2439
  logHostReadyDelay(deps, cwd);
2288
2440
  emitSmellsSessionStartLine(dbg, sessionStartMs);