@herbertgao/pi-extensions 2026.8.11 → 2026.8.13

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 (476) hide show
  1. package/README.md +23 -10
  2. package/{node_modules/@herbertgao/pi-mermaid-open/LICENSE → THIRD_PARTY_NOTICES.md} +19 -1
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +15 -0
  4. package/node_modules/@czottmann/pi-automode/README.md +5 -3
  5. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +2 -0
  6. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-002-global-config-in-extension-data-directory.md +60 -0
  7. package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +1 -0
  8. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +4 -4
  9. package/node_modules/@czottmann/pi-automode/docs/configuration.md +20 -4
  10. package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +1 -1
  11. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/bash.ts +692 -0
  12. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +181 -3
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +4 -1
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +143 -36
  15. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +103 -148
  16. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +32 -6
  17. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +344 -22
  18. package/node_modules/@czottmann/pi-automode/extensions/auto-mode.ts +1 -0
  19. package/node_modules/@czottmann/pi-automode/package.json +4 -1
  20. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -1
  21. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -1
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +4 -0
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +21 -1
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +1 -1
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +19 -19
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +4 -2
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +2 -1
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +10 -2
  29. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  30. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +10 -0
  31. package/node_modules/@herbertgao/pi-subagents/README.md +21 -15
  32. package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
  33. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +11 -8
  34. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +184 -106
  35. package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +31 -11
  36. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +9 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/index.ts +156 -31
  38. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +17 -0
  39. package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +14 -0
  40. package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +8 -0
  41. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +32 -1
  42. package/node_modules/@herbertgao/pi-subagents/src/types.ts +17 -2
  43. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +23 -2
  44. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +259 -24
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  46. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +376 -0
  47. package/node_modules/@luxusai/pi-hindsight/README.md +92 -0
  48. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +56 -0
  49. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +169 -0
  50. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +107 -0
  51. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +89 -0
  52. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +189 -0
  53. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  54. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  55. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +54 -0
  56. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +75 -0
  57. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +300 -0
  58. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +158 -0
  59. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +164 -0
  60. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +139 -0
  61. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +74 -0
  62. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +261 -0
  63. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +151 -0
  64. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +18 -0
  65. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +46 -0
  66. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +383 -0
  67. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +240 -0
  68. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +176 -0
  69. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +178 -0
  70. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +41 -0
  71. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +386 -0
  72. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +39 -0
  73. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +34 -0
  74. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +140 -0
  75. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +61 -0
  76. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +925 -0
  77. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +247 -0
  78. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +547 -0
  79. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +480 -0
  80. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +182 -0
  81. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +86 -0
  82. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +1010 -0
  83. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +175 -0
  84. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +425 -0
  85. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +210 -0
  86. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +817 -0
  87. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +25 -0
  88. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +319 -0
  89. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +196 -0
  90. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +189 -0
  91. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +65 -0
  92. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +260 -0
  93. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +244 -0
  94. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +59 -0
  95. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +82 -0
  96. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +45 -0
  97. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +331 -0
  98. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +354 -0
  99. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +66 -0
  100. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +132 -0
  101. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +228 -0
  102. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +74 -0
  103. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +16 -0
  104. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +648 -0
  105. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +105 -0
  106. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +68 -0
  107. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +71 -0
  108. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +13 -0
  109. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +162 -0
  110. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +131 -0
  111. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +104 -0
  112. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +37 -0
  113. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +893 -0
  114. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +35 -0
  115. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +177 -0
  116. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +7 -0
  117. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +21 -0
  118. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +112 -0
  119. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +111 -0
  120. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +214 -0
  121. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +70 -0
  122. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +392 -0
  123. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +45 -0
  124. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +9 -0
  125. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +860 -0
  126. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +105 -0
  127. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +189 -0
  128. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +299 -0
  129. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +201 -0
  130. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +47 -0
  131. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +239 -0
  132. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +50 -0
  133. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +259 -0
  134. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +77 -0
  135. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +534 -0
  136. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +319 -0
  137. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +325 -0
  138. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +42 -0
  139. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +244 -0
  140. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +56 -0
  141. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +50 -0
  142. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +167 -0
  143. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +207 -0
  144. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +120 -0
  145. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +8 -0
  146. package/node_modules/@luxusai/pi-hindsight/package.json +118 -0
  147. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +75 -0
  148. package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -46
  149. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  150. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  151. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +136 -22
  152. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/README.md +2 -4
  153. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/package.json +5 -15
  154. package/node_modules/{@herbertgao → @tifan}/pi-handoff/README.md +4 -6
  155. package/node_modules/@tifan/pi-handoff/package.json +43 -0
  156. package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/index.ts +1 -1
  157. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/README.md +2 -4
  158. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/package.json +5 -15
  159. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/README.md +5 -7
  160. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/package.json +5 -19
  161. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/README.md +4 -6
  162. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/package.json +6 -16
  163. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/src/index.ts +1 -6
  164. package/node_modules/{@herbertgao → @tifan}/pi-recap/README.md +4 -6
  165. package/node_modules/@tifan/pi-recap/package.json +42 -0
  166. package/node_modules/{@herbertgao → @tifan}/pi-recap/src/models.ts +1 -6
  167. package/node_modules/{@herbertgao → @tifan}/pi-rename/README.md +13 -8
  168. package/node_modules/@tifan/pi-rename/package.json +47 -0
  169. package/node_modules/@tifan/pi-rename/src/herdr-label.ts +4 -0
  170. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/index.ts +4 -16
  171. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/models.ts +1 -6
  172. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/README.md +2 -4
  173. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/package.json +5 -15
  174. package/node_modules/pi-lens/CHANGELOG.md +96 -1
  175. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +14 -5
  177. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +48 -18
  178. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -3
  179. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +16 -4
  180. package/node_modules/pi-lens/dist/clients/bash-file-access.js +3 -1
  181. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -3
  182. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +21 -8
  183. package/node_modules/pi-lens/dist/clients/bounded-cache.js +24 -8
  184. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +4 -3
  185. package/node_modules/pi-lens/dist/clients/cache-manager.js +6 -7
  186. package/node_modules/pi-lens/dist/clients/cache-observability.js +461 -66
  187. package/node_modules/pi-lens/dist/clients/call-graph.js +238 -63
  188. package/node_modules/pi-lens/dist/clients/codebase-model.js +13 -5
  189. package/node_modules/pi-lens/dist/clients/complexity-client.js +1 -3
  190. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -8
  191. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +1 -2
  192. package/node_modules/pi-lens/dist/clients/deadline-utils.js +3 -1
  193. package/node_modules/pi-lens/dist/clients/debug-heap.js +8 -1
  194. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +1 -1
  195. package/node_modules/pi-lens/dist/clients/dependency-checker.js +11 -7
  196. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -2
  197. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +5 -1
  198. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +2 -3
  199. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +13 -1
  200. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +3 -1
  201. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +2 -1
  202. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -4
  204. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +3 -1
  205. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +6 -2
  206. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +31 -7
  207. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +5 -2
  208. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +10 -14
  209. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +5 -1
  210. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +1 -1
  211. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +3 -1
  212. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +25 -6
  213. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +1 -1
  214. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +1 -1
  215. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +3 -1
  216. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +13 -8
  217. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +4 -1
  218. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +25 -10
  219. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +1 -1
  220. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +1 -1
  221. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +1 -1
  222. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +28 -4
  223. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +6 -8
  224. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +212 -11
  225. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +1 -1
  226. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +8 -4
  227. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -6
  228. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +23 -14
  229. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -1
  230. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +7 -9
  231. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +7 -7
  233. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +6 -8
  234. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +13 -8
  235. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +13 -8
  236. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +17 -3
  237. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +7 -1
  238. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +24 -1
  239. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +35 -0
  240. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +1 -3
  241. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +6 -8
  242. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +1 -1
  243. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +2 -1
  244. package/node_modules/pi-lens/dist/clients/dispatch/types.js +6 -1
  245. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +6 -2
  246. package/node_modules/pi-lens/dist/clients/extension-log.js +5 -3
  247. package/node_modules/pi-lens/dist/clients/feature-hints.js +8 -1
  248. package/node_modules/pi-lens/dist/clients/file-kinds.js +34 -129
  249. package/node_modules/pi-lens/dist/clients/file-utils.js +17 -1
  250. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +57 -2
  251. package/node_modules/pi-lens/dist/clients/formatters.js +144 -27
  252. package/node_modules/pi-lens/dist/clients/freshness.js +38 -0
  253. package/node_modules/pi-lens/dist/clients/git-guard.js +43 -13
  254. package/node_modules/pi-lens/dist/clients/go-client.js +1 -3
  255. package/node_modules/pi-lens/dist/clients/grammar-source.js +1 -1
  256. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +30 -4
  257. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +1 -3
  258. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +4 -2
  259. package/node_modules/pi-lens/dist/clients/installer/index.js +86 -77
  260. package/node_modules/pi-lens/dist/clients/instance-reaper.js +5 -2
  261. package/node_modules/pi-lens/dist/clients/instance-registry.js +4 -2
  262. package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
  263. package/node_modules/pi-lens/dist/clients/knip-client.js +29 -15
  264. package/node_modules/pi-lens/dist/clients/language-profile.js +4 -1
  265. package/node_modules/pi-lens/dist/clients/latency-logger.js +13 -2
  266. package/node_modules/pi-lens/dist/clients/lens-config.js +1 -1
  267. package/node_modules/pi-lens/dist/clients/lens-map.js +8 -3
  268. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +1 -1
  269. package/node_modules/pi-lens/dist/clients/lsp/config.js +4 -6
  270. package/node_modules/pi-lens/dist/clients/lsp/edits.js +119 -32
  271. package/node_modules/pi-lens/dist/clients/lsp/index.js +94 -35
  272. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +2 -1
  273. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +4 -1
  274. package/node_modules/pi-lens/dist/clients/lsp/launch.js +11 -3
  275. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +152 -0
  276. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -7
  277. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +10 -2
  278. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +9 -4
  279. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -3
  280. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +10 -20
  281. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +1 -1
  282. package/node_modules/pi-lens/dist/clients/memory-sampler.js +73 -7
  283. package/node_modules/pi-lens/dist/clients/metrics-client.js +1 -3
  284. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +8 -3
  285. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +7 -1
  286. package/node_modules/pi-lens/dist/clients/module-report.js +14 -17
  287. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +3 -5
  288. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +220 -0
  289. package/node_modules/pi-lens/dist/clients/package-manager.js +6 -1
  290. package/node_modules/pi-lens/dist/clients/pipeline.js +57 -9
  291. package/node_modules/pi-lens/dist/clients/project-conventions.js +2 -8
  292. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +10 -7
  293. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +2 -1
  294. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +3 -1
  295. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +13 -9
  296. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +3 -1
  297. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -2
  298. package/node_modules/pi-lens/dist/clients/project-lens-config.js +12 -5
  299. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +48 -0
  300. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +15 -1
  301. package/node_modules/pi-lens/dist/clients/project-snapshot.js +472 -66
  302. package/node_modules/pi-lens/dist/clients/read-expansion.js +12 -2
  303. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +5 -4
  304. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +5 -2
  305. package/node_modules/pi-lens/dist/clients/read-guard.js +1 -1
  306. package/node_modules/pi-lens/dist/clients/resource-sampler.js +1 -1
  307. package/node_modules/pi-lens/dist/clients/reverse-deps.js +6 -5
  308. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +42 -17
  309. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +8 -2
  310. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +10 -1
  311. package/node_modules/pi-lens/dist/clients/review-graph/query.js +2 -1
  312. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +4 -2
  313. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +2 -2
  314. package/node_modules/pi-lens/dist/clients/ruff-client.js +6 -5
  315. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +63 -31
  316. package/node_modules/pi-lens/dist/clients/runtime-context.js +12 -4
  317. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +83 -4
  318. package/node_modules/pi-lens/dist/clients/runtime-session.js +14 -0
  319. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +59 -3
  320. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +148 -34
  321. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -6
  322. package/node_modules/pi-lens/dist/clients/rust-client.js +1 -3
  323. package/node_modules/pi-lens/dist/clients/safe-spawn.js +150 -11
  324. package/node_modules/pi-lens/dist/clients/security-scan-client.js +1 -3
  325. package/node_modules/pi-lens/dist/clients/session-summary.js +3 -1
  326. package/node_modules/pi-lens/dist/clients/sg-runner.js +1 -3
  327. package/node_modules/pi-lens/dist/clients/source-filter.js +10 -6
  328. package/node_modules/pi-lens/dist/clients/source-walker.js +1 -1
  329. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +96 -0
  330. package/node_modules/pi-lens/dist/clients/startup-scan.js +4 -1
  331. package/node_modules/pi-lens/dist/clients/tool-definition.js +7 -0
  332. package/node_modules/pi-lens/dist/clients/tool-policy.js +26 -11
  333. package/node_modules/pi-lens/dist/clients/tool-render.js +2 -1
  334. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +10 -4
  335. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  336. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +12 -5
  337. package/node_modules/pi-lens/dist/clients/warm-attach.js +12 -5
  338. package/node_modules/pi-lens/dist/clients/widget-state.js +27 -11
  339. package/node_modules/pi-lens/dist/clients/word-index.js +3 -1
  340. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -2
  341. package/node_modules/pi-lens/dist/clients/zizmor-config.js +9 -1
  342. package/node_modules/pi-lens/dist/i18n.js +13 -5
  343. package/node_modules/pi-lens/dist/index.js +10797 -8627
  344. package/node_modules/pi-lens/dist/mcp/server.js +3 -1
  345. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +68 -12
  346. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +21 -7
  347. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +164 -35
  348. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +24 -7
  349. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
  350. package/node_modules/pi-lens/dist/tools/module-report.js +1 -1
  351. package/node_modules/pi-lens/dist/tools/project-report.js +1 -1
  352. package/node_modules/pi-lens/dist/tools/symbol-search.js +5 -2
  353. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +1 -1
  354. package/node_modules/pi-lens/docs/servercapabilities.md +1 -1
  355. package/node_modules/pi-lens/package.json +160 -156
  356. package/node_modules/pi-lens/rules/typos/_typos.toml +2 -2
  357. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +31 -13
  358. package/node_modules/pi-lens/scripts/download-grammars.js +9 -3
  359. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +30 -9
  360. package/node_modules/pi-mcp-adapter/CHANGELOG.md +47 -0
  361. package/node_modules/pi-mcp-adapter/README.md +42 -13
  362. package/node_modules/pi-mcp-adapter/commands.ts +4 -2
  363. package/node_modules/pi-mcp-adapter/config.ts +45 -5
  364. package/node_modules/pi-mcp-adapter/direct-tools.ts +103 -92
  365. package/node_modules/pi-mcp-adapter/dist/agent-dir.d.ts +10 -0
  366. package/node_modules/pi-mcp-adapter/dist/agent-dir.js +63 -0
  367. package/node_modules/pi-mcp-adapter/dist/agent-dir.js.map +1 -0
  368. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.d.ts +8 -0
  369. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js +356 -0
  370. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js.map +1 -0
  371. package/node_modules/pi-mcp-adapter/dist/config.d.ts +123 -0
  372. package/node_modules/pi-mcp-adapter/dist/config.js +1087 -0
  373. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -0
  374. package/node_modules/pi-mcp-adapter/dist/metadata-cache.d.ts +19 -0
  375. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +319 -0
  376. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -0
  377. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.d.ts +2 -0
  378. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js +156 -0
  379. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js.map +1 -0
  380. package/node_modules/pi-mcp-adapter/dist/resource-tools.d.ts +1 -0
  381. package/node_modules/pi-mcp-adapter/dist/resource-tools.js +15 -0
  382. package/node_modules/pi-mcp-adapter/dist/resource-tools.js.map +1 -0
  383. package/node_modules/pi-mcp-adapter/dist/types.d.ts +564 -0
  384. package/node_modules/pi-mcp-adapter/dist/types.js +287 -0
  385. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -0
  386. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.d.ts +6 -0
  387. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js +37 -0
  388. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js.map +1 -0
  389. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.d.ts +104 -0
  390. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js +59 -0
  391. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js.map +1 -0
  392. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.d.ts +4 -0
  393. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js +27 -0
  394. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js.map +1 -0
  395. package/node_modules/pi-mcp-adapter/dist/utils.d.ts +32 -0
  396. package/node_modules/pi-mcp-adapter/dist/utils.js +338 -0
  397. package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -0
  398. package/node_modules/pi-mcp-adapter/failure-backoff.ts +23 -0
  399. package/node_modules/pi-mcp-adapter/index.ts +204 -82
  400. package/node_modules/pi-mcp-adapter/init.ts +41 -30
  401. package/node_modules/pi-mcp-adapter/lifecycle.ts +16 -8
  402. package/node_modules/pi-mcp-adapter/mcp-code.ts +2 -0
  403. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +66 -16
  404. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +95 -7
  405. package/node_modules/pi-mcp-adapter/mcp-probe.ts +18 -4
  406. package/node_modules/pi-mcp-adapter/mcp-references.ts +368 -0
  407. package/node_modules/pi-mcp-adapter/mcp-status.ts +8 -19
  408. package/node_modules/pi-mcp-adapter/metadata-cache.ts +20 -12
  409. package/node_modules/pi-mcp-adapter/namespace-tools.ts +276 -0
  410. package/node_modules/pi-mcp-adapter/package.json +24 -6
  411. package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -10
  412. package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -0
  413. package/node_modules/pi-mcp-adapter/server-manager.ts +63 -12
  414. package/node_modules/pi-mcp-adapter/state.ts +1 -3
  415. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +16 -2
  416. package/node_modules/pi-mcp-adapter/types.ts +48 -1
  417. package/node_modules/pi-mcp-adapter/ui-server.ts +3 -19
  418. package/node_modules/pi-mcp-adapter/ui-session.ts +2 -1
  419. package/node_modules/pi-mcp-adapter/utils.ts +21 -19
  420. package/node_modules/pi-web-access/CHANGELOG.md +26 -0
  421. package/node_modules/pi-web-access/README.md +71 -14
  422. package/node_modules/pi-web-access/chrome-cookies.ts +115 -35
  423. package/node_modules/pi-web-access/credential-source.ts +6 -2
  424. package/node_modules/pi-web-access/curator-page.ts +5 -3
  425. package/node_modules/pi-web-access/curator-server.ts +2 -1
  426. package/node_modules/pi-web-access/extract.ts +89 -9
  427. package/node_modules/pi-web-access/fetch-params.ts +13 -0
  428. package/node_modules/pi-web-access/gemini-adc.ts +298 -0
  429. package/node_modules/pi-web-access/gemini-api.ts +59 -15
  430. package/node_modules/pi-web-access/gemini-search.ts +58 -18
  431. package/node_modules/pi-web-access/gemini-url-context.ts +3 -2
  432. package/node_modules/pi-web-access/gemini-web-config.ts +57 -7
  433. package/node_modules/pi-web-access/gemini-web.ts +9 -3
  434. package/node_modules/pi-web-access/github-api.ts +5 -4
  435. package/node_modules/pi-web-access/github-issue-pr.ts +700 -0
  436. package/node_modules/pi-web-access/index.ts +403 -297
  437. package/node_modules/pi-web-access/kimi-search.ts +234 -0
  438. package/node_modules/pi-web-access/openai-search.ts +118 -21
  439. package/node_modules/pi-web-access/package.json +3 -2
  440. package/node_modules/pi-web-access/ssrf-protection.ts +4 -1
  441. package/node_modules/pi-web-access/utils.ts +307 -1
  442. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  443. package/package.json +46 -37
  444. package/node_modules/@herbertgao/pi-copy-response/CHANGELOG.md +0 -49
  445. package/node_modules/@herbertgao/pi-copy-response/LICENSE +0 -22
  446. package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +0 -83
  447. package/node_modules/@herbertgao/pi-handoff/LICENSE +0 -22
  448. package/node_modules/@herbertgao/pi-handoff/package.json +0 -60
  449. package/node_modules/@herbertgao/pi-inline-skills/CHANGELOG.md +0 -57
  450. package/node_modules/@herbertgao/pi-inline-skills/LICENSE +0 -22
  451. package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +0 -39
  452. package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +0 -63
  453. package/node_modules/@herbertgao/pi-preferred-thinking/LICENSE +0 -22
  454. package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +0 -101
  455. package/node_modules/@herbertgao/pi-recap/LICENSE +0 -22
  456. package/node_modules/@herbertgao/pi-recap/package.json +0 -55
  457. package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +0 -49
  458. package/node_modules/@herbertgao/pi-rename/LICENSE +0 -22
  459. package/node_modules/@herbertgao/pi-rename/package.json +0 -63
  460. package/node_modules/@herbertgao/pi-titlebar-spinner/CHANGELOG.md +0 -25
  461. package/node_modules/@herbertgao/pi-titlebar-spinner/LICENSE +0 -22
  462. /package/node_modules/{@herbertgao → @tifan}/pi-copy-response/src/index.ts +0 -0
  463. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/complete-text.ts +0 -0
  464. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/session-query.ts +0 -0
  465. /package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/src/index.ts +0 -0
  466. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +0 -0
  467. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/viewer.mjs +0 -0
  468. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/src/index.ts +0 -0
  469. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/index.ts +0 -0
  470. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/model-picker.ts +0 -0
  471. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/sanitize.ts +0 -0
  472. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/tui.ts +0 -0
  473. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/model-picker.ts +0 -0
  474. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/naming.ts +0 -0
  475. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/sanitize.ts +0 -0
  476. /package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/src/index.ts +0 -0
