@herbertgao/pi-extensions 2026.8.4 → 2026.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -5,7 +5,7 @@
5
5
  * doesn't — session-start warms the dominant-language LSP (so warm `analyze` is
6
6
  * LSP-complete), establishes the error-debt baseline + complexity baselines, and
7
7
  * kicks off knip/jscpd/type-coverage/dep/secrets scans; turn-end runs
8
- * knip/jscpd incrementally, dep-circular, tests, cascade, and the
8
+ * knip incrementally, dep-circular, tests, cascade, and the
9
9
  * actionable/code-quality aggregation.
10
10
  *
11
11
  * The handlers don't return findings — they emit them through the same
@@ -16,33 +16,47 @@
16
16
  * persistent RuntimeCoordinator + CacheManager (so baselines/turn-state survive
17
17
  * across calls, like a real session), and the bootstrap client bundle.
18
18
  */
19
+ import * as crypto from "node:crypto";
19
20
  import * as fs from "node:fs";
20
21
  import * as path from "node:path";
21
22
  import { AstGrepClient } from "../ast-grep-client.js";
22
23
  import { loadBootstrapClients } from "../bootstrap.js";
23
- import { CacheManager } from "../cache-manager.js";
24
+ import { CacheManager, MCP_TURN_STATE_OWNER_ID, } from "../cache-manager.js";
24
25
  import { resetDispatchBaselines } from "../dispatch/integration.js";
25
26
  import { resetFormatService } from "../format-service.js";
26
27
  import { getLSPService, resetLSPService } from "../lsp/index.js";
27
- import { consumeSessionStartGuidance, consumeTestFindings, consumeTurnEndFindings, } from "../runtime-context.js";
28
+ import { acknowledgeTestFindings, acknowledgeTurnEndFindings, consumeSessionStartGuidance, consumeTestFindings, consumeTurnEndFindings, peekTestFindings, peekTurnEndFindings, } from "../runtime-context.js";
28
29
  import { RuntimeCoordinator } from "../runtime-coordinator.js";
29
30
  import { handleSessionStart } from "../runtime-session.js";
30
31
  import { handleTurnEnd } from "../runtime-turn.js";
31
32
  import { createMcpHost } from "./host-shim.js";
32
33
  let contextPromise;
34
+ let resolvedRuntime;
33
35
  /** Lazily build (once) the persistent session context shared across MCP calls. */
34
36
  export function getMcpSessionContext() {
35
- contextPromise ??= (async () => ({
36
- runtime: new RuntimeCoordinator(),
37
- cacheManager: new CacheManager(),
38
- astGrepClient: new AstGrepClient(),
39
- clients: await loadBootstrapClients(),
40
- }))();
37
+ contextPromise ??= (async () => {
38
+ const context = {
39
+ runtime: new RuntimeCoordinator(),
40
+ cacheManager: new CacheManager(),
41
+ astGrepClient: new AstGrepClient(),
42
+ clients: await loadBootstrapClients(),
43
+ };
44
+ resolvedRuntime = context.runtime;
45
+ return context;
46
+ })();
41
47
  return contextPromise;
42
48
  }
49
+ /** Synchronous peek at the session runtime, for construction sites that cannot
50
+ * await (e.g. the MCP server's tool wiring). Returns undefined until a session
51
+ * context has actually been built — advisory validation then honestly skips
52
+ * the session-identity check instead of comparing against a phantom session. */
53
+ export function peekMcpSessionRuntime() {
54
+ return resolvedRuntime;
55
+ }
43
56
  /** Test hook — drop the cached context so a fresh one is built next call. */
44
57
  export function _resetMcpSessionContext() {
45
58
  contextPromise = undefined;
59
+ resolvedRuntime = undefined;
46
60
  }
47
61
  const noop = () => { };
48
62
  function joinMessages(consumed) {
@@ -105,12 +119,82 @@ export async function runSessionStart(cwd) {
105
119
  aliveLspClients: getLSPService().getAliveClientCount(),
106
120
  };
107
121
  }
