@herbertgao/pi-extensions 2026.9.1 → 2026.9.3

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 (341) hide show
  1. package/README.md +3 -2
  2. package/THIRD_PARTY_NOTICES.md +24 -0
  3. package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
  4. package/node_modules/@herbertgao/sol-pi/README.md +159 -0
  5. package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
  6. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
  7. package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
  8. package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
  9. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
  10. package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
  11. package/node_modules/@herbertgao/sol-pi/package.json +76 -0
  12. package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
  13. package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
  14. package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
  15. package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
  16. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
  17. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
  18. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
  19. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
  20. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
  21. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
  22. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
  23. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
  24. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
  25. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
  26. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
  27. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
  28. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
  29. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
  30. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
  31. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
  32. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
  33. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
  34. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
  35. package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
  36. package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
  37. package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
  38. package/node_modules/@narumitw/pi-btw/README.md +57 -141
  39. package/node_modules/@narumitw/pi-btw/dist/index.ts +478 -43
  40. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
  41. package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
  42. package/node_modules/@narumitw/pi-btw/package.json +2 -1
  43. package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -3
  44. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
  45. package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
  46. package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
  47. package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
  48. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
  49. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
  50. package/node_modules/pi-lens/CHANGELOG.md +260 -0
  51. package/node_modules/pi-lens/README.md +13 -8
  52. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
  53. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
  54. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
  55. package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
  56. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
  57. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -8
  58. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
  59. package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
  60. package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
  61. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
  62. package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
  63. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
  64. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -5
  65. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
  66. package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -6
  67. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
  68. package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
  69. package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
  70. package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
  71. package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
  72. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
  73. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
  74. package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
  75. package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
  76. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +3 -1
  77. package/node_modules/pi-lens/dist/clients/config-resolve.js +10 -7
  78. package/node_modules/pi-lens/dist/clients/config-schema.js +56 -2
  79. package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
  80. package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
  81. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
  82. package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
  84. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
  85. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
  86. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -41
  87. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
  88. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
  89. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
  91. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
  93. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +7 -2
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +3 -2
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +3 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +15 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +3 -3
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +3 -2
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +5 -3
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
  144. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
  145. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
  146. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +5 -3
  147. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
  148. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
  149. package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
  150. package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
  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 -0
  153. package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
  154. package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
  155. package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
  157. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
  158. package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
  159. package/node_modules/pi-lens/dist/clients/formatters.js +66 -93
  160. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
  161. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
  162. package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
  163. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
  164. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
  165. package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
  166. package/node_modules/pi-lens/dist/clients/installer/index.js +416 -61
  167. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
  168. package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
  169. package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
  170. package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
  171. package/node_modules/pi-lens/dist/clients/language-profile.js +12 -11
  172. package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
  173. package/node_modules/pi-lens/dist/clients/latency-logger.js +7 -7
  174. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
  175. package/node_modules/pi-lens/dist/clients/lens-config.js +23 -0
  176. package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
  177. package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
  179. package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
  180. package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
  181. package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/config.js +37 -7
  183. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
  184. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +79 -1
  185. package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
  186. package/node_modules/pi-lens/dist/clients/lsp/index.js +491 -64
  187. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
  188. package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
  189. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  190. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
  191. package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
  192. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
  193. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
  194. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
  195. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
  196. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
  197. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
  198. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
  199. package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
  200. package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
  201. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
  202. package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
  204. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
  205. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
  206. package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
  207. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
  208. package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
  209. package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
  210. package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
  211. package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
  212. package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
  213. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +9 -4
  214. package/node_modules/pi-lens/dist/clients/pipeline.js +5 -4
  215. package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
  216. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
  217. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
  218. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
  219. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
  220. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
  221. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
  222. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
  223. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
  224. package/node_modules/pi-lens/dist/clients/project-lens-config.js +49 -1
  225. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
  226. package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
  227. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +3 -1
  228. package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
  229. package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
  230. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
  231. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
  232. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
  233. package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
  234. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +10 -1
  235. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
  236. package/node_modules/pi-lens/dist/clients/runtime-session.js +58 -14
  237. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
  238. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
  239. package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
  240. package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
  241. package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
  242. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
  243. package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
  244. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
  245. package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
  246. package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
  247. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
  248. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
  249. package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
  250. package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
  251. package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
  252. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
  253. package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
  254. package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
  255. package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
  256. package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
  257. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
  258. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
  259. package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
  260. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
  261. package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
  262. package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
  263. package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
  264. package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
  265. package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
  266. package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
  267. package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
  268. package/node_modules/pi-lens/dist/index.js +19969 -17481
  269. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
  270. package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
  271. package/node_modules/pi-lens/dist/mcp/server.js +135 -159
  272. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
  273. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
  274. package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
  275. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
  276. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
  277. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
  278. package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
  279. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
  280. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +354 -86
  281. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +54 -112
  282. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
  283. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
  284. package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
  285. package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
  286. package/node_modules/pi-lens/dist/tools/render-compact.js +281 -2
  287. package/node_modules/pi-lens/dist/tools/symbol-search.js +3 -4
  288. package/node_modules/pi-lens/docs/agent-guide.md +3 -4
  289. package/node_modules/pi-lens/docs/agent-tools.md +46 -22
  290. package/node_modules/pi-lens/docs/configuration.md +9 -0
  291. package/node_modules/pi-lens/docs/environment-variables.md +0 -5
  292. package/node_modules/pi-lens/docs/features.md +5 -5
  293. package/node_modules/pi-lens/docs/globalconfig.md +31 -1
  294. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
  295. package/node_modules/pi-lens/docs/mcp.md +13 -1
  296. package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
  297. package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
  298. package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
  299. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +41 -0
  300. package/node_modules/pi-lens/docs/pi-lens-subagent.md +21 -2
  301. package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
  302. package/node_modules/pi-lens/docs/real-harness.md +46 -0
  303. package/node_modules/pi-lens/docs/release-qa-baseline.md +17 -5
  304. package/node_modules/pi-lens/docs/servercapabilities.md +2 -3
  305. package/node_modules/pi-lens/docs/settings.md +37 -2
  306. package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
  307. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  308. package/node_modules/pi-lens/docs/usage.md +13 -3
  309. package/node_modules/pi-lens/docs/word-index.md +1 -1
  310. package/node_modules/pi-lens/package.json +15 -15
  311. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
  312. package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
  313. package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
  314. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
  315. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
  316. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
  317. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
  318. package/node_modules/pi-web-access/CHANGELOG.md +29 -0
  319. package/node_modules/pi-web-access/README.md +33 -22
  320. package/node_modules/pi-web-access/abortable.ts +17 -0
  321. package/node_modules/pi-web-access/crawl4ai.ts +204 -0
  322. package/node_modules/pi-web-access/credential-source.ts +1 -0
  323. package/node_modules/pi-web-access/curator-page.ts +20 -2
  324. package/node_modules/pi-web-access/curator-run.ts +44 -0
  325. package/node_modules/pi-web-access/curator-server.ts +3 -1
  326. package/node_modules/pi-web-access/duckduckgo.ts +1 -1
  327. package/node_modules/pi-web-access/extract.ts +57 -12
  328. package/node_modules/pi-web-access/fetch-params.ts +1 -1
  329. package/node_modules/pi-web-access/gemini-search.ts +9 -5
  330. package/node_modules/pi-web-access/index.ts +25 -18
  331. package/node_modules/pi-web-access/openai-search.ts +35 -13
  332. package/node_modules/pi-web-access/package.json +2 -2
  333. package/node_modules/pi-web-access/page-query.ts +5 -2
  334. package/node_modules/pi-web-access/query-rewrite.ts +5 -2
  335. package/node_modules/pi-web-access/serpapi.ts +220 -0
  336. package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
  337. package/node_modules/pi-web-access/storage.ts +10 -0
  338. package/node_modules/pi-web-access/summary-review.ts +34 -21
  339. package/node_modules/pi-web-access/utils.ts +6 -4
  340. package/package.json +7 -4
  341. package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
