@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
@@ -32,10 +32,106 @@
32
32
  * `undefined`). The caller must handle `undefined` as "sync path unavailable,
33
33
  * fall back to existing unconfirmed/timed-out behavior".
34
34
  */
35
+ import { logLatency } from "../latency-logger.js";
36
+ import { normalizeMapKey } from "../path-utils.js";
35
37
  // ---------------------------------------------------------------------------
36
38
  // Constants
37
39
  // ---------------------------------------------------------------------------
38
40
  export const TSSERVER_REQUEST_COMMAND = "typescript.tsserverRequest";
41
+ function classifyProjectInfo(body) {
42
+ if (!body || typeof body !== "object") {
43
+ return { projectKind: "unassociated", association: "unassociated" };
44
+ }
45
+ const info = body;
46
+ const configFile = typeof info.configFileName === "string" && info.configFileName.length > 0
47
+ ? info.configFileName
48
+ : undefined;
49
+ const inferred = configFile
50
+ ? /(?:^|[/\\])inferredProject\d*\*?$/i.test(configFile) ||
51
+ /inferred[-_ ]?project/i.test(configFile)
52
+ : false;
53
+ const projectKind = configFile
54
+ ? inferred
55
+ ? "inferred"
56
+ : /(?:^|[/\\])(?:tsconfig|jsconfig)\.json$/i.test(configFile)
57
+ ? "configured"
58
+ : "unassociated"
59
+ : "unassociated";
60
+ return {
61
+ projectKind,
62
+ ...(configFile ? { configFile } : {}),
63
+ association: info.languageServiceDisabled === true
64
+ ? "language-service-disabled"
65
+ : projectKind === "unassociated"
66
+ ? "unassociated"
67
+ : "associated",
68
+ };
69
+ }
70
+ /**
71
+ * #1412: after classic TypeScript's first successful didOpen, sample the
72
+ * tsserver project association without delaying diagnostics. The supplied
73
+ * executeCommand channel owns the existing bounded anti-deadlock backstop.
74
+ */
75
+ export async function probeTsserverProjectIdentity(options) {
76
+ const normalizedFile = options.normalizedFile ?? normalizeMapKey(options.file);
77
+ const startedAt = Date.now();
78
+ // Logging starts only once a probe is actually eligible and attempted:
79
+ // ineligible servers (wrong serverId/launchVariant, no command channel) and
80
+ // already-probed dedupe are both routine, high-volume, and per-server — a
81
+ // bare return keeps them out of the telemetry stream entirely instead of
82
+ // writing an `lsp_typescript_project_identity` row per didOpen on every
83
+ // server (python, go, opengrep, ...).
84
+ const logOutcome = (outcome, metadata = {}) => logLatency({
85
+ type: "phase", phase: "lsp_typescript_project_identity", filePath: normalizedFile,
86
+ durationMs: Date.now() - startedAt,
87
+ metadata: { serverId: options.serverId, launchVariant: options.launchVariant, clientRoot: options.clientRoot, outcome, ...metadata },
88
+ });
89
+ if (options.serverId !== "typescript" ||
90
+ options.launchVariant !== "classic" ||
91
+ typeof options.commandChannel.executeCommand !== "function") {
92
+ return;
93
+ }
94
+ if (options.probedFiles.has(normalizedFile))
95
+ return;
96
+ // Claim before yielding so concurrent opens cannot issue duplicate probes.
97
+ options.probedFiles.add(normalizedFile);
98
+ try {
99
+ const outcome = await options.commandChannel.executeCommand(TSSERVER_REQUEST_COMMAND, ["projectInfo", { file: options.file, needFileNameList: false }]);
100
+ if (!outcome.executed) {
101
+ logOutcome("not-executed");
102
+ return;
103
+ }
104
+ const response = outcome.result;
105
+ if (!response) {
106
+ logOutcome("no-response");
107
+ return;
108
+ }
109
+ if (response.success !== true) {
110
+ logOutcome("unsuccessful");
111
+ return;
112
+ }
113
+ const identity = classifyProjectInfo(response.body);
114
+ logLatency({
115
+ type: "phase",
116
+ phase: "lsp_typescript_project_identity",
117
+ filePath: normalizedFile,
118
+ durationMs: Date.now() - startedAt,
119
+ metadata: {
120
+ outcome: "ok",
121
+ serverId: options.serverId,
122
+ launchVariant: options.launchVariant,
123
+ clientRoot: options.clientRoot,
124
+ projectKind: identity.projectKind,
125
+ configFile: identity.configFile,
126
+ association: identity.association,
127
+ },
128
+ });
129
+ }
130
+ catch {
131
+ logOutcome("threw");
132
+ // Best-effort telemetry: command errors/timeouts never reach diagnostics.
133
+ }
134
+ }
39
135
  // ---------------------------------------------------------------------------