@@ -15,7 +15,7 @@ import { getGlobalPiLensDir } from "../file-utils.js";
15
15
  import { isFullyQualified } from "../path-utils.js";
16
16
  import { findGlobalBinary } from "../package-manager.js";
17
17
  import { redactSecrets } from "../redact/secrets.js";
18
- import { classifySpawnFailure, SpawnFailureError, } from "../safe-spawn.js";
18
+ import { classifySpawnFailure, SpawnFailureError } from "../safe-spawn.js";
19
19
  import { getRubyVersionDirNamesAsync } from "./ruby-drive-dirs.js";
20
20
  const isWindows = process.platform === "win32";
21
21
  /**
@@ -176,7 +176,10 @@ export function isCmdShimValid(cmdPath) {
176
176
  try {
177
177
  const content = fs.readFileSync(cmdPath, "utf-8");
178
178
  // npm cmd shim pattern: "%~dp0\..\<relpath>" or "%~dp0/<relpath>"
179
- // biome-ignore format: regex char-class \- must stay escaped formatter strips it
179
+ // The `-` ends the char class, where it is a literal and needs no escape.
180
+ // oxfmt formats this repository (#1844) and rewrites no regex literal, so
181
+ // this line needs no suppression; the directive oxfmt honors, if one is
182
+ // ever needed here, is `// prettier-ignore`.
180
183
  const match = content.match(/"%~dp0[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
181
184
  if (!match)
182
185
  return true; // non-npm shim — let it through
@@ -205,7 +208,8 @@ function bypassPs1OnWindows(ps1Path, args) {
205
208
  // npm-generated PS1 pattern: "$basedir/../<package>/bin/cli.js"
206
209
  try {
207
210
  const content = fs.readFileSync(ps1Path, "utf-8");
208
- // biome-ignore format: regex char-class \- must stay escaped formatter strips it
211
+ // Same char class as isCmdShimValid above, and the same note: the trailing
212
+ // `-` is a literal, and oxfmt leaves regex literals alone.
209
213
  const match = content.match(/"\$basedir[/\\]\.\.[/\\]((?:[\w./@-]|\\)+\.(?:mjs|cjs|js))"/i);
210
214
  if (match) {
211
215
  const relPath = match[1].replace(/[/\\]/g, path.sep);
@@ -263,6 +267,10 @@ function trySpawn(command, args, cwd, env, needsShell) {
263
267
  // shell:true justified: Windows .cmd/.bat LSP binaries (e.g. typescript-language-server.cmd)
264
268
  // cannot be spawned via execFile — cmd.exe must interpret the script wrapper.
265
269
  const shellCommand = `"${command}" ${args.map(escapeCmdArg).join(" ")}`;
270
+ // #2015 class-sweep exemption: this is a LONG-LIVED language-server launch,
271
+ // not a bounded probe - killing it on a timeout would be wrong, and its
272
+ // lifetime is owned by the LSP lifecycle, not the spawner. Exempt from the
273
+ // verifyToolBinary/probe tree-kill migration.
266
274
  proc = nodeSpawn(shellCommand, [], {
267
275
  cwd,
268
276
  env,
@@ -0,0 +1,152 @@
1
+ /**
2
+ * #2001/#2002 — collect-later coverage store for slow auxiliary LSP servers.
3
+ *
4
+ * When a `with-auxiliary` touch's aux-grace window expires without a
5
+ * publication from an auxiliary scanner (opengrep on Windows measures ~8s per
6
+ * scan against a 2s grace), that scanner's eventual findings were silently
7
+ * cached inside its LSP client and never surfaced to the agent: the auxiliary
8
+ * contributed ZERO agent-visible coverage on most edits.
9
+ *
10
+ * This module is the bounded hand-off between the two halves of the fix:
11
+ *
12
+ * - PRODUCER (`clients/lsp/index.ts`'s aux-grace wait): after the outcomes
13
+ * are decided, every auxiliary with no publication evidence for this
14
+ * content (`cut_off` or `silent`, minus #1493's published-this-content
15
+ * exemption) marks its (filePath, serverId) pair here. DEFERRED servers
16
+ * are never marked — they never received the content, so their cache
17
+ * still describes the PREVIOUS revision (#1459).
18
+ * - CONSUMER (`clients/runtime-turn.ts` at turn_end): drains the store,
19
+ * probes each pair through the read-only
20
+ * `LSPService.readCachedDiagnosticsForServers` seam, freshness-gates the
21
+ * result against `markedAtMs`, and delivers survivors as the registered
22
+ * `runtime-turn:late-auxiliary-findings` gated surface. A pair whose
23
+ * client is alive but has STILL published nothing is re-armed until
24
+ * readLateAuxRearmTtlMs() (env-overridable via
25
+ * `PI_LENS_LATE_AUX_REARM_TTL_MS`) after the LAST re-arm, so a scan
26
+ * finishing between two turn ends is not lost and a demonstrably alive
27
+ * but slow scanner keeps its window open; `markedAtMs` itself never
28
+ * moves — it stays the immutable freshness baseline the delivery gate
29
+ * stats against. Past the TTL, or when the client is gone, the entry is
30
+ * dropped silently (best-effort by design).
31
+ *
32
+ * Bounds: at most MAX_PENDING_ENTRIES (file, server) pairs, insertion-order
33
+ * eviction of the OLDEST pair when the cap is exceeded (shape 9 discipline —
34
+ * the axis that grows is the pair count, so that is the axis that is capped).
35
+ * Keys fold through `normalizeEphemeralMapKey`: this is a hot single-process
36
+ * index whose keys are produced by this same process's touch path, so the
37
+ * cheap ephemeral normalizer is the lifetime-appropriate choice per the
38
+ * PathKeyedMap guidance — no realpath walk on the per-edit path.
39
+ */
40
+ import { normalizeEphemeralMapKey } from "../path-utils.js";
41
+ /** Maximum pending (filePath, serverId) pairs; oldest evicted beyond this. */
42
+ export const MAX_PENDING_AUX_ENTRIES = 50;
43
+ /**
44
+ * Default for how long a marked pair keeps being re-probed at successive
45
+ * turn ends when the client is alive but has published nothing yet. Covers
46
+ * opengrep's measured ~8s worst case many times over without pinning state
47
+ * forever. Overridable via `PI_LENS_LATE_AUX_REARM_TTL_MS`.
48
+ */
49
+ export const DEFAULT_LATE_AUX_REARM_TTL_MS = 5 * 60_000;
50
+ /**
51
+ * Read the `PI_LENS_LATE_AUX_REARM_TTL_MS` env override at call time (not
52
+ * module load time) so tests and users can tune without a rebuild — same
53
+ * shape as `readEnvAuxGraceMs` in clients/lsp/index.ts. Absent, non-numeric,
54
+ * or negative values fall back to {@link DEFAULT_LATE_AUX_REARM_TTL_MS}.
55
+ */
56
+ export function readLateAuxRearmTtlMs() {
57
+ const raw = process.env.PI_LENS_LATE_AUX_REARM_TTL_MS;
58
+ if (raw === undefined)
59
+ return DEFAULT_LATE_AUX_REARM_TTL_MS;
60
+ const parsed = Number.parseInt(raw, 10);
61
+ if (!Number.isFinite(parsed) || parsed < 0)
62
+ return DEFAULT_LATE_AUX_REARM_TTL_MS;
63
+ return parsed;
64
+ }
65
+ /**
66
+ * Whether a pending pair is past its re-arm TTL and should be retired at the
67
+ * next drain. The TTL anchors on {@link PendingAuxCoverageEntry.lastRearmedAtMs}
68
+ * when present (each successful probe extends the window), else on
69
+ * `markedAtMs`. `nowMs` is injectable so tests are deterministic.
70
+ */
71
+ export function isPendingAuxiliaryPastRearmTtl(pair, nowMs = Date.now()) {
72
+ const anchor = pair.lastRearmedAtMs ?? pair.markedAtMs;
73
+ return nowMs - anchor >= readLateAuxRearmTtlMs();
74
+ }
75
+ const pending = new Map();
76
+ function pairKey(filePath, serverId) {
77
+ return `${normalizeEphemeralMapKey(filePath)}\u0000${serverId}`;
78
+ }
79
+ /**
80
+ * Mark (or re-arm) one file's pending auxiliary coverage for `serverIds`.
81
+ * An existing pair keeps its ORIGINAL `markedAtMs`; only genuinely new pairs
82
+ * stamp the current time. Insertion order updates on re-mark so a re-armed
83
+ * pair is not the next one evicted at the cap.
84
+ *
85
+ * `rearmedAtMs` is the turn-end consumer's re-arm form: it stamps
86
+ * `lastRearmedAtMs` (the TTL anchor) WITHOUT moving the freshness baseline,
87
+ * so each successful probe extends the wait window while the delivery gate
88
+ * keeps comparing mtimes against the original mark. The producer form (no
89
+ * `rearmedAtMs`) marks a NEWER revision, so it resets any prior re-arm stamp
90
+ * along with the baseline — the new pair's TTL starts from its own mark.
91
+ */
92
+ export function markPendingAuxiliaryCoverage(filePath, serverIds, markedAtMs = Date.now(), rearmedAtMs) {
93
+ for (const serverId of serverIds) {
94
+ const key = pairKey(filePath, serverId);
95
+ const existing = pending.get(key);
96
+ if (existing) {
97
+ // #2027 review: bump the freshness baseline on producer re-mark. A
98
+ // newer touch means the auxiliary is scanning a NEWER revision;
99
+ // keeping the original baseline would make every post-baseline mtime
100
+ // read as stale, permanently dropping current-revision findings.
101
+ // A re-arm form never moves the baseline — only the TTL anchor.
102
+ pending.delete(key);
103
+ pending.set(key, rearmedAtMs === undefined
104
+ ? { filePath, serverId, markedAtMs }
105
+ : {
106
+ filePath,
107
+ serverId,
108
+ markedAtMs: existing.markedAtMs,
109
+ lastRearmedAtMs: rearmedAtMs,
110
+ });
111
+ continue;
112
+ }
113
+ pending.set(key, rearmedAtMs === undefined
114
+ ? { filePath, serverId, markedAtMs }
115
+ : { filePath, serverId, markedAtMs, lastRearmedAtMs: rearmedAtMs });
116
+ while (pending.size > MAX_PENDING_AUX_ENTRIES) {
117
+ const oldest = pending.keys().next().value;
118
+ if (oldest === undefined)
119
+ break;
120
+ pending.delete(oldest);
121
+ }
122
+ }
123
+ }
124
+ /**
125
+ * Remove one pair after its findings were delivered, or whenever the caller
126
+ * knows it is resolved. Unknown pairs are a no-op.
127
+ */
128
+ export function clearPendingAuxiliaryCoverage(filePath, serverId) {
129
+ pending.delete(pairKey(filePath, serverId));
130
+ }
131
+ /**
132
+ * Drain ALL pending pairs (removing them from the store) and return them in
133
+ * insertion order. The consumer re-arms the still-waiting subset via
134
+ * {@link markPendingAuxiliaryCoverage}'s `rearmedAtMs` form, which preserves
135
+ * each entry's original `markedAtMs` and stamps `lastRearmedAtMs`.
136
+ */
137
+ export function drainPendingAuxiliaryCoverage() {
138
+ const drained = [...pending.values()];
139
+ pending.clear();
140
+ return drained;
141
+ }
142
+ /** Test-only: current pending pair count. */
143
+ export function pendingAuxiliaryCoverageSizeForTests() {
144
+ return pending.size;
145
+ }
146
+ /**
147
+ * Session-boundary clear (#1635): pending baselines are unreachable after
148
+ * reset (the generation-stamped keys no longer match any active session).
149
+ */
150
+ export function resetPendingAuxiliaryCoverage() {
151
+ pending.clear();
152
+ }
@@ -7,7 +7,7 @@
7
7
  * - Platform-specific handling