122
+ /**
123
+ * #1274: the delivery map used to be unbounded — every timed-out client and
124
+ * every distinct raw-cwd alias left an entry for the life of the process.
125
+ * Both bounds drop entries WITHOUT committing, which re-arms the findings in
126
+ * the cache: the safe direction, since an un-consumed finding is re-reported on
127
+ * a later Stop while a wrongly-consumed one is gone for good. The TTL is
128
+ * generous next to Claude Code's 60 s hook budget — it exists to bound the map,
129
+ * not to police clients.
130
+ */
131
+ const TURN_END_DELIVERY_TTL_MS = 10 * 60_000;
132
+ const TURN_END_DELIVERY_MAX = 8;
133
+ const TURN_END_QUEUE_WAIT_MS = 5_000;
134
+ /**
135
+ * A bounded, cancellable serial queue. A turn_end mutates shared runtime and
136
+ * cache state, so concurrent passes are unsafe; a disconnected/hung pass must
137
+ * nevertheless not accumulate an unbounded tail of Stop requests.
138
+ */
139
+ class TurnEndQueue {
140
+ running = false;
141
+ pending = [];
142
+ enqueue(work, waitMs = TURN_END_QUEUE_WAIT_MS) {
143
+ if (this.pending.length >= 1) {
144
+ return Promise.reject(new Error("turn_end queue is busy"));
145
+ }
146
+ return new Promise((resolve, reject) => {
147
+ const item = {
148
+ work,
149
+ resolve,
150
+ reject,
151
+ timer: setTimeout(() => {
152
+ const index = this.pending.indexOf(item);
153
+ if (index === -1)
154
+ return;
155
+ this.pending.splice(index, 1);
156
+ reject(new Error("turn_end queue wait timed out"));
157
+ }, waitMs),
158
+ };
159
+ item.timer.unref();
160
+ this.pending.push(item);
161
+ this.drain();
162
+ });
163
+ }
164
+ drain() {
165
+ if (this.running)
166
+ return;
167
+ const item = this.pending.shift();
168
+ if (!item)
169
+ return;
170
+ clearTimeout(item.timer);
171
+ this.running = true;
172
+ void item
173
+ .work()
174
+ .then(item.resolve, item.reject)
175
+ .finally(() => {
176
+ this.running = false;
177
+ this.drain();
178
+ });
179
+ }
180
+ reset() {
181
+ for (const item of this.pending.splice(0)) {
182
+ clearTimeout(item.timer);
183
+ item.reject(new Error("turn_end queue reset"));
184
+ }
185
+ this.running = false;
186
+ }
187
+ }
188
+ const turnEndQueue = new TurnEndQueue();
189
+ const pendingTurnEndDeliveries = new Map();
190
+ /** In-flight Stop-hook passes, keyed by cwd — see `runTurnEndForIpc` (#1274). */
191
+ const inFlightIpcTurnEnds = new Map();
108
192
  /**
109
193
  * Run pi-lens's real turn_end over the files edited this "turn". The handler
110
194
  * reads edited files from turn-state, so we register the caller-supplied files
111
195
  * first (a full-file range, importsChanged=true so dep/knip re-check broadly).
112
196
  */
