@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
@@ -55,7 +55,7 @@ const TYPESCRIPT_DIAGNOSTIC_SOURCES = new Set(["typescript", "ts", "tsserver"]);
55
55
  export function isTsProjectFile(filePath) {
56
56
  return TS_PROJECT_EXTENSIONS.has(path.extname(filePath).toLowerCase());
57
57
  }
58
- export function isTypeScriptSourcedDiagnostic(d) {
58
+ function isTypeScriptSourcedDiagnostic(d) {
59
59
  return TYPESCRIPT_DIAGNOSTIC_SOURCES.has((d.source ?? "").toLowerCase());
60
60
  }
61
61
  /**
@@ -61,11 +61,3 @@ export function getLanguageId(filePath) {
61
61
  LANGUAGE_EXTENSIONS[base.toLowerCase()] ??
62
62
  getBasenameLanguageId(base));
63
63
  }
64
- /**
65
- * Get all extensions for a language ID
66
- */
67
- export function getExtensionsForLanguage(languageId) {
68
- return Object.entries(LANGUAGE_EXTENSIONS)
69
- .filter(([, id]) => id === languageId)
70
- .map(([ext]) => ext);
71
- }
@@ -2,4 +2,4 @@
2
2
  * Re-export from shared path-utils.
3
3
  * Kept as a local module for LSP imports that use relative paths.
4
4
  */
5
- export { isUnderDir, normalizeFilePath, normalizeEphemeralMapKey, normalizeMapKey, pathsEqual, pathToUri, uriToDiskPath, uriToPath, } from "../path-utils.js";
5
+ export { isUnderDir, normalizeEphemeralMapKey, normalizeMapKey, pathsEqual, uriToDiskPath, uriToPath, } from "../path-utils.js";
@@ -187,8 +187,6 @@ export function drainPendingAuxiliaryCoverage() {
187
187
  export function pendingAuxiliaryCoverageSize() {
188
188
  return pending.size;
189
189
  }
190
- /** Test-only alias for the store-size assertion seam. */
191
- export const pendingAuxiliaryCoverageSizeForTests = pendingAuxiliaryCoverageSize;
192
190
  /**
193
191
  * Drain (read and reset) the cap-eviction count accumulated since the last
194
192
  * drain. Mirrors {@link drainPendingAuxiliaryCoverage}'s consume-once shape
@@ -26,6 +26,8 @@ import { logSessionStart } from "../sessionstart-logger.js";
26
26
  import { findLocalSgconfig, resolveBaselineSgconfig } from "../sgconfig.js";
27
27
  import { findLocalTyposConfig } from "../typos-config.js";
28
28
  import { resolvePackagePath } from "../package-root.js";
29
+ import { resolveToolCwd } from "../tool-cwd.js";
30
+ import { recordDegradationOnce } from "../degradation-ledger.js";
29
31
  import { hasCargoWorkspaceTable, readCargoWorkspaceExclude, readCargoWorkspaceMembers, readTextFileOrUndefined, } from "../cargo-manifest.js";
30
32
  import { resolveAstGrepNativeExe } from "./wait-policy/index.js";
31
33
  import { hasSpawnFailureKind, isCommandAvailableAsync, safeSpawnAsync, } from "../safe-spawn.js";
@@ -36,6 +38,48 @@ import { normalizeMapKey } from "./path-utils.js";
36
38
  import { getRubyVersionDirNamesSync } from "./ruby-drive-dirs.js";
37
39
  import { getProcessSingleton } from "../process-singletons.js";
38
40
  import { createGenerationSource, } from "../generation-guard.js";
41
+ function withRootMarkers(root, markers) {
42
+ root.rootMarkers = markers;
43
+ return root;
44
+ }
45
+ /** Resolve a server identity cwd through the shared tool-cwd seam. */
46
+ export async function resolveLspServerCwd(server, filePath, sessionCwd, onRootFailure) {
47
+ const rootMarkers = server.rootMarkers ?? server.root.rootMarkers;
48
+ let serverRoot;
49
+ let rootFailed = false;
50
+ try {
51
+ serverRoot = await server.root(filePath);
52
+ }
53
+ catch (error) {
54
+ const reason = error instanceof Error ? error.message : String(error);
55
+ rootFailed = true;
56
+ onRootFailure?.(reason);
57
+ }
58
+ const isFileDirFallback = serverRoot !== undefined &&
59
+ rootMarkers?.length &&
60
+ path.resolve(serverRoot) === path.resolve(path.dirname(filePath));
61
+ if (!serverRoot || isFileDirFallback) {
62
+ if (!serverRoot) {
63
+ recordDegradationOnce({
64
+ kind: "tool-cwd-resolution",
65
+ subject: server.id,
66
+ reason: `lsp:server-root-${rootFailed ? "failed" : "fallback"}:${filePath}`,
67
+ });
68
+ }
69
+ if (!rootMarkers?.length)
70
+ return undefined;
71
+ return resolveToolCwd("lsp", server.id, filePath, {
72
+ cwd: path.dirname(path.resolve(filePath)),
73
+ rootMarkers,
74
+ });
75
+ }
76
+ const boundedServerRoot = enforceLspRootCeiling(serverRoot, sessionCwd, filePath);
77
+ return resolveToolCwd("lsp", server.id, filePath, {
78
+ cwd: sessionCwd,
79
+ rootMarkers,
80
+ serverRoot: boundedServerRoot,
81
+ });
82
+ }
39
83
  const FIXTURE_ROOT_SEGMENTS = new Set(["__fixtures__", "testdata"]);
40
84
  const FALLBACK_PROJECT_MARKERS = [
41
85
  ".git",
@@ -845,12 +889,12 @@ function normalizeRootKey(root) {
845
889
  }
846
890
  function IgnoreHomeRoot(primary) {
847
891
  const homeKey = normalizeRootKey(os.homedir());
848
- return async (file) => {
892
+ return withRootMarkers(async (file) => {
849
893
  const root = await primary(file);
850
894
  if (!root)
851
895
  return undefined;
852
896
  return normalizeRootKey(root) === homeKey ? undefined : root;
853
- };
897
+ }, primary.rootMarkers ?? []);
854
898
  }
855
899
  function rubyBinCandidates(baseName) {
856
900
  const candidates = [];
@@ -879,6 +923,7 @@ function createInteractiveServer(spec) {
879
923
  name: spec.name,
880
924
  extensions: spec.extensions,
881
925
  root: spec.root,
926
+ rootMarkers: spec.root.rootMarkers,
882
927
  fallbackFor: spec.fallbackFor,
883
928
  availabilityKey: typeof spec.command === "string" && isSimpleCommand(spec.command)
884
929
  ? spec.command
@@ -917,29 +962,29 @@ function createInteractiveServer(spec) {
917
962
  }
918
963
  export function PriorityRoot(markerGroups, excludePatterns, stopDir) {
919
964
  const resolvers = markerGroups.map((markers) => NearestRoot(markers, excludePatterns, stopDir));
920
- return async (file) => {
965
+ return withRootMarkers(async (file) => {
921
966
  for (const resolve of resolvers) {
922
967
  const root = await resolve(file);
923
968
  if (root)
924
969
  return root;
925
970
  }
926
971
  return undefined;
927
- };
972
+ }, markerGroups.flat());
928
973
  }
929
974
  export const FileDirRoot = async (file) => {
930
975
  const candidate = path.resolve(path.dirname(file));
931
976
  return nearestNonExcludedFallbackRoot(candidate);
932
977
  };
933
978
  export function RootWithFallback(primary, fallback = FileDirRoot) {
934
- return async (file) => {
979
+ return withRootMarkers(async (file) => {
935
980
  const primaryRoot = await primary(file);
936
981
  if (primaryRoot)
937
982
  return primaryRoot;
938
983
  return fallback(file);
939
- };
984
+ }, primary.rootMarkers ?? []);
940
985
  }
941
986
  export function WorkspacePriorityRoot(markerGroups, excludePatterns) {
942
- return async (file) => PriorityRoot(markerGroups, excludePatterns, process.cwd())(file);
987
+ return withRootMarkers(async (file) => PriorityRoot(markerGroups, excludePatterns, process.cwd())(file), markerGroups.flat());
943
988
  }
944
989
  function isPermissionFsError(err) {
945
990
  const code = err?.code;
@@ -1010,7 +1055,7 @@ export function NearestRoot(includePatterns, excludePatterns, stopDir) {
1010
1055
  // re-walk cost for configless repos is a known trade-off; bounding the
1011
1056
  // walk with stopDir for in-cwd files is the tracked optimization (#1412).
1012
1057
  const inFlight = new Map();
1013
- return async (file) => {
1058
+ return withRootMarkers(async (file) => {
1014
1059
  // Cache key is the resolved directory — all files in the same dir share a root.
1015
1060
  const startDir = path.resolve(path.dirname(file));
1016
1061
  const dirKey = normalizeMapKey(startDir);
@@ -1052,6 +1097,7 @@ export function NearestRoot(includePatterns, excludePatterns, stopDir) {
1052
1097
  // glob markers like `*.csproj` match real project filenames (#201).
1053
1098
  for (const pattern of includePatterns) {
1054
1099
  if ((await markerExists(currentDir, pattern)) &&
1100
+ (pattern !== ".git" || currentDir !== os.tmpdir()) &&
1055
1101
  !(await isExcludedLspRoot(currentDir))) {
1056
1102
  return enforceLspRootCeiling(currentDir, process.cwd(), file);
1057
1103
  }
@@ -1073,7 +1119,7 @@ export function NearestRoot(includePatterns, excludePatterns, stopDir) {
1073
1119
  finally {
1074
1120
  inFlight.delete(dirKey);
1075
1121
  }
1076
- };
1122
+ }, includePatterns);
1077
1123
  }
1078
1124
  /** Alias kept for backward compatibility */
1079
1125
  export const createRootDetector = NearestRoot;
@@ -1579,7 +1625,7 @@ async function hasAgentLevelProjectMarker(extensionRootKey) {
1579
1625
  }
1580
1626
  return false;
1581
1627
  }
1582
- const TypeScriptRoot = DenoExcludeRoot(async (file) => {
1628
+ const TypeScriptRoot = withRootMarkers(DenoExcludeRoot(async (file) => {
1583
1629
  const extensionRootKey = piAgentExtensionsRootKey(file);
1584
1630
  if (extensionRootKey) {
1585
1631
  // Bounded walk so we never adopt a parent (e.g. ~/.pi/agent/) as the
@@ -1603,13 +1649,14 @@ const TypeScriptRoot = DenoExcludeRoot(async (file) => {
1603
1649
  if (projectRoot)
1604
1650
  return projectRoot;
1605
1651
  return FileDirRoot(file);
1606
- });
1652
+ }), [...TS_CONFIG_MARKERS, ...TS_TOOLING_MARKERS]);
1607
1653
  export const TypeScriptServer = {
1608
1654
  id: "typescript",
1609
1655
  name: "TypeScript Language Server",
1610
1656
  extensions: JS_TS_LSP_EXTENSIONS,
1611
1657
  autoPropagateDiagnostics: true,
1612
1658
  root: TypeScriptRoot,
1659
+ rootMarkers: TypeScriptRoot.rootMarkers,
1613
1660
  async spawn(root, options) {
1614
1661
  const fs = await import("node:fs/promises");
1615
1662
  const nativeLsp = await findNativeTypeScriptLsp(root);
@@ -1919,7 +1966,7 @@ function sessionHoistCeiling(sessionCwd, file) {
1919
1966
  }
1920
1967
  function RustWorkspaceRoot() {
1921
1968
  const crateRoot = createRootDetector(["Cargo.toml", "Cargo.lock"]);
1922
- return async (file) => {
1969
+ return withRootMarkers(async (file) => {
1923
1970
  const root = await crateRoot(file);
1924
1971
  if (!root)
1925
1972
  return undefined;
@@ -1958,7 +2005,7 @@ function RustWorkspaceRoot() {
1958
2005
  current = parent;
1959
2006
  }
1960
2007
  return root;
1961
- };
2008
+ }, crateRoot.rootMarkers ?? []);
1962
2009
  }
1963
2010
  /**
1964
2011
  * Resolve whether `parentPomPath`'s <modules> block declares `childDir` as one
@@ -2011,7 +2058,7 @@ function JavaWorkspaceRoot() {
2011
2058
  "build.gradle",
2012
2059
  ".classpath",
2013
2060
  ]);
2014
- return async (file) => {
2061
+ return withRootMarkers(async (file) => {
2015
2062
  const root = await moduleRoot(file);
2016
2063
  if (!root)
2017
2064
  return undefined;
@@ -2051,7 +2098,7 @@ function JavaWorkspaceRoot() {
2051
2098
  current = parent;
2052
2099
  }
2053
2100
  return enforceLspRootCeiling(lastHop, sessionCwd, file);
2054
- };
2101
+ }, moduleRoot.rootMarkers ?? []);
2055
2102
  }
2056
2103
  export const RustServer = {
2057
2104
  id: "rust",
@@ -16,7 +16,6 @@
16
16
  * always sent, so an unrecognized/absent value never regresses `Full`/`None`
17
17
  * behavior.
18
18
  */
19
- export const TEXT_DOCUMENT_SYNC_KIND_NONE = 0;
20
19
  export const TEXT_DOCUMENT_SYNC_KIND_FULL = 1;
21
20
  export const TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL = 2;
22
21
  function isSyncKind(value) {
@@ -37,7 +37,7 @@ import { normalizeMapKey } from "../path-utils.js";
37
37
  // ---------------------------------------------------------------------------
38
38
  // Constants
39
39
  // ---------------------------------------------------------------------------
40
- export const TSSERVER_REQUEST_COMMAND = "typescript.tsserverRequest";
40
+ const TSSERVER_REQUEST_COMMAND = "typescript.tsserverRequest";
41
41
  /**
42
42
  * tsserver's synthetic inferred-project name, as its own source builds it:
43
43
  * `"/dev/null/inferredProject" + counter + "*"`. `/dev/null` is a deliberate
@@ -219,13 +219,13 @@ export async function fetchTsserverProjectIdentity(svc, file) {
219
219
  // ---------------------------------------------------------------------------
220
220
  // Helpers
221
221
  // ---------------------------------------------------------------------------
222
- export function isTsserverSyncRawDiagnostic(value) {
222
+ function isTsserverSyncRawDiagnostic(value) {
223
223
  if (!value || typeof value !== "object")
224
224
  return false;
225
225
  const v = value;
226
226
  return typeof v.message === "string" && typeof v.category === "string";
227
227
  }
228
- export function tsserverSeverityFromCategory(category) {
228
+ function tsserverSeverityFromCategory(category) {
229
229
  switch (category) {
230
230
  case "error":
231
231
  return 1;
@@ -242,7 +242,7 @@ export function tsserverSeverityFromCategory(category) {
242
242
  * `LSPDiagnostic`. Both `line`/`offset` are 1-based in tsserver's protocol
243
243
  * and 0-based in LSP — this conversion handles that.
244
244
  */
245
- export function tsserverSyncDiagnosticToLsp(d) {
245
+ function tsserverSyncDiagnosticToLsp(d) {
246
246
  const startLine = Math.max(0, (d.startLocation?.line ?? 1) - 1);
247
247
  const startChar = Math.max(0, (d.startLocation?.offset ?? 1) - 1);
248
248
  const endLine = Math.max(0, (d.endLocation?.line ?? d.startLocation?.line ?? 1) - 1);
@@ -265,7 +265,7 @@ export function tsserverSyncDiagnosticToLsp(d) {
265
265
  * executed, the response envelope isn't `{success:true, body:[...]}`, or
266
266
  * any error is thrown.
267
267
  */
268
- export async function runTsserverSyncCommand(svc, file, command) {
268
+ async function runTsserverSyncCommand(svc, file, command) {
269
269
  if (typeof svc.executeCommand !== "function")
270
270
  return undefined;
271
271
  const outcome = await svc.executeCommand(file, TSSERVER_REQUEST_COMMAND, [
@@ -24,6 +24,12 @@ export function classifyServerWaitTier(serverId, snapshot) {
24
24
  const mode = snapshot.workspaceDiagnosticsSupport?.mode;
25
25
  if (mode === "pull")
26
26
  return "pull-capable";
27
+ if (snapshot.customServer === true &&
28
+ mode === "push-only" &&
29
+ snapshot.diagnosticsUnsupported === true &&
30
+ snapshot.diagnosticsPublished !== true) {
31
+ return "diagnostics-unsupported";
32
+ }
27
33
  if (mode !== "push-only")
28
34
  return "waits";
29
35
  const strategy = getStrategy(serverId, snapshot.launchVariant);
@@ -73,6 +73,7 @@ export function resolveAstGrepNativeExe(platform = process.platform, arch = proc
73
73
  return undefined;
74
74
  }
75
75
  }
76
+ /** @public — loaded by scripts/probe-clean-signal.mjs through a dynamic import wrapper knip cannot see. */
76
77
  export const SERVER_DIAGNOSTIC_STRATEGIES = {
77
78
  typescript: {
78
79
  seedFirstPush: true,
@@ -287,7 +288,7 @@ const NATIVE_TS7_DIAGNOSTIC_STRATEGY = {
287
288
  silentOnClean: false,
288
289
  };
289
290
  /** Fallback for unknown servers. Conservative defaults. */
290
- export const DEFAULT_STRATEGY = {
291
+ const DEFAULT_STRATEGY = {
291
292
  seedFirstPush: false,
292
293
  pullRetryBudgetMs: 250,
293
294
  debounceMs: 150,
@@ -8,6 +8,7 @@ import { normalizeMapKey } from "../path-utils.js";
8
8
  import { loadReverseDependencyIndexFromSnapshot } from "../reverse-deps.js";
9
9
  import { freshnessFromMtime } from "../freshness.js";
10
10
  import { logLatency } from "../latency-logger.js";
11
+ import { recordDegradationOnce } from "../degradation-ledger.js";
11
12
  import { compareOrdinal } from "../string-utils.js";
12
13
  import { workspaceDiagnosticsCacheSessionStart } from "./workspace-diagnostics-session.js";
13
14
  import { createDiskBindingCache, } from "./diagnostic-binding.js";
@@ -31,12 +32,17 @@ import { createDiskBindingCache, } from "./diagnostic-binding.js";
31
32
  * `LSPWorkspaceDiagnosticResult.timedOut` in `./index.ts`) into
32
33
  * `WorkspaceDiagnosticsCacheEntry`.
33
34
  */
35
+ // v3 (#2776): cached diagnostics must carry per-diagnostic `serverId`
36
+ // provenance before replay, because primary/auxiliary partitioning is
37
+ // server-owned rather than source-owned. v2 entries predate that contract and
38
+ // are rejected so the owning server can re-collect them instead of silently
39
+ // demoting old primary findings to auxiliary.
34
40
  // v2 (#1095): entries may carry an optional `contentHash` fingerprint of the
35
41
  // file bytes the cached diagnostics were computed against, so a `lookup` can
36
42
  // surface a content `binding` (boundToCurrentDisk) beyond the mtime proxy.
37
43
  // Legacy v1 entries are rejected by the version guard and re-scanned — a
38
44
  // deliberately clean break so no entry lacking the field is ever served.
39
- export const WORKSPACE_DIAGNOSTICS_CACHE_VERSION = 2;
45
+ export const WORKSPACE_DIAGNOSTICS_CACHE_VERSION = 3;
40
46
  const CACHE_FILE = "lsp-workspace-diagnostics.json";
41
47
  function cachePath(cwd) {
42
48
  return path.join(getProjectDataDir(cwd), "cache", CACHE_FILE);
@@ -161,11 +167,34 @@ export function loadWorkspaceDiagnosticsCache(cwd) {
161
167
  if (!parsed || typeof parsed !== "object")
162
168
  return undefined;
163
169
  const cache = parsed;
164
- if (cache.version !== WORKSPACE_DIAGNOSTICS_CACHE_VERSION)
170
+ if (cache.version !== WORKSPACE_DIAGNOSTICS_CACHE_VERSION) {
171
+ if (cache.version === 1 || cache.version === 2) {
172
+ recordDegradationOnce({
173
+ kind: "lsp-workspace-cache-migration",
174
+ subject: path.resolve(cwd),
175
+ reason: `rejected v${cache.version} cache with ${cache.entries && typeof cache.entries === "object"
176
+ ? Object.keys(cache.entries).length
177
+ : 0} entries during provenance migration`,
178
+ });
179
+ }
165
180
  return undefined;
181
+ }
166
182
  if (!cache.entries || typeof cache.entries !== "object")
167
183
  return undefined;
168
- return cache;
184
+ const validEntries = {};
185
+ for (const [key, entry] of Object.entries(cache.entries)) {
186
+ if (!entry || typeof entry !== "object")
187
+ continue;
188
+ if (!Array.isArray(entry.diagnostics) ||
189
+ entry.diagnostics.some((diagnostic) => !diagnostic ||
190
+ typeof diagnostic !== "object" ||
191
+ typeof diagnostic.serverId !== "string" ||
192
+ diagnostic.serverId.length === 0)) {
193
+ continue;
194
+ }
195
+ validEntries[key] = entry;
196
+ }
197
+ return { ...cache, entries: validEntries };
169
198
  });
170
199
  }
171
200
  export function saveWorkspaceDiagnosticsCache(cwd, cache) {
@@ -470,6 +499,9 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
470
499
  depIndexColdRefusalCount = 0;
471
500
  };
472
501
  return {
502
+ importsFor(filePath) {
503
+ return getImports(filePath);
504
+ },
473
505
  lookup(filePath, scopeKey) {
474
506
  // #1669 review N4: the epoch guarded `persist()` but not `lookup()` —
475
507
  // an in-flight sweep kept REPLAYING disowned entries into its OWN
@@ -552,11 +584,12 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
552
584
  };
553
585
  },
554
586
  record(filePath, scopeKey, diagnostics, mtimeMs, contentHash, sizeBytes) {
587
+ const scanGeneration = Date.now();
555
588
  entries[cacheKeyFor(filePath)] = {
556
589
  diagnostics,
557
590
  count: diagnostics.length,
558
591
  mtimeMs,
559
- scannedAt: Date.now(),
592
+ scannedAt: scanGeneration,
560
593
  scopeKey,
561
594
  // #1793: stamp whether THIS FILE actually had dependency
562
595
  // knowledge this sweep (not just whether SOME index was
@@ -2,7 +2,7 @@ import { getLSPService } from "./lsp/index.js";
2
2
  // Grounded against this repo's workspace-native TypeScript 7.0.2 server
3
3
  // (`tsc --lsp --stdio`) on 2026-07-30: 20 already-open documentSymbol calls
4
4
  // measured p50 3.70 ms / p95 5.28 ms. Keep generous headroom for slower hosts.
5
- export const LSP_DOCUMENT_SYMBOL_TIMEOUT_MS = 150;
5
+ const LSP_DOCUMENT_SYMBOL_TIMEOUT_MS = 150;
6
6
  export const SYMBOL_KIND_NAMES = {
7
7
  1: "file",
8
8
  2: "module",
@@ -367,6 +367,9 @@ export async function analyzeFile(filePath, cwd, options = {}) {
367
367
  const lspRunner = latencyReport?.runners.find((runner) => runner.runnerId === "lsp");
368
368
  const lsp = lspRunner
369
369
  ? {
370
+ // `deferred` means the runner entered the LSP path but its auxiliary
371
+ // coverage is delivered later, so it still counts as ran here. The
372
+ // status remains available to surfaces that need the coverage detail.
370
373
  ran: lspRunner.status !== "skipped" &&
371
374
  lspRunner.status !== "when_skipped" &&
372
375
  lspRunner.status !== "test_file_skipped",
@@ -30,6 +30,7 @@ import { RuntimeCoordinator } from "../runtime-coordinator.js";
30
30
  import { handleSessionStart } from "../runtime-session.js";
31
31
  import { handleTurnEnd } from "../runtime-turn.js";
32
32
  import { createMcpHost } from "./host-shim.js";
33
+ import { startSituationalToolTelemetrySession } from "../situational-tool-telemetry.js";
33
34
  let contextPromise;
34
35
  let resolvedRuntime;
35
36
  /**
@@ -79,6 +80,7 @@ function joinMessages(consumed) {
79
80
  * `pilens_health` afterwards for the scan results as they land.
80
81
  */
81
82
  export async function runSessionStart(cwd) {
83
+ startSituationalToolTelemetrySession("mcp");
82
84
  const ctx = await getMcpSessionContext();
83
85
  const host = createMcpHost(undefined, cwd);
84
86
  await handleSessionStart({
@@ -93,7 +93,7 @@ export function loadHistory() {
93
93
  /**
94
94
  * Save history to disk
95
95
  */
96
- export function saveHistory(history) {
96
+ function saveHistory(history) {
97
97
  const historyDir = getProjectDataDir(process.cwd());
98
98
  if (!fs.existsSync(historyDir)) {
99
99
  fs.mkdirSync(historyDir, { recursive: true });
@@ -161,10 +161,35 @@ export function captureSnapshot(filePath, metrics) {
161
161
  }, SAVE_DEBOUNCE_MS);
162
162
  saveTimer.unref?.();
163
163
  }
164
+ // --- Trend Analysis ---
164
165
  /**
165
- * Capture snapshots for multiple files (explicit, immediate save)
166
- * Used by /lens-metrics for batch capture
166
+ * Compute trend direction from history snapshots
167
+ * Uses last 3 snapshots for stability (or 2 if only 2 available)
167
168
  */
169
+ function computeTrend(history) {
170
+ if (history.length < 2)
171
+ return "stable";
172
+ const recent = history.slice(-3);
173
+ const first = recent[0];
174
+ const last = recent[recent.length - 1];
175
+ // Use MI as primary indicator, cognitive as secondary
176
+ const miDelta = last.mi - first.mi;
177
+ const cogDelta = last.cognitive - first.cognitive;
178
+ // Thresholds (MI changes < 2 are noise)
179
+ if (miDelta > 2)
180
+ return "improving";
181
+ if (miDelta < -2)
182
+ return "regressing";
183
+ // If MI is stable, check cognitive
184
+ if (cogDelta < -10)
185
+ return "improving";
186
+ if (cogDelta > 10)
187
+ return "regressing";
188
+ return "stable";
189
+ }
190
+ // --- Technical Debt Index (TDI) ---
191
+ // Test-reached through a child-process `require` string
192
+ /** @public — reached through a child-process `require` string in tests/clients/metrics-history-stderr.test.ts; knip cannot see it. */
168
193
  export function captureSnapshots(files) {
169
194
  const history = loadHistory();
170
195
  for (const file of files) {
@@ -200,110 +225,6 @@ export function captureSnapshots(files) {
200
225
  saveHistory(history);
201
226
  return history;
202
227
  }
203
- // --- Trend Analysis ---
204
- /**
205
- * Compute trend direction from history snapshots
206
- * Uses last 3 snapshots for stability (or 2 if only 2 available)
207
- */
208
- export function computeTrend(history) {
209
- if (history.length < 2)
210
- return "stable";
211
- const recent = history.slice(-3);
212
- const first = recent[0];
213
- const last = recent[recent.length - 1];
214
- // Use MI as primary indicator, cognitive as secondary
215
- const miDelta = last.mi - first.mi;
216
- const cogDelta = last.cognitive - first.cognitive;
217
- // Thresholds (MI changes < 2 are noise)
218
- if (miDelta > 2)
219
- return "improving";
220
- if (miDelta < -2)
221
- return "regressing";
222
- // If MI is stable, check cognitive
223
- if (cogDelta < -10)
224
- return "improving";
225
- if (cogDelta > 10)
226
- return "regressing";
227
- return "stable";
228
- }
229
- /**
230
- * Get delta between current snapshot and previous
231
- */
232
- export function getDelta(history) {
233
- if (!history || history.history.length < 2)
234
- return null;
235
- const current = history.history[history.history.length - 1];
236
- const previous = history.history[history.history.length - 2];
237
- return {
238
- mi: Math.round((current.mi - previous.mi) * 10) / 10,
239
- cognitive: current.cognitive - previous.cognitive,
240
- trend: history.trend,
241
- };
242
- }
243
- /**
244
- * Get trend emoji for display
245
- */
246
- export function getTrendEmoji(trend) {
247
- switch (trend) {
248
- case "improving":
249
- return "📈";
250
- case "regressing":
251
- return "📉";
252
- default:
253
- return "➡️";
254
- }
255
- }
256
- /**
257
- * Get trend summary across all files
258
- */
259
- export function getTrendSummary(history) {
260
- let improving = 0;
261
- let regressing = 0;
262
- let stable = 0;
263
- const regressions = [];
264
- for (const [file, fileHistory] of Object.entries(history.files)) {
265
- switch (fileHistory.trend) {
266
- case "improving":
267
- improving++;
268
- break;
269
- case "regressing": {
270
- regressing++;
271
- const delta = getDelta(fileHistory);
272
- if (delta) {
273
- regressions.push({ file, miDelta: delta.mi });
274
- }
275
- break;
276
- }
277
- default:
278
- stable++;
279
- }
280
- }
281
- // Sort regressions by MI delta (worst first)
282
- regressions.sort((a, b) => a.miDelta - b.miDelta);
283
- return {
284
- improving,
285
- regressing,
286
- stable,
287
- worstRegressions: regressions.slice(0, 5),
288
- };
289
- }
290
- /**
291
- * Format trend for metrics table
292
- */
293
- export function formatTrendCell(filePath, history) {
294
- const relativePath = path.relative(process.cwd(), filePath);
295
- const fileHistory = history.files[relativePath];
296
- if (!fileHistory || fileHistory.history.length < 2) {
297
- return "—"; // No history
298
- }
299
- const delta = getDelta(fileHistory);
300
- if (!delta)
301
- return "—";
302
- const emoji = getTrendEmoji(delta.trend);
303
- const miSign = delta.mi > 0 ? "+" : "";
304
- const miColor = delta.mi > 0 ? "🟢" : delta.mi < 0 ? "🔴" : "⚪";
305
- return `${emoji} ${miColor}${miSign}${delta.mi}`;
306
- }
307
228
  /**
308
229
  * Calculate Technical Debt Index for the project.
309
230
  * Score: 0 = perfect, 100 = maximum debt.
@@ -159,7 +159,7 @@ function isAccessorLine(rawLine) {
159
159
  * extracted data — no re-parsing, no file I/O beyond the lines already read
160
160
  * by the caller.
161
161
  */
162
- export function analyzeMiddleMan(classEntry, lines, languageId) {
162
+ function analyzeMiddleMan(classEntry, lines, languageId) {
163
163
  if (!languageId)
164
164
  return undefined;
165
165
  const selfSpec = SELF_TOKEN[languageId];
@@ -48,7 +48,7 @@ import { symbolExtractionGrammar, TreeSitterSymbolExtractor, } from "./tree-sitt
48
48
  // lsp.ts) to be re-homed in #236, where LSP writes provenance-tagged edges INTO
49
49
  // the review graph (computed once, persisted) so this path just reads them.
50
50
  /** Hard payload bound for the per-symbol who-uses-this section. */
51
- export const MAX_MODULE_REPORT_REFS = 100;
51
+ const MAX_MODULE_REPORT_REFS = 100;
52
52
  function normalizeMaxRefsPerSymbol(value) {
53
53
  if (value === undefined || !Number.isFinite(value))
54
54
  return 10;
@@ -113,7 +113,7 @@ function asRecord(value) {
113
113
  * field list the seam classifies with — a second spelling list would arm on
114
114
  * inputs the seam cannot resolve, and miss ones it can.
115
115
  */
116
- export function resolveMutationPath(input) {
116
+ function resolveMutationPath(input) {
117
117
  for (const key of ["path", "filePath", "file_path"]) {
118
118
  const value = input[key];
119
119
  if (typeof value === "string" && value.length > 0)
@@ -141,7 +141,7 @@ export function readMutationPathField(event) {
141
141
  * base62 anchor — handled by `clients/hashline-anchor.ts`. Do not reach for
142
142
  * this function there.
143
143
  */
144
- export function parseHashlineAnchor(anchor) {
144
+ function parseHashlineAnchor(anchor) {
145
145
  if (typeof anchor !== "string")
146
146
  return undefined;
147
147
  const trimmed = anchor.trim();
@@ -153,7 +153,7 @@ export function parseHashlineAnchor(anchor) {
153
153
  return Number.isInteger(line) && line > 0 ? line : undefined;
154
154
  }
155
155
  /** Bounding box plus per-range detail for a multi-range edit. */
156
- export function combineRanges(ranges) {
156
+ function combineRanges(ranges) {
157
157
  const starts = ranges.map(([start]) => start);
158
158
  const ends = ranges.map(([, end]) => end);
159
159
  return {