8
8
  */
9
9
  import { existsSync, mkdirSync } from "node:fs";
10
- import { access, readFile, readdir, stat, } from "node:fs/promises";
10
+ import { access, readFile, readdir, stat } from "node:fs/promises";
11
11
  import os from "node:os";
12
12
  import path from "node:path";
13
13
  import { getGlobalPiLensDir, getProjectIgnoreGlobs, isPathIgnoredByProject, } from "../file-utils.js";
@@ -16,7 +16,7 @@ import { DOTNET_CSHARP_ROOT_MARKERS, DOTNET_FSHARP_ROOT_MARKERS, KIND_EXTENSIONS
16
16
  import { direntsHaveMarkerGlobMatch, isAtOrAboveHomeDir, isFullyQualified, isWindowsPath, pathsEqual, } from "../path-utils.js";
17
17
  import { ensureTool, getToolEnvironment, getToolPath, } from "../installer/index.js";
18
18
  import { resolveOpengrepConfig } from "../opengrep-config.js";
19
- import { isZizmorAuditTarget, resolveZizmorGitHubToken } from "../zizmor-config.js";
19
+ import { isZizmorAuditTarget, resolveZizmorGitHubToken, } from "../zizmor-config.js";
20
20
  import { logLatency } from "../latency-logger.js";
21
21
  import { logSessionStart } from "../sessionstart-logger.js";
22
22
  import { findLocalSgconfig, resolveBaselineSgconfig } from "../sgconfig.js";
@@ -1236,7 +1236,9 @@ function isTsFamilyFile(file) {
1236
1236
  return TS_FAMILY_EXTENSIONS.has(path.extname(file).toLowerCase());
1237
1237
  }
1238
1238
  function tsConfigMarkersForFile(file) {
1239
- return isTsFamilyFile(file) ? ["tsconfig.json"] : TS_CONFIG_MARKERS;
1239
+ return isTsFamilyFile(file)
1240
+ ? ["tsconfig.json"]
1241
+ : TS_CONFIG_MARKERS;
1240
1242
  }
1241
1243
  // Two detector instances (not one parameterized by file) so each keeps its own
1242
1244
  // per-directory NearestRoot cache valid for its fixed marker set — a shared
@@ -1606,7 +1608,9 @@ function extractTomlTableSection(content, tableName) {
1606
1608
  return "";
1607
1609
  const rest = content.slice(match.index + match[0].length);
1608
1610
  const nextHeading = rest.match(/^\[{1,2}[^\]]+\]{1,2}[ \t]*(?:#.*)?$/m);
1609
- return nextHeading?.index !== undefined ? rest.slice(0, nextHeading.index) : rest;
1611
+ return nextHeading?.index !== undefined
1612
+ ? rest.slice(0, nextHeading.index)
1613
+ : rest;
1610
1614
  }
1611
1615
  function parseTomlStringArray(content, key) {
1612
1616
  const match = content.match(new RegExp(`^[ \\t]*${key}[ \\t]*=[ \\t]*\\[([\\s\\S]*?)\\]`, "m"));
@@ -1674,7 +1678,10 @@ function matchesCargoWorkspacePattern(pattern, relativePath) {
1674
1678
  * common case and the one #1671's fixtures exercise — is unaffected.
1675
1679
  */
1676
1680
  function cargoWorkspaceDeclaresMember(workspaceContent, parentDir, childDir) {
1677
- const relativePath = path.relative(parentDir, childDir).split(path.sep).join("/");
1681
+ const relativePath = path
1682
+ .relative(parentDir, childDir)
1683
+ .split(path.sep)
1684
+ .join("/");
1678
1685
  if (relativePath === "" || relativePath.startsWith(".."))
1679
1686
  return false;
1680
1687
  const workspaceSection = extractTomlTableSection(workspaceContent, "workspace");
@@ -1721,7 +1728,8 @@ function RustWorkspaceRoot() {
1721
1728
  break;
1722
1729
  const parentCargoPath = path.join(parent, "Cargo.toml");
1723
1730
  const parentCargoContent = await readTextFileOrUndefined(parentCargoPath);
1724
- if (parentCargoContent !== undefined && /^\s*\[workspace\]/m.test(parentCargoContent)) {
1731
+ if (parentCargoContent !== undefined &&
1732
+ /^\s*\[workspace\]/m.test(parentCargoContent)) {
1725
1733
  // Test membership against the ORIGINAL crate dir (`root`), never the
1726
1734
  // walk cursor (`current`, which may already have climbed through
1727
1735
  // gap directories that have no Cargo.toml of their own) — a
@@ -1786,7 +1794,11 @@ async function declaresMavenModule(parentDir, parentPomPath, childDir) {
1786
1794
  }
1787
1795
  }
1788
1796
  function JavaWorkspaceRoot() {
1789
- const moduleRoot = createRootDetector(["pom.xml", "build.gradle", ".classpath"]);
1797
+ const moduleRoot = createRootDetector([
1798
+ "pom.xml",
1799
+ "build.gradle",
1800
+ ".classpath",
1801
+ ]);
1790
1802
  return async (file) => {
1791
1803
  const root = await moduleRoot(file);
1792
1804
  if (!root)
@@ -114,9 +114,17 @@ export async function probeTsserverProjectIdentity(options) {
114
114
  // writing an `lsp_typescript_project_identity` row per didOpen on every
115
115
  // server (python, go, opengrep, ...).
116
116
  const logOutcome = (outcome, metadata = {}) => logLatency({
117
- type: "phase", phase: "lsp_typescript_project_identity", filePath: normalizedFile,
117
+ type: "phase",
118
+ phase: "lsp_typescript_project_identity",
119
+ filePath: normalizedFile,
118
120
  durationMs: Date.now() - startedAt,
119
- metadata: { serverId: options.serverId, launchVariant: options.launchVariant, clientRoot: options.clientRoot, outcome, ...metadata },
121
+ metadata: {
122
+ serverId: options.serverId,
123
+ launchVariant: options.launchVariant,
124
+ clientRoot: options.clientRoot,
125
+ outcome,
126
+ ...metadata,
127
+ },
120
128
  });
121
129
  if (options.serverId !== "typescript" ||
122
130
  options.launchVariant !== "classic" ||
@@ -6,7 +6,7 @@ import { readJsonCache } from "../json-cache-read.js";
6
6
  import { createGenerationMap } from "../generation-guard.js";
7
7
  import { normalizeMapKey } from "../path-utils.js";
8
8
  import { loadReverseDependencyIndexFromSnapshot } from "../reverse-deps.js";
9
- import { MTIME_DRIFT_TOLERANCE_MS } from "../blocker-freshness.js";
9
+ import { freshnessFromMtime } from "../freshness.js";
10
10
  import { logLatency } from "../latency-logger.js";
11
11
  import { workspaceDiagnosticsCacheSessionStart } from "./workspace-diagnostics-session.js";
12
12
  import { createDiskBindingCache, } from "./diagnostic-binding.js";
@@ -344,14 +344,19 @@ export function isEntryFresh(filePath, entry, getImports) {
344
344
  return entry.depIndexAtScan !== true;
345
345
  }
346
346
  for (const dep of imports) {
347
+ let mtimeMs;
347
348
  try {
348
- if (fs.statSync(dep).mtimeMs > entry.scannedAt + MTIME_DRIFT_TOLERANCE_MS) {
349
- return false;
350
- }
349
+ mtimeMs = fs.statSync(dep).mtimeMs;
351
350
  }
352
351
  catch {
353
352
  return false; // dependency deleted/unreadable: fail closed
354
353
  }
354
+ const verdict = freshnessFromMtime({
355
+ mtimeMs,
356
+ referenceMs: entry.scannedAt,
357
+ });
358
+ if (verdict.verdict === "stale")
359
+ return false;
355
360
  }
356
361
  return true;
357
362
  }
@@ -68,9 +68,7 @@ export function findDocumentSymbolAtLine(symbols, oneBasedLine) {
68
68
  const visit = (items, ancestry) => {
69
69
  for (const symbol of items) {
70
70
  const range = symbolRange(symbol);
71
- if (range &&
72
- range.start.line <= line &&
73
- range.end.line >= line) {
71
+ if (range && range.start.line <= line && range.end.line >= line) {
74
72
  const nextAncestry = [...ancestry, symbol];
75
73
  const span = range.end.line - range.start.line;
76
74
  if (span <= bestSpan) {
@@ -1,6 +1,5 @@
1
1
  import * as path from "node:path";
2
2
  import { createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
3
- import { appendProjectChange, } from "./project-changes.js";
4
3
  import { normalizeMapKey } from "./path-utils.js";
5
4
  const MAX_SAMPLES = 100;
6
5
  const MAX_SUMMARIES_PER_CONTEXT = 100;
@@ -67,7 +66,7 @@ function uniqueDetails(files, fileDetails) {
67
66
  start: Math.min(previous.range.start, detail.range.start),
68
67
  end: Math.max(previous.range.end, detail.range.end),
69
68
  }
70
- : previous.range ?? detail.range,
69
+ : (previous.range ?? detail.range),
71
70
  importsChanged: previous.importsChanged || detail.importsChanged,
72
71
  });
73
72
  }
@@ -93,24 +92,15 @@ function bookkeepLspMutation(context, files, fileDetails) {
93
92
  }
94
93
  }
95
94
  const runtime = context.runtime;
96
- if (runtime?.bumpFileSeq) {
97
- const { projectSeq, fileSeq } = runtime.bumpFileSeq(filePath);
98
- try {
99
- appendProjectChange(context.cwd, {
100
- seq: projectSeq,
101
- timestamp: new Date().toISOString(),
102
- sessionId: runtime.telemetrySessionId ?? "unknown",
103
- turnIndex: runtime.turnIndex ?? 0,
104
- source: context.source,
105
- filePath,
106
- fileSeq,
107
- changedRange: detail.range,
108
- });
109
- }
110
- catch (err) {
111
- context.dbg?.(`lsp mutation project change append failed for ${filePath}: ${err}`);
112
- }
113
- }
95
+ // One mutation seam (#2000 phase 1): bump + receipt + change-log live in
96
+ // RuntimeCoordinator.recordProjectMutation.
97
+ runtime?.recordProjectMutation?.({
98
+ filePath,
99
+ source: context.source,
100
+ cwd: context.cwd,
101
+ changedRange: detail.range,
102
+ onAppendError: (err) => context.dbg?.(`lsp mutation project change append failed for ${filePath}: ${err}`),
103
+ });
114
104
  if (context.cacheManager) {
115
105
  try {
116
106
  context.cacheManager.addModifiedRange(filePath, detail.range ?? { start: 1, end: 1 }, detail.importsChanged ?? true, context.cwd, runtime?.telemetrySessionId);
@@ -9,7 +9,7 @@
9
9
  * coupling the MCP path has to satisfy — everything else under `clients/` is
10
10
  * host-neutral.
11
11
  */
12
- import { loadPiLensGlobalConfig, resolvePiLensFlag, } from "../lens-config.js";
12
+ import { loadPiLensGlobalConfig, resolvePiLensFlag } from "../lens-config.js";
13
13
  import { loadPiLensProjectConfig } from "../project-lens-config.js";
14
14
  /**
15
15
  * Build a `PiAgentAPI` for the MCP path. `overrides` lets a single MCP tool call
@@ -40,15 +40,63 @@ export const MEMORY_SAMPLE_TURN_INTERVAL = 10;
40
40
  export function shouldEmitMemorySample(turnIndex) {
41
41
  return turnIndex > 0 && turnIndex % MEMORY_SAMPLE_TURN_INTERVAL === 0;
42
42
  }
43
- /** PURE: reshape Node's `process.memoryUsage()` into this module's field
44
- * names testable without touching the real process. */
45
- export function toMemoryProcessUsage(mem) {
43
+ /**
44
+ * Rising-edge cadence (#1999): when heapUsed grows more than
45
+ * {@link HEAP_GROWTH_TIGHTEN_RATIO} between two sampled turns, sampling
46
+ * tightens from every {@link MEMORY_SAMPLE_TURN_INTERVAL} turns to every turn
47
+ * until growth stabilizes. The state below is module-scoped SESSION state —
48
+ * reset it at every primary `session_start` via
49
+ * {@link resetMemorySamplerCadence} (defect shape 17: a process-lifetime latch
50
+ * holding a session-scoped signal).
51
+ */
52
+ export const HEAP_GROWTH_TIGHTEN_RATIO = 1.2;
53
+ let _lastSampledHeapUsedBytes = 0;
54
+ let _tightenThroughTurn = 0;
55
+ /** Clear the rising-edge cadence state. Called on primary session_start. */
56
+ export function resetMemorySamplerCadence() {
57
+ _lastSampledHeapUsedBytes = 0;
58
+ _tightenThroughTurn = 0;
59
+ }
60
+ /** PURE: >20% heap growth between two sampled readings warrants tightening. */
61
+ export function isRapidHeapGrowth(previousHeapUsedBytes, currentHeapUsedBytes) {
62
+ return (previousHeapUsedBytes > 0 &&
63
+ currentHeapUsedBytes > previousHeapUsedBytes * HEAP_GROWTH_TIGHTEN_RATIO);
64
+ }
65
+ /** Record the heap reading of a sample just emitted at `turnIndex`. A rapid
66
+ * growth edge extends the tightened window through the NEXT turn; each
67
+ * subsequent still-growing sample (including one taken inside an already
68
+ * tightened window) extends it again, so the window naturally expires once
69
+ * growth stabilizes. Monotonic max so an out-of-order turn can never shrink
70
+ * the window. O(1). */
71
+ export function recordMemorySampleOutcome(heapUsedBytes, turnIndex) {
72
+ if (isRapidHeapGrowth(_lastSampledHeapUsedBytes, heapUsedBytes)) {
73
+ _tightenThroughTurn = Math.max(_tightenThroughTurn, turnIndex + 1);
74
+ }
75
+ _lastSampledHeapUsedBytes = heapUsedBytes;
76
+ }
77
+ /** Adaptive gate used by turn_end: base every-10 cadence OR an open tightened
78
+ * window. Pure w.r.t. its argument; the window itself is session state owned
79
+ * by {@link recordMemorySampleOutcome}. */
80
+ export function shouldEmitMemorySampleAdaptive(turnIndex) {
81
+ if (turnIndex <= 0)
82
+ return false;
83
+ return (turnIndex % MEMORY_SAMPLE_TURN_INTERVAL === 0 ||
84
+ turnIndex <= _tightenThroughTurn);
85
+ }
86
+ /** PURE: reshape Node's `process.memoryUsage()` (+ optional
87
+ * `process.resourceUsage()`) into this module's field names — testable
88
+ * without touching the real process. */
89
+ export function toMemoryProcessUsage(mem, resourceUsage) {
90
+ const maxKb = resourceUsage?.maxRSS;
46
91
  return {
47
92
  rssBytes: mem.rss,
48
93
  heapUsedBytes: mem.heapUsed,
49
94
  heapTotalBytes: mem.heapTotal,
50
95
  externalBytes: mem.external,
51
96
  arrayBuffersBytes: mem.arrayBuffers,
97
+ peakWorkingSetBytes: typeof maxKb === "number" && Number.isFinite(maxKb) && maxKb > 0
98
+ ? maxKb * 1024
99
+ : null,
52
100
  };
53
101
  }
54
102
  /**
@@ -86,11 +134,23 @@ export function collectMemorySampleSubsystems(wordIndex) {
86
134
  };
87
135
  }
88
136
  /** Assemble one full sample. `mem` is injectable for tests; defaults to a
89
- * live `process.memoryUsage()` read. */
90
- export function buildMemorySample(wordIndex, mem = process.memoryUsage()) {
137
+ * live `process.memoryUsage()` read. `resourceUsage` (peak working set) and
138
+ * `session` are optional ridealongs (#1999); when `resourceUsage` is omitted
139
+ * a live `process.resourceUsage()` read supplies the peak. */
140
+ export function buildMemorySample(wordIndex, mem = process.memoryUsage(), resourceUsage, session) {
141
+ let resolvedResourceUsage = resourceUsage;
142
+ if (!resolvedResourceUsage) {
143
+ try {
144
+ resolvedResourceUsage = process.resourceUsage();
145
+ }
146
+ catch {
147
+ resolvedResourceUsage = undefined;
148
+ }
149
+ }
91
150
  return {
92
- process: toMemoryProcessUsage(mem),
151
+ process: toMemoryProcessUsage(mem, resolvedResourceUsage),
93
152
  subsystems: collectMemorySampleSubsystems(wordIndex),
153
+ session,
94
154
  };
95
155
  }
96
156
  const toMb = (bytes) => Math.round(bytes / (1024 * 1024));
@@ -110,6 +170,12 @@ export function formatMemoryHealthLine(sample) {
110
170
  ? `${toMb(subsystems.treeSitter.treeCacheTotalBytes)}MB (${subsystems.treeSitter.treeCacheSize} trees)`
111
171
  : "n/a";
112
172
  const graph = `${subsystems.reviewGraph.totalNodes}n/${subsystems.reviewGraph.totalEdges}e (${subsystems.reviewGraph.cacheEntries} cwd)`;
173
+ // #1999: peak WS rides along when known — rss far below peak means the
174
+ // periodic samples are catching idle valleys, not the true high-water mark.
175
+ const peak = proc.peakWorkingSetBytes !== null
176
+ ? ` · peak WS ${toMb(proc.peakWorkingSetBytes)}MB`
177
+ : "";
113
178
  return (`Memory: RSS ${toMb(proc.rssBytes)}MB · heap ${toMb(proc.heapUsedBytes)}/${toMb(proc.heapTotalBytes)}MB` +
114
- ` · external ${toMb(proc.externalBytes)}MB · tree-sitter cache ${treeCache} · review-graph ${graph}`);
179
+ ` · external ${toMb(proc.externalBytes)}MB${peak}` +
180
+ ` · tree-sitter cache ${treeCache} · review-graph ${graph}`);
115
181
  }
@@ -18,9 +18,7 @@ export class MetricsClient {
18
18
  log;
19
19
  fileBaselines = new Map();
20
20
  constructor(verbose = false) {
21
- this.log = verbose
22
- ? createSubsystemLogger("metrics")
23
- : () => { };
21
+ this.log = verbose ? createSubsystemLogger("metrics") : () => { };
24
22
  }
25
23
  /**
26
24
  * Record initial state of a file when first touched this session
@@ -50,7 +50,12 @@ const SELF_TOKEN = {
50
50
  const INTENTIONAL_FORWARDER_NAME = /adapter|facade|proxy|wrapper|decorator/i;
51
51
  /** Names that are constructors/destructors (never delegation candidates) in at
52
52
  * least one covered language. */
53
- const CONSTRUCTOR_NAMES = new Set(["constructor", "__init__", "__new__", "initialize"]);
53
+ const CONSTRUCTOR_NAMES = new Set([
54
+ "constructor",
55
+ "__init__",
56
+ "__new__",
57
+ "initialize",
58
+ ]);
54
59
  /** Below this many real (non-accessor, non-constructor) methods, a delegation
55
60
  * ratio isn't a meaningful judgment — a one-method utility class forwarding
56
61
  * that one call is not "the class only ever delegates", it's just a small
@@ -130,7 +135,7 @@ function bodyStatementLines(lines, entry, isPython) {
130
135
  return [];
131
136
  body = raw.slice(braceIdx + 1, lastBrace);
132
137
  }
133
- return body
138
+ return (body
134
139
  .replace(/\/\*[\s\S]*?\*\//g, "")
135
140
  .split("\n")
136
141
  .map((l) => l.replace(/\/\/.*$/, ""))
@@ -140,7 +145,7 @@ function bodyStatementLines(lines, entry, isPython) {
140
145
  // A lone triple-quoted docstring line in python isn't executable, but
141
146
  // distinguishing it textually is unreliable — treat any leading `"""`/`'''`
142
147
  // line as noise so a documented one-liner forward still qualifies.
143
- .filter((l) => !/^("""|''')/.test(l));
148
+ .filter((l) => !/^("""|''')/.test(l)));
144
149
  }
145
150
  /** Detects an accessor (getter/setter) declaration from its raw source line —
146
151
  * accessors are a DIFFERENT smell (anemic class) and excluded from both the
@@ -82,7 +82,13 @@ function lspLocationsToUsedBy(locs, cap) {
82
82
  if (seen.has(key))
83
83
  continue;
84
84
  seen.add(key);
85
- out.push({ file, symbol: "", line, relation: "references", provenance: "lsp" });
85
+ out.push({
86
+ file,
87
+ symbol: "",
88
+ line,
89
+ relation: "references",
90
+ provenance: "lsp",
91
+ });
86
92
  if (out.length >= cap)
87
93
  break;
88
94
  }
@@ -1180,7 +1180,8 @@ function unavailableCallGraph(reason) {
1180
1180
  }
1181
1181
  function callGraphCoverage(coverage) {
1182
1182
  const languages = coverage.languages;
1183
- const complete = coverage.complete && Object.values(languages ?? {}).every((status) => status === "complete");
1183
+ const complete = coverage.complete &&
1184
+ Object.values(languages ?? {}).every((status) => status === "complete");
1184
1185
  return {
1185
1186
  status: complete ? "complete" : "partial",
1186
1187
  complete,
@@ -1235,7 +1236,8 @@ function readCallGraph(projectRoot, normalizedPath, maxEntries, graphFileCap, id
1235
1236
  // read-only: do not walk source files or compare an independent mtime map.
1236
1237
  if (!reviewGraph)
1237
1238
  return unavailableCallGraph("review-graph-missing");
1238
- if (reviewGraph.persistCoverage?.partial || reviewGraph.persistCoverage?.inProgress) {
1239
+ if (reviewGraph.persistCoverage?.partial ||
1240
+ reviewGraph.persistCoverage?.inProgress) {
1239
1241
  return unavailableCallGraph("partial");
1240
1242
  }
1241
1243
  if (!identity)
@@ -1458,9 +1460,7 @@ export async function moduleReport(file, cwd, options) {
1458
1460
  else if (graph) {
1459
1461
  importsProvenance = "cached-review-graph";
1460
1462
  }
1461
- const unavailableGraphProvenance = graphFileCap !== undefined
1462
- ? "unavailable:file-cap"
1463
- : "none";
1463
+ const unavailableGraphProvenance = graphFileCap !== undefined ? "unavailable:file-cap" : "none";
1464
1464
  const blastRadiusProvenance = blastRadius
1465
1465
  ? "cached-review-graph"
1466
1466
  : unavailableGraphProvenance;
@@ -1495,13 +1495,9 @@ export async function moduleReport(file, cwd, options) {
1495
1495
  provenance: {
1496
1496
  symbols: languageId ? "syntax" : "none",
1497
1497
  imports: importsProvenance,
1498
- usedBy: hasGraphNode
1499
- ? "cached-review-graph"
1500
- : unavailableGraphProvenance,
1498
+ usedBy: hasGraphNode ? "cached-review-graph" : unavailableGraphProvenance,
1501
1499
  callbacks: languageId && !summaryView ? "heuristic-tree-sitter" : "none",
1502
- ...(options?.blastRadius
1503
- ? { blastRadius: blastRadiusProvenance }
1504
- : {}),
1500
+ ...(options?.blastRadius ? { blastRadius: blastRadiusProvenance } : {}),
1505
1501
  ...(options?.callGraph ? { callGraph: callGraphProvenance } : {}),
1506
1502
  },
1507
1503
  semantic: {
@@ -1565,7 +1561,9 @@ function compactEntryLine(entry, width) {
1565
1561
  const range = padRange(entry.startLine, entry.endLine, width);
1566
1562
  const kind = compactKind(entry.kind).padEnd(6);
1567
1563
  const sig = entry.signature ? `${entry.name}${entry.signature}` : entry.name;
1568
- const flagsSuffix = entry.flags && entry.flags.length > 0 ? ` [${entry.flags.join(", ")}]` : "";
1564
+ const flagsSuffix = entry.flags && entry.flags.length > 0
1565
+ ? ` [${entry.flags.join(", ")}]`
1566
+ : "";
1569
1567
  const docSuffix = entry.doc ? ` — ${entry.doc}` : "";
1570
1568
  const usedBySuffix = compactUsedBySuffix(entry.usedBy);
1571
1569
  return ` ${range}${kind}${sig}${flagsSuffix}${usedBySuffix}${docSuffix}`;
@@ -1607,10 +1605,7 @@ export function renderCompactModuleReport(report) {
1607
1605
  return `${report.path} — unavailable${report.error ? `: ${report.error}` : ""}`;
1608
1606
  }
1609
1607
  const allEntries = [...report.api, ...report.internal];
1610
- const allRanges = allEntries.flatMap((e) => [
1611
- e,
1612
- ...(e.members ?? []),
1613
- ]);
1608
+ const allRanges = allEntries.flatMap((e) => [e, ...(e.members ?? [])]);
1614
1609
  const width = Math.max(5, ...allRanges.map((e) => `${e.startLine}-${e.endLine}`.length), ...report.callbacks.map((c) => `${c.startLine}-${c.endLine}`.length)) + 2;
1615
1610
  const importsList = [...report.imports.internal, ...report.imports.external];
1616
1611
  const importsSuffix = importsList.length > 0
@@ -1679,7 +1674,9 @@ function baseNameNoExt(p) {
1679
1674
  function selectMatch(candidates, kind) {
1680
1675
  if (candidates.length === 0)
1681
1676
  return {};
1682
- const filtered = kind ? candidates.filter((c) => c.kind === kind) : candidates;
1677
+ const filtered = kind
1678
+ ? candidates.filter((c) => c.kind === kind)
1679
+ : candidates;
1683
1680
  const pool = filtered.length > 0 ? filtered : candidates;
1684
1681
  const match = pool[0];
1685
1682
  if (pool.length <= 1)