113
- export async function runTurnEnd(cwd, files = []) {
197
+ async function runTurnEndNow(cwd, files = [], deferredDelivery = false) {
114
198
  const ctx = await getMcpSessionContext();
115
199
  const host = createMcpHost(undefined, cwd);
116
200
  let registered = 0;
@@ -123,9 +207,15 @@ export async function runTurnEnd(cwd, files = []) {
123
207
  catch {
124
208
  continue; // unreadable / deleted — skip
125
209
  }
126
- ctx.cacheManager.addModifiedRange(abs, { start: 1, end: lineCount }, true, cwd, ctx.runtime.telemetrySessionId);
210
+ ctx.cacheManager.addModifiedRange(abs, { start: 1, end: lineCount }, true, cwd, MCP_TURN_STATE_OWNER_ID, "mcp");
127
211
  registered++;
128
212
  }
213
+ const owner = {
214
+ kind: "mcp",
215
+ id: MCP_TURN_STATE_OWNER_ID,
216
+ pid: process.pid,
217
+ lastSeen: new Date().toISOString(),
218
+ };
129
219
  await handleTurnEnd({
130
220
  ctxCwd: cwd,
131
221
  getFlag: host.getFlag,
@@ -136,12 +226,143 @@ export async function runTurnEnd(cwd, files = []) {
136
226
  deadCodeClients: ctx.clients.deadCodeClients,
137
227
  depChecker: ctx.clients.depChecker,
138
228
  testRunnerClient: ctx.clients.testRunnerClient,
229
+ owner,
139
230
  resetLSPService,
140
231
  resetFormatService,
141
232
  });
233
+ const outcome = deferredDelivery
234
+ ? {
235
+ turnEnd: joinMessages(peekTurnEndFindings(ctx.cacheManager, cwd, ctx.runtime, true)),
236
+ tests: joinMessages(peekTestFindings(ctx.cacheManager, cwd, ctx.runtime, true)),
237
+ filesRegistered: registered,
238
+ }
239
+ : {
240
+ turnEnd: joinMessages(consumeTurnEndFindings(ctx.cacheManager, cwd, ctx.runtime)),
241
+ tests: joinMessages(consumeTestFindings(ctx.cacheManager, cwd, ctx.runtime)),
242
+ filesRegistered: registered,
243
+ };
142
244
  return {
143
- turnEnd: joinMessages(consumeTurnEndFindings(ctx.cacheManager, cwd)),
144
- tests: joinMessages(consumeTestFindings(ctx.cacheManager, cwd)),
145
- filesRegistered: registered,
245
+ outcome,
246
+ commit: () => {
247
+ if (!deferredDelivery)
248
+ return;
249
+ acknowledgeTurnEndFindings(ctx.cacheManager, cwd);
250
+ acknowledgeTestFindings(ctx.cacheManager, cwd);
251
+ },
146
252
  };
147
253
  }
254
+ /**
255
+ * Run a normal MCP turn_end. Its caller owns the tool response, so the
256
+ * historical consume-on-return behavior remains unchanged.
257
+ */
258
+ export function runTurnEnd(cwd, files = []) {
259
+ return turnEndQueue.enqueue(async () => (await runTurnEndNow(cwd, files)).outcome);
260
+ }
261
+ /** A result with no findings needs no durable delivery transaction. */
262
+ function hasTurnEndFindings(outcome) {
263
+ return Boolean(outcome.turnEnd || outcome.tests);
264
+ }
265
+ /** Drop expired deliveries, then the oldest ones over the cap. Never commits. */
266
+ function prunePendingTurnEndDeliveries(now = Date.now()) {
267
+ for (const [deliveryId, delivery] of pendingTurnEndDeliveries) {
268
+ if (now - delivery.createdAt >= TURN_END_DELIVERY_TTL_MS) {
269
+ pendingTurnEndDeliveries.delete(deliveryId);
270
+ }
271
+ }
272
+ // Map iteration is insertion-ordered, so the head is the oldest entry.
273
+ while (pendingTurnEndDeliveries.size > TURN_END_DELIVERY_MAX) {
274
+ const oldest = pendingTurnEndDeliveries.keys().next();
275
+ if (oldest.done)
276
+ break;
277
+ pendingTurnEndDeliveries.delete(oldest.value);
278
+ }
279
+ }
280
+ function pendingForCwd(cwd) {
281
+ for (const [deliveryId, delivery] of pendingTurnEndDeliveries) {
282
+ if (delivery.cwd === cwd)
283
+ return [deliveryId, delivery];
284
+ }
285
+ return undefined;
286
+ }
287
+ /**
288
+ * Run the Stop-hook pass as a durable delivery transaction. The result is
289
+ * acknowledged through a separate one-shot IPC request. Until that request
290
+ * arrives, the findings cache is deliberately left unconsumed; a client
291
+ * timeout, socket close, or server restart therefore leaves the result for a
292
+ * later Stop request instead of losing it between execution and reply.
293
+ */
294
+ export function runTurnEndForIpc(cwd) {
295
+ // #1274: the Stop-hook request carries no files and no sessionId, so two
296
+ // overlapping ones are byte-identical and a second pass would be pure waste
297
+ // — worse, the queue only holds ONE waiter, so a third Stop is rejected
298
+ // outright. Identical in-flight requests share the one pass and one
299
+ // deliveryId; the ack is idempotent-by-capability, so the loser of the race
300
+ // simply finds the delivery already committed.
301
+ const inFlight = inFlightIpcTurnEnds.get(cwd);
302
+ if (inFlight)
303
+ return inFlight;
304
+ const run = runTurnEndForIpcNow(cwd).finally(() => {
305
+ inFlightIpcTurnEnds.delete(cwd);
306
+ });
307
+ inFlightIpcTurnEnds.set(cwd, run);
308
+ return run;
309
+ }
310
+ function runTurnEndForIpcNow(cwd) {
311
+ return turnEndQueue.enqueue(async () => {
312
+ prunePendingTurnEndDeliveries();
313
+ const pending = pendingForCwd(cwd);
314
+ if (pending) {
315
+ return {
316
+ outcome: pending[1].transaction.outcome,
317
+ deliveryId: pending[0],
318
+ };
319
+ }
320
+ const ctx = await getMcpSessionContext();
321
+ const cachedOutcome = {
322
+ turnEnd: joinMessages(peekTurnEndFindings(ctx.cacheManager, cwd, ctx.runtime, true)),
323
+ tests: joinMessages(peekTestFindings(ctx.cacheManager, cwd, ctx.runtime, true)),
324
+ filesRegistered: 0,
325
+ };
326
+ const transaction = hasTurnEndFindings(cachedOutcome)
327
+ ? {
328
+ outcome: cachedOutcome,
329
+ commit: () => {
330
+ acknowledgeTurnEndFindings(ctx.cacheManager, cwd);
331
+ acknowledgeTestFindings(ctx.cacheManager, cwd);
332
+ },
333
+ }
334
+ : await runTurnEndNow(cwd, [], true);
335
+ if (!hasTurnEndFindings(transaction.outcome)) {
336
+ return { outcome: transaction.outcome };
337
+ }
338
+ const deliveryId = crypto.randomUUID();
339
+ pendingTurnEndDeliveries.set(deliveryId, {
340
+ cwd,
341
+ transaction,
342
+ createdAt: Date.now(),
343
+ });
344
+ prunePendingTurnEndDeliveries();
345
+ return { outcome: transaction.outcome, deliveryId };
346
+ });
347
+ }
348
+ /** Commit exactly one admitted delivery capability. */
349
+ export function acknowledgeTurnEnd(cwd, deliveryId) {
350
+ prunePendingTurnEndDeliveries();
351
+ const delivery = pendingTurnEndDeliveries.get(deliveryId);
352
+ if (!delivery || delivery.cwd !== cwd)
353
+ return false;
354
+ // #1274: commit BEFORE dropping the capability. Deleting first meant a
355
+ // throwing consume destroyed the only handle to the findings — precisely the
356
+ // loss this two-phase protocol exists to prevent, reintroduced on the error
357
+ // path. Leaving the entry in place on a throw keeps the delivery re-fetchable
358
+ // by a later Stop.
359
+ delivery.transaction.commit();
360
+ pendingTurnEndDeliveries.delete(deliveryId);
361
+ return true;
362
+ }
363
+ /** Test hook — drop pending requests so one failed test cannot wedge the rest. */
364
+ export function _resetTurnEndChain() {
365
+ turnEndQueue.reset();
366
+ pendingTurnEndDeliveries.clear();
367
+ inFlightIpcTurnEnds.clear();
368
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Periodic memory-attribution sample (#1123 item 2, expanded on top of item 1's
3
+ * loop_block windowing — the #1126 sizing study's "instrumentation the next
4
+ * report should add" list is this module's requirements).
5
+ *
6
+ * The #1126 sizing study diagnosed a 1.37 GB instance from code + serialized
7
+ * artifacts alone, because nothing recorded a per-subsystem trajectory over
8
+ * time — the same detection-without-attribution gap loop_block had before
9
+ * #1122/#1125. This module answers "what is resident right now, broken down
10
+ * by subsystem" as a single ndjson `memory_sample` `latency.log` line, emitted
11
+ * every `MEMORY_SAMPLE_TURN_INTERVAL` turns (cheap enough not to need finer
12
+ * throttling).
13
+ *
14
+ * HARD CONSTRAINT: every field here is an O(1) `Map`/array `.size`/`.length`
15
+ * read, or a `process.memoryUsage()` call — nothing here iterates a large
16
+ * structure's contents, and nothing takes a heap snapshot. `PI_LENS_DEBUG_HEAP`
17
+ * (item 4's memory sibling) is a SEPARATE, explicitly opt-in mechanism, out of
18
+ * scope here.
19
+ *
20
+ * WASM linear-memory byte length gap (documented, not silently dropped): the
21
+ * #1126 spec asked for `Module.wasmMemory.buffer.byteLength` off the
22
+ * web-tree-sitter parser runtime. Inspecting the installed web-tree-sitter
23
+ * 0.25.10 package (see `clients/tree-sitter-client.ts#getRuntimeStats`'s
24
+ * docstring) confirmed that value is not reachable through any public export
25
+ * — only through package-internal reflection or by overriding Emscripten's
26
+ * `wasmMemory` module option with a hand-built `WebAssembly.Memory` (a
27
+ * stability risk for an observability-only feature, given a memory-import
28
+ * mismatch would break structural analysis entirely). `process.memoryUsage()`
29
+ * `arrayBuffers` is used as the process-wide proxy instead — WASM linear
30
+ * memory backs an ArrayBuffer, so it is already included there.
31
+ */
32
+ import { getSharedTreeSitterClient } from "./tree-sitter-shared.js";
33
+ import { getReviewGraphWorkspaceCacheSnapshot } from "./review-graph/builder.js";
34
+ import { getDispatchCascadeCacheStats } from "./dispatch/integration.js";
35
+ /** Every N turns, emit one `memory_sample` latency.log line (#1123 item 2). */
36
+ export const MEMORY_SAMPLE_TURN_INTERVAL = 10;
37
+ /** True on turn 10, 20, 30, ... — never on turn 0 (nothing meaningful is
38
+ * resident yet at session start). Pure so the cadence is unit-testable
39
+ * without driving a real turn loop. */
40
+ export function shouldEmitMemorySample(turnIndex) {
41
+ return turnIndex > 0 && turnIndex % MEMORY_SAMPLE_TURN_INTERVAL === 0;
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) {
46
+ return {
47
+ rssBytes: mem.rss,
48
+ heapUsedBytes: mem.heapUsed,
49
+ heapTotalBytes: mem.heapTotal,
50
+ externalBytes: mem.external,
51
+ arrayBuffersBytes: mem.arrayBuffers,
52
+ };
53
+ }
54
+ /**
55
+ * Live O(1)/O(bounded-cache-size) subsystem counters. Impure (reads
56
+ * process-global singletons) but every individual read is a `.size`/`.length`
57
+ * access — see the module docstring's hard constraint.
58
+ */
59
+ export function collectMemorySampleSubsystems(wordIndex) {
60
+ const reviewGraph = getReviewGraphWorkspaceCacheSnapshot();
61
+ const treeSitterClient = getSharedTreeSitterClient();
62
+ const treeSitter = treeSitterClient
63
+ ? (() => {
64
+ const runtimeStats = treeSitterClient.getRuntimeStats();
65
+ const cacheStats = treeSitterClient.getParseCacheStats();
66
+ return {
67
+ ...runtimeStats,
68
+ treeCacheSize: cacheStats.size,
69
+ treeCacheMaxSize: cacheStats.maxSize,
70
+ treeCacheTotalBytes: cacheStats.totalBytes,
71
+ };
72
+ })()
73
+ : null;
74
+ const dispatchCaches = getDispatchCascadeCacheStats();
75
+ return {
76
+ reviewGraph,
77
+ wordIndex: wordIndex
78
+ ? {
79
+ docs: wordIndex.docLengths.size,
80
+ postings: wordIndex.postings.size,
81
+ forwardEntries: wordIndex.forward?.size ?? 0,
82
+ }
83
+ : null,
84
+ treeSitter,
85
+ dispatchCaches,
86
+ };
87
+ }
88
+ /** 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()) {
91
+ return {
92
+ process: toMemoryProcessUsage(mem),
93
+ subsystems: collectMemorySampleSubsystems(wordIndex),
94
+ };
95
+ }
96
+ const toMb = (bytes) => Math.round(bytes / (1024 * 1024));
97
+ /**
98
+ * PURE: one compact `/lens-health` line reusing the same sample the periodic
99
+ * latency.log emitter builds — RSS + heap/external, plus the two subsystem
100
+ * numbers most useful for spotting an attribution outlier at a glance: the
101
+ * tree-sitter tree-cache byte total (the only subsystem counter here that is
102
+ * ALREADY in bytes, so it's directly comparable to RSS) and the review-graph
103
+ * node/edge counts (the multiple-graph-copies question #1126 called out).
104
+ * Follows #1125's health-line style (a single summary line, no per-subsystem
105
+ * breakdown table — that's what latency.log's `memory_sample` is for).
106
+ */
107
+ export function formatMemoryHealthLine(sample) {
108
+ const { process: proc, subsystems } = sample;
109
+ const treeCache = subsystems.treeSitter
110
+ ? `${toMb(subsystems.treeSitter.treeCacheTotalBytes)}MB (${subsystems.treeSitter.treeCacheSize} trees)`
111
+ : "n/a";
112
+ const graph = `${subsystems.reviewGraph.totalNodes}n/${subsystems.reviewGraph.totalEdges}e (${subsystems.reviewGraph.cacheEntries} cwd)`;
113
+ 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}`);
115
+ }
@@ -10,6 +10,7 @@
10
10
  * These are observational metrics — they inform the human in session summary,
11
11
  * they don't gate or interrupt the agent mid-task.
12
12
  */
13
+ import { createSubsystemLogger } from "./extension-log.js";
13
14
  import * as fs from "node:fs";
14
15
  import * as path from "node:path";
15
16
  // --- Client ---
@@ -18,7 +19,7 @@ export class MetricsClient {
18
19
  fileBaselines = new Map();
19
20
  constructor(verbose = false) {
20
21
  this.log = verbose
21
- ? (msg) => console.error(`[metrics] ${msg}`)
22
+ ? createSubsystemLogger("metrics")
22
23
  : () => { };
23
24
  }
24
25
  /**
@@ -10,6 +10,7 @@ import { execSync } from "node:child_process";
10
10
  import * as fs from "node:fs";
11
11
  import * as path from "node:path";
12
12
  import { getProjectDataDir } from "./file-utils.js";
13
+ import { writeFileAtomic } from "./atomic-write.js";
13
14
  // --- Constants ---
14
15
  const HISTORY_FILE = "metrics-history.json";
15
16
  const MAX_HISTORY_PER_FILE = 20;
@@ -82,7 +83,7 @@ export function saveHistory(history) {
82
83
  }
83
84
  history.capturedAt = new Date().toISOString();
84
85
  const historyPath = path.join(historyDir, "metrics-history.json");
85
- fs.writeFileSync(historyPath, JSON.stringify(history, null, 2));
86
+ writeFileAtomic(historyPath, JSON.stringify(history, null, 2));
86
87
  }
87
88
  // In-memory cache to avoid loading/saving on every capture
88
89
  let pendingHistory = null;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Provider derivation for worklog/disposition attribution (#1448).
3
+ *
4
+ * The host reports `provider` and `model` as separate fields on its telemetry
5
+ * events (see `updateRuntimeIdentityFromEvent` in index.ts and the
6
+ * `tool_result` handler in clients/runtime-tool-result.ts) MOST of the time —
7
+ * so the common case needs no parsing at all. This parser exists only for the
8
+ * fallback: a model id supplied without an explicit provider.
9
+ *
10
+ * Derivation rule (conservative — returns "" rather than guess):
11
+ * 1. A single `/` or `:` separator splits the id into `<provider>/<rest>`
12
+ * or `<provider>:<rest>` — e.g. "anthropic/claude-sonnet-4-5",
13
+ * "openai:gpt-5". The left segment is lowercased and returned AS-IS
14
+ * (no allowlist check) since an explicit separator is deliberate host
15
+ * structure, not a guess.
16
+ * 2. No separator: match a known model-id PREFIX against a small table of
17
+ * vendor naming conventions (claude- -> anthropic; gpt-, o1-, o3- ->
18
+ * openai; gemini- -> google; llama- -> meta; mistral-, mixtral- ->
19
+ * mistral; command- -> cohere). First match wins.
20
+ * 3. Anything else (unrecognized prefix, multiple separators, empty
21
+ * string) is ambiguous -> "".
22
+ */
23
+ const KNOWN_PREFIXES = [
24
+ ["claude-", "anthropic"],
25
+ ["gpt-", "openai"],
26
+ ["o1-", "openai"],
27
+ ["o3-", "openai"],
28
+ ["gemini-", "google"],
29
+ ["llama-", "meta"],
30
+ ["mistral-", "mistral"],
31
+ ["mixtral-", "mistral"],
32
+ ["command-", "cohere"],
33
+ ];
34
+ export function deriveProviderFromModelId(modelId) {
35
+ const id = modelId?.trim().toLowerCase();
36
+ if (!id)
37
+ return "";
38
+ const separators = [...id].filter((c) => c === "/" || c === ":").length;
39
+ if (separators === 1) {
40
+ const sep = id.includes("/") ? "/" : ":";
41
+ const [providerPart, ...rest] = id.split(sep);
42
+ if (providerPart && rest.join(sep).length > 0)
43
+ return providerPart;
44
+ return "";
45
+ }
46
+ if (separators > 1)
47
+ return "";
48
+ for (const [prefix, provider] of KNOWN_PREFIXES) {
49
+ if (id.startsWith(prefix))
50
+ return provider;
51
+ }
52
+ return "";
53
+ }
@@ -15,6 +15,11 @@
15
15
  * remaining wall-clock budget.
16
16
  * - OPT-IN: disabled by default (budget 0) until validated in a real pi session;
17
17
  * enable with PI_LENS_MODULE_REPORT_LSP_BUDGET_MS.
18
+ *
19
+ * PARKED BY DECISION (#1090, 2026-08-12): zero live importers by design —
20
+ * efe3d2a5 unwired module_report's LSP path (#256) and re-homed live
21
+ * enrichment to #236 (LSP-confirmed graph edges). Kept for that future
22
+ * implementation; do not re-flag in dead-code sweeps while #236 is open.
18
23
  */
19
24
  import { withinRemaining } from "./deadline-utils.js";
20
25
  import { uriToPath } from "./path-utils.js";