@@ -1,55 +1,7 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { getProjectIgnoreMatcher, isExcludedDirName, } from "./file-utils.js";
4
- import { isGeneratedArtifactDirectoryName, isGeneratedOrArtifact, } from "./generated-artifacts.js";
5
- import { collectSourceFiles, collectSourceFilesAsync, collectSourceFilesWithBudgetAsync, } from "./source-filter.js";
6
- export function shouldSkipProjectPath(filePath, options) {
7
- const isDirectory = options.isDirectory === true;
8
- const matcher = options.ignoreMatcher ?? getProjectIgnoreMatcher(options.rootDir);
9
- if (matcher.isIgnored(filePath, isDirectory))
10
- return true;
11
- const name = path.basename(filePath);
12
- if (isDirectory) {
13
- if (isExcludedDirName(name))
14
- return true;
15
- return (options.includeGenerated !== true &&
16
- isGeneratedArtifactDirectoryName(name));
17
- }
18
- return (options.includeGenerated !== true &&
19
- isGeneratedOrArtifact(filePath, {
20
- readContentHeader: options.inspectGeneratedHeaders !== false,
21
- includeDeclarations: options.includeDeclarationFiles !== true,
22
- }));
23
- }
24
- export function shouldScanProjectSourceFile(filePath, options) {
25
- try {
26
- if (!fs.statSync(filePath).isFile())
27
- return false;
28
- }
29
- catch {
30
- return false;
31
- }
32
- return !shouldSkipProjectPath(filePath, {
33
- ...options,
34
- isDirectory: false,
35
- });
36
- }
37
- export function collectProjectSourceFiles(rootDir, options) {
38
- return collectSourceFiles(rootDir, options);
39
- }
40
- /**
41
- * Async, chunked-yield twin of {@link collectProjectSourceFiles}. Produces the
42
- * exact same file list (it shares `classifyEntry` with the sync collector) but
43
- * yields to the event loop every N entries so a large-tree walk on a hot hook
44
- * tick (e.g. the per-edit cascade graph rebuild) never holds the loop in one
45
- * synchronous burst. Prefer this on the per-edit / per-cascade path.
46
- */
47
- export function collectProjectSourceFilesAsync(rootDir, options) {
48
- return collectSourceFilesAsync(rootDir, options);
49
- }
1
+ import { collectSourceFilesWithBudgetAsync, } from "./source-filter.js";
50
2
  /**
51
- * Budget-aware twin of {@link collectProjectSourceFilesAsync} (#760): same
52
- * walk, but returns `{ files, entryBudgetExceeded }` so a caller on a hot
3
+ * Budget-aware source walk (#760): the same walk as
4
+ * `collectProjectSourceFiles`, but returns `{ files, entryBudgetExceeded }` so a caller on a hot
53
5
  * path (e.g. the per-edit cascade graph rebuild) can observe that the walk
54
6
  * stopped at its `maxScanEntries` entry budget and got a truncated
55
7
  * best-effort list rather than a complete enumeration.
@@ -455,7 +455,7 @@ class Summary {
455
455
  return false;
456
456
  }
457
457
  }
458
- export function getPythonProvenanceSummary(root) {
458
+ function getPythonProvenanceSummary(root) {
459
459
  const cached = SUMMARY_BY_ROOT.get(root);
460
460
  if (cached)
461
461
  return cached;
@@ -3,6 +3,7 @@ import { isTestMode } from "./env-utils.js";
3
3
  import { getGlobalPiLensLogDir } from "./probe-home-state.js";
4
4
  import { createNdjsonLogger } from "./ndjson-logger.js";
5
5
  import { normalizeFilePath } from "./path-utils.js";
6
+ import { getTurnId } from "./turn-context.js";
6
7
  const READ_GUARD_LOG_DIR = getGlobalPiLensLogDir();
7
8
  const READ_GUARD_LOG_FILE = path.join(READ_GUARD_LOG_DIR, "read-guard.log");
8
9
  const READ_GUARD_LOG_BACKUP_FILE = path.join(READ_GUARD_LOG_DIR, "read-guard.log.1");
@@ -18,7 +19,7 @@ const VERBOSE_READ_GUARD_LOG = process.env.PI_LENS_READ_GUARD_VERBOSE === "1" ||
18
19
  const LOG_ALLOWED_EDITS = process.env.PI_LENS_READ_GUARD_LOG_ALLOWS === "1";
19
20
  const SNAPSHOT_LOG_SETTING = (process.env.PI_LENS_READ_GUARD_LOG_SNAPSHOTS ?? "1").toLowerCase();
20
21
  const LOG_SNAPSHOT_VALIDATION = !["0", "false", "off"].includes(SNAPSHOT_LOG_SETTING);
21
- export const MAX_EDIT_BATCH_ITEMS = 100;
22
+ const MAX_EDIT_BATCH_ITEMS = 100;
22
23
  let generatedCorrelationCounter = 0;
23
24
  export function sanitizeCorrelationId(value) {
24
25
  if (typeof value !== "string" && typeof value !== "number")
@@ -236,6 +237,7 @@ export function logReadGuardEvent(entry) {
236
237
  writer.log({
237
238
  ts: new Date().toISOString(),
238
239
  ...logEntry,
240
+ turnId: getTurnId(),
239
241
  filePath: normalizeFilePath(logEntry.filePath),
240
242
  metadata,
241
243
  });
@@ -1396,8 +1396,11 @@ export class ReadGuard {
1396
1396
  return filePath.endsWith(suffix);
1397
1397
  }
1398
1398
  if (pattern.includes("*")) {
1399
- // Convert glob to regex
1400
- const regex = new RegExp(`^${pattern.replace(/\\/g, "\\\\").replace(/\./g, "\\.").replace(/\*/g, ".*")}$`);
1399
+ // Adjacent stars are equivalent to one star in this dialect. Collapse
1400
+ // them before compiling so a non-match cannot backtrack over every
1401
+ // nullable `.*` group (#2622).
1402
+ const collapsedPattern = pattern.replace(/\*+/g, "*");
1403
+ const regex = new RegExp(`^${collapsedPattern.replace(/\\/g, "\\\\").replace(/\./g, "\\.").replace(/\*/g, ".*")}$`);
1401
1404
  return regex.test(filePath);
1402
1405
  }
1403
1406
  return filePath === pattern;
@@ -37,7 +37,7 @@ import { getProjectDataDir } from "./file-utils.js";
37
37
  import { normalizeFilePath } from "./path-utils.js";
38
38
  export const RECENT_TOUCHES_MAX_ENTRIES = 50;
39
39
  /** Freshness window for the CHILD session_start consumer (15 minutes). */
40
- export const RECENT_TOUCHES_FRESHNESS_MS = 15 * 60 * 1000;
40
+ const RECENT_TOUCHES_FRESHNESS_MS = 15 * 60 * 1000;
41
41
  function recentTouchesPath(cwd) {
42
42
  return path.join(getProjectDataDir(cwd), "recent-touches.json");
43
43
  }
@@ -46,7 +46,7 @@ function recentTouchesPath(cwd) {
46
46
  // INTO the same nudge pipeline, so one switch governs the whole path
47
47
  // (producer, both consumers) as specified in the issue.
48
48
  let _enabledCache;
49
- export function isRecentTouchesEnabled() {
49
+ function isRecentTouchesEnabled() {
50
50
  if (_enabledCache === undefined) {
51
51
  _enabledCache = process.env.PI_LENS_AGENT_NUDGE !== "0";
52
52
  }
@@ -92,8 +92,6 @@ const MAIN_KINDS = new Set([
92
92
  // so a repo heavy in JSON/YAML/Markdown doesn't trip the cap on files the graph
93
93
  // would have filtered out anyway (the cap is on the walk, not on noise). #250.
94
94
  const MAIN_KIND_EXTENSIONS = Array.from(MAIN_KINDS).flatMap((kind) => KIND_EXTENSIONS[kind] ?? []);
95
- /** The bounded, source-filtered extension set shared by graph cache readers. */
96
- export const REVIEW_GRAPH_SOURCE_EXTENSIONS = MAIN_KIND_EXTENSIONS;
97
95
  const CHANGED_SYMBOLS_PREFIX = "session.reviewGraph.changedSymbols:";
98
96
  const extractorCache = new Map();
99
97
  const REVIEW_GRAPH_MAX_WARM_WORKSPACES = 8;
@@ -407,7 +405,7 @@ export function estimateReviewGraphStoreBytes(totalNodes, totalEdges) {
407
405
  // cleared). Bounding only the cache left the full graph resident on the fact, so
408
406
  // both sites go through `retainedGraph` below, memoized per graph instance so the
409
407
  // two sites share ONE bounded object instead of trimming twice (#2255 review F2).
410
- export const GRAPH_MAX_IN_MEMORY_BYTES_DEFAULT = 512 * 1024 * 1024;
408
+ const GRAPH_MAX_IN_MEMORY_BYTES_DEFAULT = 512 * 1024 * 1024;
411
409
  function graphMaxInMemoryBytes() {
412
410
  const raw = Number(process.env.PI_LENS_GRAPH_MAX_IN_MEMORY_BYTES);
413
411
  return Number.isFinite(raw) && raw > 0
@@ -967,7 +965,7 @@ function diffSignatureMaps(previous, next) {
967
965
  // `RUNTIME_CONFIG.reviewGraph.maxFiles` constant as the fallback — the ratio
968
966
  // table reproduces that same 1,000-file default at the default base, so this
969
967
  // is behavior-neutral when nothing is configured.
970
- export function getReviewGraphMaxFiles(cwd) {
968
+ function getReviewGraphMaxFiles(cwd) {
971
969
  const override = Number.parseInt(process.env.PI_LENS_REVIEW_GRAPH_MAX_FILES ?? "", 10);
972
970
  return Number.isFinite(override) && override > 0
973
971
  ? override
@@ -3481,7 +3479,7 @@ function addTreeSitterFile(graph, cwd, filePath, languageId, extracted, ignoredI
3481
3479
  * SymbolInformation results (including native TypeScript 7) recover the same
3482
3480
  * containment through `containerName` when the owner is present in the result.
3483
3481
  */
3484
- export function addLspFallbackSymbols(graph, filePath, languageId, symbols) {
3482
+ function addLspFallbackSymbols(graph, filePath, languageId, symbols) {
3485
3483
  const normalized = normalizeMapKey(filePath);
3486
3484
  const fileNodeId = `file:${normalized}`;
3487
3485
  let added = 0;
@@ -90,7 +90,7 @@ function resolveDart(cwd, filePath, source) {
90
90
  // JS/TS extension from the specifier before re-appending candidate extensions
91
91
  // lets that universal pattern resolve to the real source file. Exported so
92
92
  // builder.ts's warm `localImportToFile` shares the exact same regex (#694).
93
- export const JS_TS_EXT_RE = /\.(mjs|cjs|mts|cts|jsx?|tsx?)$/i;
93
+ const JS_TS_EXT_RE = /\.(mjs|cjs|mts|cts|jsx?|tsx?)$/i;
94
94
  /**
95
95
  * Ordered candidate list for resolving a relative JS/TS import specifier
96
96
  * (already resolved to an absolute base path) to an on-disk file, with
@@ -4,6 +4,7 @@ import { getGlobalPiLensLogDir } from "./probe-home-state.js";
4
4
  import { getMaxLogSizeMB } from "./log-cleanup.js";
5
5
  import { createNdjsonLogger } from "./ndjson-logger.js";
6
6
  import { normalizeFilePath } from "./path-utils.js";
7
+ import { getTurnId } from "./turn-context.js";
7
8
  const REVIEW_GRAPH_LOG_DIR = getGlobalPiLensLogDir();
8
9
  const REVIEW_GRAPH_LOG_FILE = path.join(REVIEW_GRAPH_LOG_DIR, "review-graph.log");
9
10
  // Bounded like every other global sink (#2505) — see sessionstart-logger.
@@ -64,6 +65,7 @@ export function logReviewGraph(entry) {
64
65
  ...entry,
65
66
  cwd: normalizeFilePath(entry.cwd),
66
67
  pid: process.pid,
68
+ turnId: getTurnId(),
67
69
  });
68
70
  }
69
71
  export function getReviewGraphLogPath() {
@@ -13,6 +13,7 @@ import * as path from "node:path";
13
13
  import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./dispatch/runners/utils/runner-helpers.js";
14
14
  import { isFileKind } from "./file-kinds.js";
15
15
  import { safeSpawnAsync } from "./safe-spawn.js";
16
+ import { resolveToolCwd } from "./tool-cwd.js";
16
17
  import { ruffConfigArgs } from "./tool-policy.js";
17
18
  // --- Client ---
18
19
  const ruffAvailability = createAvailabilityChecker("ruff", ".exe");
@@ -44,8 +45,11 @@ export class RuffClient {
44
45
  }
45
46
  /**
46
47
  * Async auto-fix variant for pipeline use (non-blocking spawn).
47
- * `cwd` is the dispatch language root (used for config discovery); when
48
- * omitted it defaults to the file's directory.
48
+ * `cwd` is the dispatch language root. It is the seam's starting point,
49
+ * not the answer: `resolveToolCwd` walks from the file to the nearest
50
+ * `pyproject.toml`/`ruff.toml`/`.ruff.toml` at or above it, capped inside
51
+ * `cwd` (and at `$HOME` when there is none), so a file in a nested package
52
+ * gets that package's config rather than the workspace-root one.
49
53
  */
50
54
  async fixFileAsync(filePath, cwd) {
51
55
  if (!(await this.ensureAvailable())) {
@@ -67,15 +71,20 @@ export class RuffClient {
67
71
  }
68
72
  try {
69
73
  const before = await fs.promises.readFile(absolutePath, "utf-8");
74
+ // #2894: the root ruff resolves its config from now comes from the
75
+ // shared seam, not a local `cwd ?? path.dirname(file)`. `tool-policy.ts`
76
+ // requires the lint runner (`ruff.ts`, on `resolveRunnerCwd`) and this
77
+ // autofix path to consume the SAME policy; deriving the root two
78
+ // different ways is how they drift, and the hand-rolled form ignored a
79
+ // nested `pyproject.toml` whenever the caller passed a workspace root.
80
+ const ruffCwd = resolveToolCwd("runner", "ruff", absolutePath, {
81
+ ...(cwd !== undefined && { cwd }),
82
+ });
70
83
  // Shared config-args seam (#1247): the lint runner consumes the same
71
84
  // builder, so `check --fix` can never drift to ruff's default rule
72
85
  // set when the project lacks its own config and the package-owned
73
86
  // core.toml fallback applies.
74
- const configArgs = ruffConfigArgs(cwd ?? path.dirname(absolutePath));
75
- const spawnOpts = {
76
- timeout: 10000,
77
- cwd: cwd ?? path.dirname(absolutePath),
78
- };
87
+ const configArgs = ruffConfigArgs(ruffCwd);
79
88
  const pre = await safeSpawnAsync(this.ruffCommand, [
80
89
  "check",
81
90
  "--output-format",
@@ -84,12 +93,12 @@ export class RuffClient {
84
93
  "py310",
85
94
  ...configArgs,
86
95
  absolutePath,
87
- ], spawnOpts);
96
+ ], { timeout: 10000, cwd: ruffCwd });
88
97
  const beforeDiags = pre.stdout?.trim()
89
98
  ? this.parseOutput(pre.stdout, absolutePath)
90
99
  : [];
91
100
  const fixableCount = beforeDiags.filter((d) => d.fixable).length;
92
- const fix = await safeSpawnAsync(this.ruffCommand, ["check", "--fix", ...configArgs, absolutePath], { timeout: 15000, cwd: cwd ?? path.dirname(absolutePath) });
101
+ const fix = await safeSpawnAsync(this.ruffCommand, ["check", "--fix", ...configArgs, absolutePath], { timeout: 15000, cwd: ruffCwd });
93
102
  if (fix.error) {
94
103
  return {
95
104
  success: false,
@@ -19,7 +19,7 @@ import { getAutofixPolicyForFile, hasBiomeConfig, hasDetektConfig, hasEslintConf
19
19
  * path at all (they match on `ownerSessionId`), so this only trades a little
20
20
  * extra staleness for guaranteed eventual formatting. (#791)
21
21
  */
22
- export const DEFERRED_FORMAT_STALE_AFTER_MS = 10 * 60_000;
22
+ const DEFERRED_FORMAT_STALE_AFTER_MS = 10 * 60_000;
23
23
  const DEFERRED_FORMAT_CONCURRENCY = 3;
24
24
  function recordProjectChange(args) {
25
25
  // One mutation seam (#2000 phase 1): bump + receipt + change-log live in
@@ -39,6 +39,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
39
39
  // to fall back to "claim as orphaned" (see claimDeferredFormatFiles).
40
40
  const { claimed, staleClaimed, deferredToOwner, droppedOrphans } = runtime.claimDeferredMutations(currentSessionId, Date.now(), staleAfterMs, ctxCwd ?? runtime.projectRoot);
41
41
  const records = [...claimed, ...staleClaimed];
42
+ const scheduledTurnId = records[0]?.queuedTurnId;
42
43
  const requeuedKinds = new Set();
43
44
  // S2d (gap 4, #1432 review): the aggregate `agent_end_deferred_mutation_drain`
44
45
  // row only carried a coalesced `requeuedKinds` set with no reason, per-call
@@ -65,6 +66,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
65
66
  toolName: "agent_end",
66
67
  filePath: ctxCwd ?? runtime.projectRoot,
67
68
  phase: "agent_end_deferred_mutation_requeue",
69
+ turnId: pending[0]?.queuedTurnId,
68
70
  durationMs: 0,
69
71
  metadata: {
70
72
  reason,
@@ -170,6 +172,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
170
172
  toolName: "agent_end",
171
173
  filePath: ctxCwd ?? runtime.projectRoot,
172
174
  phase: "agent_end_deferred_format_stale_claim",
175
+ turnId: scheduledTurnId,
173
176
  durationMs: 0,
174
177
  metadata: {
175
178
  fileCount: staleClaimed.length,
@@ -307,6 +310,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
307
310
  toolName: "agent_end",
308
311
  filePath: ctxCwd ?? runtime.projectRoot,
309
312
  phase: "agent_end_deferred_format_start",
313
+ turnId: scheduledTurnId,
310
314
  durationMs: 0,
311
315
  metadata: {
312
316
  fileCount: records.length,
@@ -491,6 +495,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
491
495
  toolName: "agent_end",
492
496
  filePath,
493
497
  phase: "deferred_format_file",
498
+ turnId: record.queuedTurnId,
494
499
  durationMs: Date.now() - fileStart,
495
500
  metadata: {
496
501
  changed: result.formatChanged,
@@ -635,6 +640,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
635
640
  toolName: "agent_end",
636
641
  filePath: ctxCwd ?? runtime.projectRoot,
637
642
  phase: "actionable_warnings_autofix",
643
+ turnId: scheduledTurnId,
638
644
  durationMs: Date.now() - fixStart,
639
645
  metadata: {
640
646
  considered: fixSummary.considered,
@@ -657,6 +663,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
657
663
  toolName: "agent_end",
658
664
  filePath: ctxCwd ?? runtime.projectRoot,
659
665
  phase: "agent_end_deferred_mutation_drain",
666
+ turnId: scheduledTurnId,
660
667
  durationMs: Date.now() - startedAt,
661
668
  metadata: {
662
669
  autofixRecords: autofixRecords.length,
@@ -671,6 +678,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
671
678
  filePath: ctxCwd ?? runtime.projectRoot,
672
679
  durationMs: Date.now() - startedAt,
673
680
  result: "deferred_format_complete",
681
+ turnId: scheduledTurnId,
674
682
  metadata: {
675
683
  queued: summary.queued,
676
684
  formatted: summary.formatted,
@@ -685,6 +693,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
685
693
  toolName: "agent_end",
686
694
  filePath: ctxCwd ?? runtime.projectRoot,
687
695
  phase: "agent_end_deferred_format_done",
696
+ turnId: scheduledTurnId,
688
697
  durationMs: Date.now() - startedAt,
689
698
  metadata: {
690
699
  formatted: summary.formatted,
@@ -11,6 +11,7 @@ import { ReadGuard } from "./read-guard.js";
11
11
  import { RUNTIME_CONFIG } from "./runtime-config.js";
12
12
  import { TurnSummaryCollector } from "./turn-summary.js";
13
13
  import { deriveProviderFromModelId } from "./model-provider.js";
14
+ import { beginTurnContext, setTurnContextSession } from "./turn-context.js";
14
15
  /**
15
16
  * Bounded receipt ring capacity (defect shape 9: bound the axis that grows —
16
17
  * per-mutation receipts are unbounded across a long session). Oldest receipts
@@ -259,6 +260,7 @@ export class RuntimeCoordinator {
259
260
  // by resetForSession().
260
261
  this._turnStartProjectSeq = this._projectSeq;
261
262
  this._turnIndex += 1;
263
+ beginTurnContext(this._telemetrySessionId);
262
264
  this._writeIndex = 0;
263
265
  this._reportedThisTurn.clear();
264
266
  this._writtenThisTurn.clear();
@@ -362,6 +364,7 @@ export class RuntimeCoordinator {
362
364
  setTelemetryIdentity(identity) {
363
365
  if (identity.sessionId && identity.sessionId.trim()) {
364
366
  this._telemetrySessionId = identity.sessionId.trim();
367
+ setTurnContextSession(this._telemetrySessionId);
365
368
  }
366
369
  const model = identity.model?.trim();
367
370
  const provider = identity.provider?.trim();
@@ -1029,6 +1032,7 @@ export class RuntimeCoordinator {
1029
1032
  existing.toolNames.add(toolName);
1030
1033
  existing.kinds.add(kind);
1031
1034
  existing.queuedTurnIndex = this._turnIndex;
1035
+ existing.queuedTurnId = `${this._telemetrySessionId}:${this._turnIndex}`;
1032
1036
  existing.ownerSessionId = ownerSessionId;
1033
1037
  existing.originCwd = resolvedOriginCwd;
1034
1038
  return addedKind;
@@ -1042,6 +1046,7 @@ export class RuntimeCoordinator {
1042
1046
  toolNames: new Set([toolName]),
1043
1047
  kinds: new Set([kind]),
1044
1048
  queuedTurnIndex: this._turnIndex,
1049
+ queuedTurnId: `${this._telemetrySessionId}:${this._turnIndex}`,
1045
1050
  ownerSessionId,
1046
1051
  originCwd: resolvedOriginCwd,
1047
1052
  });
@@ -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";
@@ -42,6 +42,7 @@ import { resetSafeSpawnWindowsCommandCache } from "./safe-spawn.js";
42
42
  import { resetAnalyzerBootstrapSessionState, } from "./bootstrap.js";
43
43
  import { getSlowFsVerdict, isSlowFs, slowFsDegradationNotice, } from "./slow-fs.js";
44
44
  import { countRecentSmells, formatSmellsSessionStartLine, resetSmellsSessionState, } from "./smells-rollup.js";
45
+ import { resetSituationalToolTelemetry } from "./situational-tool-telemetry.js";
45
46
  import { findNearestProjectRoot, getStartupScanMaxEntries, isStartupScanVerdictFresh, resolveStartupScanContext, } from "./startup-scan.js";
46
47
  import { getSubagentIdentity, isSubagentSession, subagentLightModeNotice, } from "./subagent-mode.js";
47
48
  import { TrivyClient } from "./trivy-client.js";
@@ -256,11 +257,14 @@ function logProjectSnapshotProbe(args) {
256
257
  args.dbg(`project_snapshot: miss reason=${args.missReason}`);
257
258
  }
258
259
  }
259
- function resolveStartupMode() {
260
+ function resolveStartupMode(projectConfig, globalConfig) {
260
261
  const envMode = (process.env.PI_LENS_STARTUP_MODE ?? "").trim().toLowerCase();
261
262
  if (envMode === "full" || envMode === "minimal" || envMode === "quick") {
262
263
  return envMode;
263
264
  }
265
+ const configMode = projectConfig?.startup?.mode ?? globalConfig?.startup?.mode;
266
+ if (configMode)
267
+ return configMode;
264
268
  if (isPrintMode()) {
265
269
  return "quick";
266
270
  }
@@ -813,6 +817,15 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
813
817
  /** The scan bodies, once the analyzers they need are resolved. */
814
818
  function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analysisRoot, snapshotRoot, languageProfile, dbg) {
815
819
  const { todoScanner, cacheManager, knipClient, jscpdClient, deadCodeClients, govulncheckClient, gitleaksClient, trivyClient, opengrepClient, astGrepClient, depChecker, } = deps;
820
+ const analyzerEnabled = (flag) => !deps.getFlag(flag);
821
+ if (!analyzerEnabled("no-complexity")) {
822
+ dbg("session_start complexity: skipped (disabled by config)");
823
+ recordDegradationOnce({
824
+ kind: "startup-analyzer-disabled",
825
+ subject: "complexity",
826
+ reason: "skipped (disabled by config)",
827
+ });
828
+ }
816
829
  // Some background scans are CPU-heavy and arrive on the event loop
817
830
  // just as the user is most likely typing (right after /new). Defer
818
831
  // those by a few seconds so the perceptible 50-100ms sync bursts they
@@ -869,7 +882,7 @@ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analy
869
882
  scanNames.push("knip", "jscpd", "ast-grep exports", "project index");
870
883
  }
871
884
  dbg(`session_start: launching background scans (${scanNames.join(", ")})`);
872
- runTask("todo", async () => {
885
+ void runTask("todo", async () => {
873
886
  if (!runtime.isCurrentSession(sessionGeneration))
874
887
  return;
875
888
  // The original implementation called todoScanner.scanDirectory(), which
@@ -906,9 +919,19 @@ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analy
906
919
  const isSubagent = isSubagentSession();
907
920
  const skipHeavyweightScans = isSlowFs(analysisRoot) || isSubagent;
908
921
  const runHeavyweightTask = (name, task) => {
922
+ const flag = `no-${name}`;
923
+ if (name !== "opengrep" && name !== "trivy" && !analyzerEnabled(flag)) {
924
+ dbg(`session_start ${name}: skipped (disabled by config)`);
925
+ recordDegradationOnce({
926
+ kind: "startup-analyzer-disabled",
927
+ subject: name,
928
+ reason: "skipped (disabled by config)",
929
+ });
930
+ return;
931
+ }
909
932
  if (skipHeavyweightScans)
910
933
  return;
911
- runTask(name, task);
934
+ void runTask(name, task);
912
935
  };
913
936
  if (skipHeavyweightScans) {
914
937
  dbg(`session_start: skipping knip/jscpd/madge/dead-code/govulncheck/gitleaks/trivy/opengrep (${isSubagent ? "subagent" : "slow-fs"})`);
@@ -1239,7 +1262,7 @@ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analy
1239
1262
  // racing its independently deferred timer. Otherwise a slow graph build leaves
1240
1263
  // `runtime.callGraph` unset at this task's start and loses the model for the
1241
1264
  // entire session (#1070).
1242
- runTask("codebase-model", async () => {
1265
+ void runTask("codebase-model", async () => {
1243
1266
  await callGraphTask;
1244
1267
  if (!runtime.isCurrentSession(sessionGeneration))
1245
1268
  return;
@@ -1258,7 +1281,7 @@ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analy
1258
1281
  `${model.totalTokens} tokens, top symbols: ${top3 || "(none)"}`);
1259
1282
  });
1260
1283
  // ast-grep — export scan for duplicate detection
1261
- runTask("ast-grep-exports", async () => {
1284
+ void runTask("ast-grep-exports", async () => {
1262
1285
  if (await astGrepClient.ensureAvailable()) {
1263
1286
  if (!runtime.isCurrentSession(sessionGeneration))
1264
1287
  return;
@@ -1275,7 +1298,7 @@ function scheduleStartupScansWithClients(deps, runtime, sessionGeneration, analy
1275
1298
  // word-index — identifier inverted index + BM25 for ranked symbol search
1276
1299
  // (#162). Load -> rebuild-if-stale -> persist lifecycle (#348), shared with
1277
1300
  // the quick-mode cold-start warmup pass below.
1278
- runTask("word-index", async () => {
1301
+ void runTask("word-index", async () => {
1279
1302
  await buildOrRefreshWordIndex({
1280
1303
  runtime,
1281
1304
  sessionGeneration,
@@ -1339,17 +1362,16 @@ function scheduleDeferredToolProbesWithClients(deps, languageProfile, startupDef
1339
1362
  /**
1340
1363
  * Session-start orientation prepended as a context message (gated by the
1341
1364
  * context-injection toggle). Deliberately lean: it names the high-value tools
1342
- * and the one non-obvious behaviour (mode=all resurfaces stale blocking errors)
1365
+ * and the distinction between cached reporting and active verification
1343
1366
  * — per-tool argument detail lives in each tool's own registered description, so
1344
1367
  * re-documenting it here would just pay the tokens twice every session.
1345
1368
  */
1346
1369
  export const SESSION_START_GUIDANCE = [
1347
1370
  "📌 pi-lens active — automated checks run on every edit/write; blocking errors (including pre-existing) show inline and must be fixed.\n" +
1348
1371
  "Key tools (see each tool's own description for args):\n" +
1349
- "• lens_diagnostics — session-wide diagnostic state; mode=all resurfaces stale blocking errors that dropped from turn context.\n" +
1372
+ "• lens_diagnostics — source=session reads cache; empty cache ≠ clean; use source=lsp scope=paths for changed files with absent or stale findings.\n" +
1350
1373
  "• symbol_search → module_report → read_symbol/read_enclosing — ranked identifier search, then navigable outline/callback handles + exact body reads; cheaper than reading a whole file before editing.\n" +
1351
- "• lsp_diagnostics — probe LSP for errors in a file/folder/workspace.\n" +
1352
- "• Situational (activate via pi_lens_activate_tools): lsp_navigation, ast_grep_search, ast_grep_replace, ast_grep_dump.",
1374
+ "• Situational (activate via pi_lens_activate_tools): lsp_navigation, ast_grep_search, ast_grep_replace. Use ast_grep_search with dump=true to inspect AST nodes.",
1353
1375
  ];
1354
1376
  export async function handleSessionStart(deps) {
1355
1377
  resetDegradationLedger();
@@ -1423,7 +1445,7 @@ export async function handleSessionStart(deps) {
1423
1445
  // entirely — but only when PI_LENS_STARTUP_MODE is unset in the env
1424
1446
  // (an explicit env var still takes highest precedence).
1425
1447
  // Tunable: PI_LENS_WARMUP_DELAY_MS adjusts the warmup delay.
1426
- let startupMode = resolveStartupMode();
1448
+ let startupMode = resolveStartupMode(deps.projectConfig, deps.globalConfig);
1427
1449
  // SAFETY: these two flags are process-lifetime state pi-lens stashes on
1428
1450
  // `globalThis` so a second extension instance in the same process sees the
1429
1451
  // first one's warmup. There is no ambient declaration for them, and adding
@@ -1433,7 +1455,9 @@ export async function handleSessionStart(deps) {
1433
1455
  const isFirstSessionOfProcess = !processGlobals.__piLensFirstSessionDone;
1434
1456
  if (isFirstSessionOfProcess &&
1435
1457
  process.env.PI_LENS_COLD_START_QUICK !== "0" &&
1436
- !process.env.PI_LENS_STARTUP_MODE) {
1458
+ !process.env.PI_LENS_STARTUP_MODE &&
1459
+ !deps.projectConfig?.startup?.mode &&
1460
+ !deps.globalConfig?.startup?.mode) {
1437
1461
  // Apply host-provided override (e.g. MCP server forces "full") before
1438
1462
  // falling back to the TUI quick-mode heuristic.
1439
1463
  startupMode = deps.startupModeOverride ?? "quick";
@@ -1790,6 +1814,15 @@ export async function handleSessionStart(deps) {
1790
1814
  // #1123 item 3: a fresh session can re-report smells that a prior session
1791
1815
  // already surfaced once (see `checkSmellsAndNoteOnce`'s once-per-session gate).
1792
1816
  resetSmellsSessionState();
1817
+ // #2800 item 8: the situational-tool dead-weight observation (which tools
1818
+ // this session never activated or called) is session-scoped, so its sets
1819
+ // and once-latch re-arm here beside the other registered resets. Both hosts
1820
+ // open the session's row through startSituationalToolTelemetrySession()
1821
+ // BEFORE this handler runs, and a repeated MCP session_start refresh
1822
+ // legitimately re-runs this handler — so the reset only acts when no
1823
+ // telemetry session is open; clearing a live session here would wipe the
1824
+ // calls recorded before the refresh.
1825
+ resetSituationalToolTelemetry();
1793
1826
  // #1782: re-arm the workspace-diagnostics cache session clock. Entries
1794
1827
  // written before this instant assert findings from a session that is over,
1795
1828
  // so they must revalidate before they can be served as current again.
@@ -2271,7 +2304,10 @@ export async function handleSessionStart(deps) {
2271
2304
  else {
2272
2305
  dbg("session_start: no language defaults selected for pre-install");
2273
2306
  }
2274
- const startupScansWillRun = allowBootstrapTasks && startupScan.canWarmCaches;
2307
+ const startupScansEnabled = deps.projectConfig?.startup?.scans?.enabled ??
2308
+ deps.globalConfig?.startup?.scans?.enabled ??
2309
+ true;
2310
+ const startupScansWillRun = allowBootstrapTasks && startupScan.canWarmCaches && startupScansEnabled;
2275
2311
  const jstsHeavyScansWillRun = startupScansWillRun && canRunStartupHeavyScans(languageProfile, "jsts");
2276
2312
  if (allowBootstrapTasks) {
2277
2313
  scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, jstsHeavyScansWillRun, dbg);
@@ -2326,6 +2362,14 @@ export async function handleSessionStart(deps) {
2326
2362
  if (!allowBootstrapTasks) {
2327
2363
  dbg("session_start: skipping startup background scans (startup mode)");
2328
2364
  }
2365
+ else if (!startupScansEnabled) {
2366
+ dbg("session_start: skipping startup background scans (disabled by config)");
2367
+ recordDegradationOnce({
2368
+ kind: "startup-analyzer-disabled",
2369
+ subject: "startup-scans",
2370
+ reason: "skipped (disabled by config)",
2371
+ });
2372
+ }
2329
2373
  else if (!startupScan.canWarmCaches) {
2330
2374
  dbg(`session_start: skipping heavy scans (${startupScan.reason ?? "unknown"})`);
2331
2375
  dbg(`session_start: skipping TODO scan (${startupScan.reason ?? "unknown"})`);
@@ -773,7 +773,8 @@ async function handleToolCallImpl(deps) {
773
773
  // is the client's own answer, hoisted into `tree-sitter-shared.ts` where it
774
774
  // needs nothing but the extension registry; `ComplexityClient.isSupportedFile`
775
775
  // delegates to it, so this is not a second copy.
776
- if (!isExternalOrVendor &&
776
+ if (!getFlag("no-complexity") &&
777
+ !isExternalOrVendor &&
777
778
  filePath &&
778
779
  !runtime.complexityBaselines.has(filePath) &&
779
780
  isComplexitySupportedFile(filePath)) {
@@ -803,6 +804,15 @@ async function handleToolCallImpl(deps) {
803
804
  });
804
805
  }
805
806
  }
807
+ else if (getFlag("no-complexity") &&
808
+ filePath &&
809
+ isComplexitySupportedFile(filePath)) {
810
+ recordDegradationOnce({
811
+ kind: "startup-analyzer-disabled",
812
+ subject: "complexity",
813
+ reason: "skipped (disabled by config)",
814
+ });
815
+ }
806
816
  // --- Read-Before-Edit Guard: check edits ---
807
817
  // write = full replacement; no prior read needed (you're starting fresh).
808
818
  // edit = partial modification; guard enforced to prevent blind overwrites.
@@ -21,7 +21,7 @@ import { replayThroughMutationBridge, storedLineHashesFor, } from "./observed-mu
21
21
  import { getAmbientAbortSignal } from "./safe-spawn.js";
22
22
  import { resolveToolCallCorrelationId } from "./tool-event.js";
23
23
  import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
24
- import { notifyExternalFileChange } from "./lsp/index.js";
24
+ import { notifyExternalFileChange, resyncGitChangedFiles, } from "./lsp/index.js";
25
25
  import { runPipeline } from "./pipeline.js";
26
26
  import { renderPostAutofixNotice, } from "./post-autofix-notice.js";
27
27
  import { syncGitGuardRecord } from "./git-guard.js";
@@ -897,6 +897,9 @@ export async function handleToolResult(deps) {
897
897
  durationMs: Date.now() - started,
898
898
  result: `changed:${opaquePaths.length}`,
899
899
  });
900
+ void resyncGitChangedFiles(opaquePaths).catch((err) => {
901
+ dbg(`git-change LSP resync failed: ${err}`);
902
+ });
900
903
  }
901
904
  }
902
905
  // wp iterates opaquePaths VERBATIM (already normalizeMapKey keys), so the