40
136
  // Helpers
41
137
  // ---------------------------------------------------------------------------
@@ -26,7 +26,7 @@ export function classifyServerWaitTier(serverId, snapshot) {
26
26
  return "pull-capable";
27
27
  if (mode !== "push-only")
28
28
  return "waits";
29
- const strategy = getStrategy(serverId);
29
+ const strategy = getStrategy(serverId, snapshot.launchVariant);
30
30
  if (strategy.silentOnClean !== true)
31
31
  return "waits"; // 2*/unknown push-only
32
32
  // #524/#529/#541/#558: `silentOnClean` on a server-id-keyed strategy is
@@ -44,6 +44,24 @@ export function classifyServerWaitTier(serverId, snapshot) {
44
44
  return "waits";
45
45
  return "tier3-silent";
46
46
  }
47
+ /**
48
+ * Resolve `filePath`'s PRIMARY (non-auxiliary) server id and its live
49
+ * capability snapshot, or `undefined` when the file has no primary server
50
+ * configured. The single place that decides what "this file's server" means
51
+ * for wait-policy purposes — shared by {@link classifyCascadeWaitTier} and the
52
+ * cascade-lane wrapper in `clients/lsp/cascade-tier.ts`, which needs the same
53
+ * id/snapshot pair to apply its one cascade-only override.
54
+ */
55
+ export function resolvePrimaryServerForWaitPolicy(filePath, snapshots) {
56
+ const servers = getServersForFileWithConfig(filePath).filter((s) => s.role !== "auxiliary");
57
+ const primary = servers[0];
58
+ if (!primary)
59
+ return undefined;
60
+ return {
61
+ serverId: primary.id,
62
+ snapshot: snapshots.find((s) => s.serverId === primary.id),
63
+ };
64
+ }
47
65
  /**
48
66
  * Classify whether `filePath`'s PRIMARY language server is a cascade-lane
49
67
  * Tier-3 (push-only, silent-on-clean) server. Ambiguous or missing capability
@@ -54,10 +72,8 @@ export function classifyServerWaitTier(serverId, snapshot) {
54
72
  */
55
73
  export function classifyCascadeWaitTier(lspService, filePath, snapshots) {
56
74
  void lspService; // kept in the signature for call-site clarity/typing only
57
- const servers = getServersForFileWithConfig(filePath).filter((s) => s.role !== "auxiliary");
58
- const primary = servers[0];
75
+ const primary = resolvePrimaryServerForWaitPolicy(filePath, snapshots);
59
76
  if (!primary)
60
77
  return "waits";
61
- const snapshot = snapshots.find((s) => s.serverId === primary.id);
62
- return classifyServerWaitTier(primary.id, snapshot);
78
+ return classifyServerWaitTier(primary.serverId, primary.snapshot);
63
79
  }
@@ -138,7 +138,8 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
138
138
  // (#242), so on a 2500ms-capped edit opengrep waits min(2500, 3500)=2500
139
139
  // and on uncapped paths it gets its full 3500. 3500 covers warm and most
140
140
  // cold; a cold scan that overruns isn't lost — late diagnostics are cached
141
- // and surface on the next edit.
141
+ // and surface on the next unchanged-content read through the content-bound
142
+ // auxiliary carry-over path.
142
143
  opengrep: {
143
144
  seedFirstPush: false,
144
145
  pullRetryBudgetMs: 0,
@@ -174,7 +175,8 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
174
175
  // reopen-on-resync. A native single-workflow audit is sub-second offline;
175
176
  // online mode may add a GitHub-API round-trip, so 2000ms gives headroom
176
177
  // (bounded by the per-edit caller cap as a ceiling, #242), and any late online
177
- // finding is cached and surfaces on the next edit.
178
+ // finding can surface on the next unchanged-content read through the
179
+ // content-bound auxiliary carry-over path.
178
180
  zizmor: {
179
181
  seedFirstPush: true,
180
182
  pullRetryBudgetMs: 0,
@@ -231,6 +233,16 @@ export const SERVER_DIAGNOSTIC_STRATEGIES = {
231
233
  silentOnClean: true,
232
234
  },
233
235
  };
236
+ /** Native TS7 can publish multiple versionless partial-program snapshots for a
237
+ * single open. Its first push is therefore provisional; a quiet window, rather
238
+ * than a protocol-unstable publication count, establishes the settled push. */
239
+ const NATIVE_TS7_DIAGNOSTIC_STRATEGY = {
240
+ ...SERVER_DIAGNOSTIC_STRATEGIES.typescript,
241
+ seedFirstPush: false,
242
+ // Native TS7 demonstrably publishes on clean, so the classic-only marker
243
+ // must not leak through the shared server id.
244
+ silentOnClean: false,
245
+ };
234
246
  /** Fallback for unknown servers. Conservative defaults. */
235
247
  export const DEFAULT_STRATEGY = {
236
248
  seedFirstPush: false,
@@ -239,6 +251,9 @@ export const DEFAULT_STRATEGY = {
239
251
  aggregateWaitMs: 1500,
240
252
  expectSemanticSecondPush: false,
241
253
  };
242
- export function getStrategy(serverId) {
254
+ export function getStrategy(serverId, launchVariant) {
255
+ if (serverId === "typescript" && launchVariant === "native-ts7") {
256
+ return NATIVE_TS7_DIAGNOSTIC_STRATEGY;
257
+ }
243
258
  return SERVER_DIAGNOSTIC_STRATEGIES[serverId] ?? DEFAULT_STRATEGY;
244
259
  }
@@ -1,9 +1,11 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { getProjectDataDir } from "../file-utils.js";
4
+ import { writeFileAtomic } from "../atomic-write.js";
4
5
  import { readJsonCache } from "../json-cache-read.js";
5
6
  import { normalizeMapKey } from "../path-utils.js";
6
7
  import { loadReverseDependencyIndexFromSnapshot } from "../reverse-deps.js";
8
+ import { createDiskBindingCache, } from "./diagnostic-binding.js";
7
9
  /**
8
10
  * #671: per-file cache of the last CONFIRMED `runWorkspaceDiagnostics` sweep
9
11
  * result, so a repeat `lens_diagnostics mode=full` with no intervening edits
@@ -24,7 +26,12 @@ import { loadReverseDependencyIndexFromSnapshot } from "../reverse-deps.js";
24
26
  * `LSPWorkspaceDiagnosticResult.timedOut` in `./index.ts`) into
25
27
  * `WorkspaceDiagnosticsCacheEntry`.
26
28
  */
27
- export const WORKSPACE_DIAGNOSTICS_CACHE_VERSION = 1;
29
+ // v2 (#1095): entries may carry an optional `contentHash` fingerprint of the
30
+ // file bytes the cached diagnostics were computed against, so a `lookup` can
31
+ // surface a content `binding` (boundToCurrentDisk) beyond the mtime proxy.
32
+ // Legacy v1 entries are rejected by the version guard and re-scanned — a
33
+ // deliberately clean break so no entry lacking the field is ever served.
34
+ export const WORKSPACE_DIAGNOSTICS_CACHE_VERSION = 2;
28
35
  const CACHE_FILE = "lsp-workspace-diagnostics.json";
29
36
  function cachePath(cwd) {
30
37
  return path.join(getProjectDataDir(cwd), "cache", CACHE_FILE);
@@ -48,7 +55,11 @@ export function loadWorkspaceDiagnosticsCache(cwd) {
48
55
  export function saveWorkspaceDiagnosticsCache(cwd, cache) {
49
56
  const filePath = cachePath(cwd);
50
57
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
51
- fs.writeFileSync(filePath, JSON.stringify(cache, null, 2));
58
+ // bestEffort: false — persist()'s catch is the error policy here, and it
59
+ // must observe the failure so `dirty` stays set and the next sweep retries.
60
+ writeFileAtomic(filePath, JSON.stringify(cache, null, 2), {
61
+ bestEffort: false,
62
+ });
52
63
  }
53
64
  /**
54
65
  * True when `filePath`'s cached entry is still trustworthy enough to reuse
@@ -133,6 +144,8 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
133
144
  return undefined;
134
145
  return reverseDepsIndex.imports[cacheKeyFor(filePath)] ?? [];
135
146
  };
147
+ // #1095: per-sweep disk-fingerprint memo (per file+mtime) for binding verify.
148
+ const diskBindingCache = createDiskBindingCache();
136
149
  let dirty = false;
137
150
  return {
138
151
  lookup(filePath, scopeKey) {
@@ -141,15 +154,26 @@ export function createWorkspaceDiagnosticsCacheContext(cwd) {
141
154
  return undefined;
142
155
  if (!isEntryFresh(filePath, entry, getImports))
143
156
  return undefined;
144
- return { diagnostics: entry.diagnostics, count: entry.count };
157
+ return {
158
+ diagnostics: entry.diagnostics,
159
+ count: entry.count,
160
+ binding: {
161
+ contentHash: entry.contentHash,
162
+ boundToCurrentDisk: diskBindingCache.boundToCurrentDisk(filePath, {
163
+ contentHash: entry.contentHash,
164
+ }),
165
+ },
166
+ scannedAt: entry.scannedAt,
167
+ };
145
168
  },
146
- record(filePath, scopeKey, diagnostics, mtimeMs) {
169
+ record(filePath, scopeKey, diagnostics, mtimeMs, contentHash) {
147
170
  entries[cacheKeyFor(filePath)] = {
148
171
  diagnostics,
149
172
  count: diagnostics.length,
150
173
  mtimeMs,
151
174
  scannedAt: Date.now(),
152
175
  scopeKey,
176
+ ...(contentHash !== undefined && { contentHash }),
153
177
  };
154
178
  dirty = true;
155
179
  },
@@ -0,0 +1,8 @@
1
+ /** Shared lazy LSP service seam (#1394). */
2
+ let lspPromise;
3
+ export function warmLspService() {
4
+ return (lspPromise ??= import("./lsp/index.js"));
5
+ }
6
+ export function loadLspService() {
7
+ return warmLspService();
8
+ }
@@ -0,0 +1,248 @@
1
+ import * as path from "node:path";
2
+ import { createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
3
+ import { appendProjectChange, } from "./project-changes.js";
4
+ import { normalizeMapKey } from "./path-utils.js";
5
+ const MAX_SAMPLES = 100;
6
+ const MAX_SUMMARIES_PER_CONTEXT = 100;
7
+ export function newLspMutationCorrelationId(toolCallId) {
8
+ return getReadGuardCorrelationId(toolCallId ? { toolCallId } : {});
9
+ }
10
+ function allResults(options) {
11
+ return options.results ?? [];
12
+ }
13
+ function combineResults(results) {
14
+ const files = new Set();
15
+ const fileDetails = [];
16
+ const appliedIndexes = [];
17
+ const paths = [];
18
+ let requestedTotal = 0;
19
+ let appliedTotal = 0;
20
+ let textEdits = 0;
21
+ let create = 0;
22
+ let rename = 0;
23
+ let deleteCount = 0;
24
+ for (const result of results) {
25
+ requestedTotal += result.operationTotal;
26
+ appliedTotal += result.appliedOperationTotal;
27
+ textEdits += result.operationCounts.textEdits;
28
+ create += result.operationCounts.create;
29
+ rename += result.operationCounts.rename;
30
+ deleteCount += result.operationCounts.delete;
31
+ for (const index of result.appliedOperationIndexes)
32
+ appliedIndexes.push(index);
33
+ for (const file of result.files) {
34
+ if (!files.has(file)) {
35
+ files.add(file);
36
+ paths.push(file);
37
+ }
38
+ }
39
+ fileDetails.push(...result.fileDetails);
40
+ }
41
+ return {
42
+ requestedTotal,
43
+ appliedTotal,
44
+ appliedIndexes,
45
+ files: [...files],
46
+ fileDetails,
47
+ textEdits,
48
+ create,
49
+ rename,
50
+ delete: deleteCount,
51
+ paths,
52
+ };
53
+ }
54
+ function uniqueDetails(files, fileDetails) {
55
+ const byPath = new Map();
56
+ for (const detail of fileDetails) {
57
+ const key = normalizeMapKey(path.resolve(detail.filePath));
58
+ const previous = byPath.get(key);
59
+ if (!previous) {
60
+ byPath.set(key, detail);
61
+ continue;
62
+ }
63
+ byPath.set(key, {
64
+ filePath: previous.filePath,
65
+ range: previous.range && detail.range
66
+ ? {
67
+ start: Math.min(previous.range.start, detail.range.start),
68
+ end: Math.max(previous.range.end, detail.range.end),
69
+ }
70
+ : previous.range ?? detail.range,
71
+ importsChanged: previous.importsChanged || detail.importsChanged,
72
+ });
73
+ }
74
+ return files.map((filePath) => byPath.get(normalizeMapKey(path.resolve(filePath))) ?? {
75
+ filePath,
76
+ // Resource operations have no already-computed text range. A small
77
+ // range is still enough to invalidate the touched-file turn state;
78
+ // never synchronously re-read the whole file here.
79
+ range: { start: 1, end: 1 },
80
+ importsChanged: true,
81
+ });
82
+ }
83
+ function bookkeepLspMutation(context, files, fileDetails) {
84
+ const details = uniqueDetails(files, fileDetails);
85
+ for (const detail of details) {
86
+ const filePath = path.resolve(detail.filePath);
87
+ if (context.readGuard) {
88
+ try {
89
+ context.readGuard.recordWritten(filePath);
90
+ }
91
+ catch (err) {
92
+ context.dbg?.(`lsp mutation read-guard stamp failed for ${filePath}: ${err}`);
93
+ }
94
+ }
95
+ 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
+ }
114
+ if (context.cacheManager) {
115
+ try {
116
+ context.cacheManager.addModifiedRange(filePath, detail.range ?? { start: 1, end: 1 }, detail.importsChanged ?? true, context.cwd, runtime?.telemetrySessionId);
117
+ }
118
+ catch (err) {
119
+ context.dbg?.(`lsp mutation modified-range tracking failed for ${filePath}: ${err}`);
120
+ }
121
+ }
122
+ if (context.recordAutofix && context.source === "autofix") {
123
+ const key = normalizeMapKey(filePath);
124
+ const seen = context.autofixRecordedPaths ?? new Set();
125
+ context.autofixRecordedPaths = seen;
126
+ if (!seen.has(key)) {
127
+ if (seen.size >= MAX_SAMPLES) {
128
+ const oldest = seen.values().next().value;
129
+ if (oldest)
130
+ seen.delete(oldest);
131
+ }
132
+ seen.add(key);
133
+ context.recordAutofix(filePath);
134
+ }
135
+ }
136
+ }
137
+ if (context.publishFilesTouched && files.length > 0) {
138
+ context.publishFilesTouched(files);
139
+ }
140
+ }
141
+ function telemetryFor(context, options) {
142
+ const combined = combineResults(allResults(options));
143
+ const requestedTotal = options.requestedTotal ?? combined.requestedTotal;
144
+ const appliedTotal = combined.appliedTotal;
145
+ const requestedIndexes = Array.from({ length: Math.min(requestedTotal, MAX_SAMPLES) }, (_, index) => index);
146
+ const rejectedTotal = Math.max(0, requestedTotal - appliedTotal);
147
+ const rejectedReasons = Array.from({ length: Math.min(rejectedTotal, MAX_SAMPLES) }, (_, index) => ({ index, code: "write_failed" }));
148
+ const status = options.status ?? (appliedTotal > 0 ? "success" : "skipped");
149
+ const editBatchSummary = createReadGuardEditBatchSummary({
150
+ requestedIndexes,
151
+ requestedTotal,
152
+ resolvedIndexes: requestedIndexes,
153
+ resolvedTotal: requestedTotal,
154
+ rejectedReasons,
155
+ rejectedTotal,
156
+ appliedIndexes: combined.appliedIndexes,
157
+ appliedTotal,
158
+ participantIds: [context.correlationId],
159
+ participantTotal: 1,
160
+ commitStatus: status === "failed"
161
+ ? "failed"
162
+ : appliedTotal > 0
163
+ ? "committed"
164
+ : "no_changes",
165
+ terminalStatus: status,
166
+ });
167
+ return {
168
+ editBatchSummary,
169
+ operationCounts: {
170
+ requested: requestedTotal,
171
+ applied: appliedTotal,
172
+ textEdits: combined.textEdits,
173
+ create: combined.create,
174
+ rename: combined.rename,
175
+ delete: combined.delete,
176
+ },
177
+ sampledPaths: combined.paths.slice(0, MAX_SAMPLES),
178
+ sampledPathsTotal: combined.paths.length,
179
+ sampledPathsTruncated: combined.paths.length > MAX_SAMPLES,
180
+ considered: options.considered,
181
+ completed: options.completed,
182
+ failedCount: options.failedCount,
183
+ };
184
+ }
185
+ export function recordLspMutation(context, options = {}) {
186
+ const results = allResults(options);
187
+ const combined = combineResults(results);
188
+ if (options.bookkeep !== false && combined.files.length > 0) {
189
+ bookkeepLspMutation(context, combined.files, combined.fileDetails);
190
+ }
191
+ const telemetry = telemetryFor(context, options);
192
+ if (context.emitSummary !== false) {
193
+ const summaryCount = context.summaryCount ?? 0;
194
+ context.summaryEmitted = true;
195
+ if (summaryCount < MAX_SUMMARIES_PER_CONTEXT) {
196
+ context.summaryCount = summaryCount + 1;
197
+ logReadGuardEvent({
198
+ event: "edit_batch_summary",
199
+ correlationId: context.correlationId,
200
+ filePath: combined.files[0] ?? context.cwd,
201
+ metadata: {
202
+ tool: context.tool,
203
+ source: context.source,
204
+ outcome: telemetry.editBatchSummary.terminalStatus,
205
+ // The outer correlation identifies the soliciting tool call; the
206
+ // bounded sequence distinguishes multiple applyEdit requests within it.
207
+ summaryIndex: summaryCount,
208
+ editBatchSummary: telemetry.editBatchSummary,
209
+ operationCounts: telemetry.operationCounts,
210
+ sampledPaths: telemetry.sampledPaths,
211
+ sampledPathsTotal: telemetry.sampledPathsTotal,
212
+ sampledPathsTruncated: telemetry.sampledPathsTruncated,
213
+ considered: telemetry.considered,
214
+ completed: telemetry.completed,
215
+ failedCount: telemetry.failedCount,
216
+ },
217
+ });
218
+ }
219
+ else if (!context.summaryOverflowed) {
220
+ context.summaryOverflowed = true;
221
+ logReadGuardEvent({
222
+ event: "edit_batch_summary_overflow",
223
+ correlationId: context.correlationId,
224
+ filePath: combined.files[0] ?? context.cwd,
225
+ metadata: {
226
+ tool: context.tool,
227
+ source: context.source,
228
+ summaryLimit: MAX_SUMMARIES_PER_CONTEXT,
229
+ suppressedSummaries: "one or more",
230
+ },
231
+ });
232
+ }
233
+ }
234
+ return telemetry;
235
+ }
236
+ export function recordLspMutationBatch(context, options) {
237
+ const previous = context.emitSummary;
238
+ context.emitSummary = true;
239
+ try {
240
+ return recordLspMutation(context, options);
241
+ }
242
+ finally {
243
+ context.emitSummary = previous;
244
+ }
245
+ }
246
+ export function recordLspMutationOutcome(context, status) {
247
+ return recordLspMutation(context, { status, requestedTotal: 0 });
248
+ }