@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
@@ -4,9 +4,13 @@ import { applyConservativeActionableWarningFixes, checkActionableWarningsReportF
4
4
  import { publishFilesTouched } from "./bus-publish.js";
5
5
  import { publishAutofixStart, publishFormatStart, } from "./format-events-publish.js";
6
6
  import { logLatency } from "./latency-logger.js";
7
+ import { isPathIgnoredByProject } from "./file-utils.js";
8
+ import { newLspMutationCorrelationId } from "./lsp-mutation.js";
7
9
  import { getGlobalActionableWarningMaxFixes, } from "./lens-config.js";
8
- import { resyncLspFile, runFormatPhase } from "./pipeline.js";
10
+ import { resyncLspFile, runAutofix, runFormatPhase } from "./pipeline.js";
11
+ import { getAmbientAbortSignal } from "./safe-spawn.js";
9
12
  import { appendProjectChange, } from "./project-changes.js";
13
+ import { getAutofixPolicyForFile, hasBiomeConfig, hasDetektConfig, hasEslintConfig, hasGolangciConfig, hasKtfmtConfig, hasKtlintConfig, hasOxlintConfig, hasRubocopConfig, hasSqlfluffConfig, hasStylelintConfig, } from "./tool-policy.js";
10
14
  /**
11
15
  * A queued file is claimed by any flush once it has sat unclaimed by its own
12
16
  * owning session for this long — recovery for an orphaned record whose
@@ -16,6 +20,7 @@ import { appendProjectChange, } from "./project-changes.js";
16
20
  * extra staleness for guaranteed eventual formatting. (#791)
17
21
  */
18
22
  export const DEFERRED_FORMAT_STALE_AFTER_MS = 10 * 60_000;
23
+ const DEFERRED_FORMAT_CONCURRENCY = 3;
19
24
  function recordProjectChange(args) {
20
25
  const bump = args.runtime.bumpFileSeq;
21
26
  if (!bump)
@@ -36,13 +41,49 @@ function recordProjectChange(args) {
36
41
  args.dbg(`project change log append failed for ${args.filePath}: ${err}`);
37
42
  }
38
43
  }
39
- export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, dbg, runtime, cacheManager, getFormatService, currentSessionId, staleAfterMs = DEFERRED_FORMAT_STALE_AFTER_MS, }) {
44
+ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, dbg, runtime, cacheManager, getFormatService, biomeClient, ruffClient, getAutofixClients, currentSessionId, staleAfterMs = DEFERRED_FORMAT_STALE_AFTER_MS, }) {
40
45
  // #791: ownership-filtered drain — records queued by a DIFFERENT known
41
46
  // session (e.g. a concurrent in-process secondary/subagent) stay queued
42
47
  // for their owner's own agent_end, unless they've been stale long enough
43
48
  // to fall back to "claim as orphaned" (see claimDeferredFormatFiles).
44
- const { claimed, staleClaimed, deferredToOwner } = runtime.claimDeferredFormatFiles(currentSessionId, Date.now(), staleAfterMs);
49
+ const { claimed, staleClaimed, deferredToOwner } = runtime.claimDeferredMutations(currentSessionId, Date.now(), staleAfterMs);
45
50
  const records = [...claimed, ...staleClaimed];
51
+ const requeuedKinds = new Set();
52
+ // S2d (gap 4, #1432 review): the aggregate `agent_end_deferred_mutation_drain`
53
+ // row only carried a coalesced `requeuedKinds` set with no reason, per-call
54
+ // file count, or tool provenance — every requeue (abort mid-drain, missing
55
+ // autofix clients, an autofix/format failure) collapsed into one
56
+ // indistinguishable bucket. Log one bounded record PER requeue call instead,
57
+ // so a real incident can tell "aborted with N files still queued" apart
58
+ // from "M files failed to format".
59
+ const requeue = (pending, reason) => {
60
+ if (pending.length === 0)
61
+ return;
62
+ const kinds = new Set();
63
+ const toolNames = new Set();
64
+ for (const record of pending) {
65
+ for (const kind of record.kinds) {
66
+ requeuedKinds.add(kind);
67
+ kinds.add(kind);
68
+ }
69
+ for (const toolName of record.toolNames)
70
+ toolNames.add(toolName);
71
+ }
72
+ logLatency({
73
+ type: "phase",
74
+ toolName: "agent_end",
75
+ filePath: ctxCwd ?? runtime.projectRoot,
76
+ phase: "agent_end_deferred_mutation_requeue",
77
+ durationMs: 0,
78
+ metadata: {
79
+ reason,
80
+ kinds: [...kinds].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
81
+ fileCount: pending.length,
82
+ toolNames: [...toolNames].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
83
+ },
84
+ });
85
+ runtime.requeueDeferredMutations(pending);
86
+ };
46
87
  const rootActionableAutofixEnabled = !!getFlag("lens-actionable-warning-autofix");
47
88
  // A path-aware source resolver signals that nested configs may re-enable
48
89
  // actionable autofix even when the root default is off. Legacy/test hosts
@@ -93,6 +134,86 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
93
134
  // publishFilesTouched call so consumers can tell "pi-lens formatted this"
94
135
  // from an agent edit.
95
136
  const deferredFormatFixes = [];
137
+ const deferredAutofixFixes = [];
138
+ const deferredAutofixChanged = new Set();
139
+ // Mutation ordering is intentional: lint --write may disturb wrapping, so
140
+ // autofix reaches the final edited state first and formatting stabilizes it.
141
+ const ambientSignal = getAmbientAbortSignal();
142
+ const executedAutofixScopes = new Set();
143
+ const autofixRecords = records.filter((candidate) => candidate.kinds.has("autofix"));
144
+ if (autofixRecords.length > 0 && (!biomeClient || !ruffClient) && getAutofixClients) {
145
+ ({ biomeClient, ruffClient } = await getAutofixClients());
146
+ }
147
+ for (let autofixIndex = 0; autofixIndex < autofixRecords.length; autofixIndex++) {
148
+ const record = autofixRecords[autofixIndex];
149
+ if (ambientSignal?.aborted) {
150
+ requeue(autofixRecords.slice(autofixIndex).map((pending) => ({
151
+ ...pending,
152
+ kinds: new Set(["autofix"]),
153
+ toolNames: new Set(pending.toolNames),
154
+ })), "abort");
155
+ break;
156
+ }
157
+ const filePath = path.resolve(record.filePath);
158
+ if (!nodeFs.existsSync(filePath)) {
159
+ summary.skipped.push({ filePath, reason: "missing" });
160
+ continue;
161
+ }
162
+ if (!biomeClient || !ruffClient) {
163
+ dbg(`agent_end deferred_autofix: clients unavailable for ${filePath}`);
164
+ requeue([{ ...record, kinds: new Set(["autofix"]), toolNames: new Set(record.toolNames) }], "clients-unavailable");
165
+ continue;
166
+ }
167
+ const policy = getAutofixPolicyForFile(filePath, {
168
+ hasEslintConfig: hasEslintConfig(record.cwd),
169
+ hasStylelintConfig: hasStylelintConfig(record.cwd),
170
+ hasSqlfluffConfig: hasSqlfluffConfig(record.cwd),
171
+ hasRubocopConfig: hasRubocopConfig(record.cwd),
172
+ hasBiomeConfig: hasBiomeConfig(record.cwd),
173
+ hasGolangciConfig: hasGolangciConfig(record.cwd),
174
+ hasDetektConfig: hasDetektConfig(record.cwd),
175
+ hasOxlintConfig: hasOxlintConfig(record.cwd),
176
+ hasKtfmtConfig: hasKtfmtConfig(record.cwd),
177
+ hasKtlintConfig: hasKtlintConfig(record.cwd),
178
+ });
179
+ const scopeKey = policy?.scope && policy.scope !== "file"
180
+ ? `${policy.defaultTool ?? "unknown"}:${path.resolve(record.cwd)}`
181
+ : `${policy?.defaultTool ?? "unknown"}:${filePath}`;
182
+ if (executedAutofixScopes.has(scopeKey))
183
+ continue;
184
+ executedAutofixScopes.add(scopeKey);
185
+ try {
186
+ const result = await runAutofix(filePath, record.cwd, getFlag, dbg, { biomeClient, ruffClient, fixedThisTurn: runtime.fixedThisTurn }, getFlagSource);
187
+ const tools = result.autofixTools.map((label) => label.split(":")[0]);
188
+ for (const changed of result.changedFiles) {
189
+ const changedPath = path.resolve(changed);
190
+ deferredAutofixChanged.add(changedPath);
191
+ for (const tool of tools)
192
+ deferredAutofixFixes.push({ path: changedPath, tool, kind: "autofix" });
193
+ if (!nodeFs.existsSync(changedPath))
194
+ continue;
195
+ recordProjectChange({ runtime, cwd: record.turnStateCwd, filePath: changedPath, source: "autofix", dbg });
196
+ if (!getFlag("no-read-guard"))
197
+ runtime.readGuard.recordWritten(changedPath);
198
+ const content = nodeFs.readFileSync(changedPath, "utf-8");
199
+ cacheManager.addModifiedRange(changedPath, { start: 1, end: content.split("\n").length }, /^import\s/m.test(content), record.turnStateCwd, currentSessionId ?? runtime.telemetrySessionId, "pi");
200
+ }
201
+ }
202
+ catch (err) {
203
+ const message = err instanceof Error ? err.message : String(err);
204
+ summary.failed.push({ filePath, errors: [message] });
205
+ requeue([{ ...record, kinds: new Set(["autofix"]), toolNames: new Set(record.toolNames) }], "autofix-failed");
206
+ }
207
+ }
208
+ if (deferredAutofixFixes.length > 0) {
209
+ publishFilesTouched({
210
+ reason: "autofix",
211
+ paths: [...new Set(deferredAutofixFixes.map((fix) => fix.path))],
212
+ cwd: ctxCwd ?? runtime.projectRoot,
213
+ dbg,
214
+ fixes: deferredAutofixFixes,
215
+ });
216
+ }
96
217
  dbg(`agent_end deferred_format: ${records.length} file(s)`);
97
218
  logLatency({
98
219
  type: "phase",
@@ -123,9 +244,10 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
123
244
  cwd: ctxCwd ?? runtime.projectRoot,
124
245
  paths: records.map((r) => r.filePath),
125
246
  dbg,
247
+ kinds: [...new Set(records.flatMap((record) => [...record.kinds]))],
126
248
  });
127
249
  }
128
- const formatRecords = records.filter((record) => {
250
+ const formatRecords = records.filter((record) => record.kinds.has("format")).filter((record) => {
129
251
  const disabled = !!getFlag("no-autoformat", record.filePath);
130
252
  if (disabled) {
131
253
  const source = getFlagSource?.("no-autoformat", record.filePath);
@@ -138,46 +260,73 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
138
260
  return !disabled;
139
261
  });
140
262
  if (formatRecords.length > 0) {
141
- // Run all formatter subprocesses concurrently — no shared state touched here.
142
- // bumpFileSeq / cacheManager mutations happen in the sequential pass below.
143
- const outcomes = await Promise.all(formatRecords.map(async (record) => {
144
- const fileStart = Date.now();
145
- const filePath = path.resolve(record.filePath);
146
- if (!nodeFs.existsSync(filePath)) {
147
- dbg(`agent_end deferred_format skipped missing file: ${filePath}`);
148
- return { kind: "skipped", filePath, reason: "missing" };
149
- }
150
- try {
151
- const result = await runFormatPhase(filePath, getFormatService, dbg);
152
- return { kind: "done", record, filePath, result, fileStart };
153
- }
154
- catch (err) {
155
- const message = err instanceof Error ? err.message : String(err);
156
- dbg(`agent_end deferred_format failed for ${filePath}: ${message}`);
157
- return { kind: "failed", filePath, message, fileStart };
263
+ const work = new Array(formatRecords.length);
264
+ const started = new Set();
265
+ let nextIndex = 0;
266
+ const worker = async () => {
267
+ while (nextIndex < formatRecords.length) {
268
+ const index = nextIndex++;
269
+ if (ambientSignal?.aborted)
270
+ return;
271
+ const record = formatRecords[index];
272
+ const fileStart = Date.now();
273
+ const filePath = path.resolve(record.filePath);
274
+ started.add(index);
275
+ if (!nodeFs.existsSync(filePath)) {
276
+ work[index] = { record, filePath, fileStart, missing: true };
277
+ continue;
278
+ }
279
+ try {
280
+ work[index] = {
281
+ record,
282
+ filePath,
283
+ fileStart,
284
+ result: await runFormatPhase(filePath, getFormatService, dbg),
285
+ };
286
+ }
287
+ catch (err) {
288
+ work[index] = {
289
+ record,
290
+ filePath,
291
+ fileStart,
292
+ error: err instanceof Error ? err.message : String(err),
293
+ };
294
+ }
158
295
  }
159
- }));
160
- // Process results sequentially — bumpFileSeq and cacheManager mutations
161
- // must stay ordered to avoid sequence number races.
162
- for (const outcome of outcomes) {
163
- if (outcome.kind === "skipped") {
164
- summary.skipped.push({
165
- filePath: outcome.filePath,
166
- reason: outcome.reason,
167
- });
296
+ };
297
+ await Promise.all(Array.from({ length: Math.min(DEFERRED_FORMAT_CONCURRENCY, formatRecords.length) }, () => worker()));
298
+ if (ambientSignal?.aborted) {
299
+ requeue(formatRecords.filter((_, index) => !started.has(index)).map((record) => ({
300
+ ...record,
301
+ kinds: new Set(["format"]),
302
+ toolNames: new Set(record.toolNames),
303
+ })), "abort");
304
+ }
305
+ for (const entry of work) {
306
+ if (!entry)
307
+ continue;
308
+ await new Promise((resolve) => setImmediate(resolve));
309
+ const { record, filePath, fileStart } = entry;
310
+ if (entry.missing) {
311
+ dbg(`agent_end deferred_format skipped missing file: ${filePath}`);
312
+ if (!summary.skipped.some((item) => item.filePath === filePath && item.reason === "missing")) {
313
+ summary.skipped.push({ filePath, reason: "missing" });
314
+ }
168
315
  continue;
169
316
  }
170
- if (outcome.kind === "failed") {
171
- summary.failed.push({
172
- filePath: outcome.filePath,
173
- errors: [outcome.message],
174
- });
317
+ if (entry.error) {
318
+ dbg(`agent_end deferred_format failed for ${filePath}: ${entry.error}`);
319
+ summary.failed.push({ filePath, errors: [entry.error] });
320
+ requeue([{ ...record, kinds: new Set(["format"]), toolNames: new Set(record.toolNames) }], "format-failed");
175
321
  continue;
176
322
  }
177
- const { record, filePath, result, fileStart } = outcome;
323
+ const result = entry.result;
324
+ if (!result)
325
+ continue;
178
326
  summary.formatted++;
179
327
  if (result.formatFailures.length > 0) {
180
328
  summary.failed.push({ filePath, errors: result.formatFailures });
329
+ requeue([{ ...record, kinds: new Set(["format"]), toolNames: new Set(record.toolNames) }], "format-failed");
181
330
  }
182
331
  if (result.formatChanged) {
183
332
  summary.changed.push(filePath);
@@ -202,7 +351,7 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
202
351
  const content = nodeFs.readFileSync(filePath, "utf-8");
203
352
  const lineCount = content.split("\n").length;
204
353
  const hasImports = /^import\s/m.test(content);
205
- cacheManager.addModifiedRange(filePath, { start: 1, end: lineCount }, hasImports, bookkeepingCwd);
354
+ cacheManager.addModifiedRange(filePath, { start: 1, end: lineCount }, hasImports, bookkeepingCwd, currentSessionId ?? runtime.telemetrySessionId, "pi");
206
355
  }
207
356
  catch (err) {
208
357
  dbg(`agent_end deferred_format modified-range tracking failed for ${filePath}: ${err}`);
@@ -244,6 +393,14 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
244
393
  });
245
394
  }
246
395
  }
396
+ // LSP sees only authoritative content after both mutation phases. In
397
+ // particular, never publish the autofix intermediate state before format.
398
+ for (const changedPath of deferredAutofixChanged) {
399
+ if (!nodeFs.existsSync(changedPath))
400
+ continue;
401
+ const content = nodeFs.readFileSync(changedPath, "utf-8");
402
+ await resyncLspFile(changedPath, content, true, false, getFlag, dbg);
403
+ }
247
404
  if (inspectActionableReport) {
248
405
  const actionReport = cacheManager.readCache("actionable-warnings", ctxCwd ?? runtime.projectRoot, 10 * 60_000);
249
406
  if (!actionReport?.data) {
@@ -251,6 +408,14 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
251
408
  }
252
409
  else {
253
410
  const enabledFiles = actionReport.data.files.filter((file) => {
411
+ // #1247: the per-edit dispatch surface gates ignored files before
412
+ // running; the turn-end autofix must apply the same filter or a
413
+ // `.pi-lens.json` `ignore` entry cannot protect a prose file
414
+ // (CHANGELOG.md / AGENTS.md) from being rewritten here.
415
+ if (isPathIgnoredByProject(file.filePath, ctxCwd ?? runtime.projectRoot)) {
416
+ dbg(`agent_end actionable_warnings_autofix: skipped ${file.filePath} (ignored by project)`);
417
+ return false;
418
+ }
254
419
  const enabled = !!getFlag("lens-actionable-warning-autofix", file.filePath);
255
420
  if (!enabled) {
256
421
  const source = getFlagSource?.("lens-actionable-warning-autofix", file.filePath);
@@ -281,49 +446,42 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
281
446
  if (!freshness.fresh) {
282
447
  dbg(`agent_end actionable_warnings_autofix: stale report (${freshness.reason}; reportProjectSeqEnd=${freshness.reportProjectSeqEnd ?? "missing"}; currentProjectSeq=${freshness.currentProjectSeq}${freshness.filePath ? `; file=${freshness.filePath}; reportFileSeq=${freshness.reportFileSeq}; currentFileSeq=${freshness.currentFileSeq}` : ""}), skipping fixes`);
283
448
  }
284
- else {
449
+ else if (eligibleReport.summary.autoFixEligible > 0) {
285
450
  // #684: same "genuine work about to happen" gate as
286
451
  // publishFormatStart — only fires when the report is fresh AND
287
452
  // has at least one autofix-eligible warning, right before
288
453
  // applyConservativeActionableWarningFixes actually starts.
289
- if (eligibleReport.summary.autoFixEligible > 0) {
290
- publishAutofixStart({
291
- cwd: ctxCwd ?? runtime.projectRoot,
292
- paths: eligibleReport.files
293
- .filter((file) => file.warnings.some((warning) => !warning.suppressed &&
294
- warning.actions.some((action) => action.autoFixEligible)))
295
- .map((file) => file.filePath),
296
- eligibleCount: eligibleReport.summary.autoFixEligible,
297
- dbg,
298
- });
299
- }
454
+ publishAutofixStart({
455
+ cwd: ctxCwd ?? runtime.projectRoot,
456
+ paths: eligibleReport.files
457
+ .filter((file) => file.warnings.some((warning) => !warning.suppressed &&
458
+ warning.actions.some((action) => action.autoFixEligible)))
459
+ .map((file) => file.filePath),
460
+ eligibleCount: eligibleReport.summary.autoFixEligible,
461
+ dbg,
462
+ });
300
463
  const fixStart = Date.now();
464
+ const fixCwd = ctxCwd ?? runtime.projectRoot;
465
+ const mutationContext = {
466
+ cwd: fixCwd,
467
+ correlationId: newLspMutationCorrelationId(),
468
+ tool: "lsp-quickfix",
469
+ source: "autofix",
470
+ runtime,
471
+ cacheManager,
472
+ readGuard: getFlag("no-read-guard") ? undefined : runtime.readGuard,
473
+ recordAutofix: getFlag("lens-turn-summary")
474
+ ? (filePath) => runtime.turnSummary.recordAutofix(filePath, { tool: "lsp-quickfix" })
475
+ : undefined,
476
+ dbg,
477
+ };
301
478
  const fixSummary = await applyConservativeActionableWarningFixes({
302
- cwd: ctxCwd ?? runtime.projectRoot,
479
+ cwd: fixCwd,
303
480
  report: eligibleReport,
304
481
  maxFixes: getGlobalActionableWarningMaxFixes(),
305
482
  dbg,
483
+ mutationContext,
306
484
  });
307
- for (const changedFile of fixSummary.changedFiles) {
308
- if (!nodeFs.existsSync(changedFile))
309
- continue;
310
- recordProjectChange({
311
- runtime,
312
- cwd: ctxCwd ?? runtime.projectRoot,
313
- filePath: changedFile,
314
- source: "autofix",
315
- dbg,
316
- });
317
- if (!getFlag("no-read-guard"))
318
- runtime.readGuard.recordWritten(changedFile);
319
- try {
320
- const content = nodeFs.readFileSync(changedFile, "utf-8");
321
- cacheManager.addModifiedRange(changedFile, { start: 1, end: content.split("\n").length }, /^import\s/m.test(content), ctxCwd ?? runtime.projectRoot);
322
- }
323
- catch (err) {
324
- dbg(`agent_end actionable warning changed-file tracking failed for ${changedFile}: ${err}`);
325
- }
326
- }
327
485
  if (fixSummary.changedFiles.length > 0) {
328
486
  publishFilesTouched({
329
487
  reason: "autofix",
@@ -336,13 +494,6 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
336
494
  kind: "autofix",
337
495
  })),
338
496
  });
339
- if (getFlag("lens-turn-summary")) {
340
- for (const changedFile of fixSummary.changedFiles) {
341
- runtime.turnSummary.recordAutofix(changedFile, {
342
- tool: "lsp-quickfix",
343
- });
344
- }
345
- }
346
497
  }
347
498
  logLatency({
348
499
  type: "phase",
@@ -361,8 +512,24 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
361
512
  notify(`pi-lens applied ${fixSummary.applied} conservative LSP warning quickfix(es)`, "info");
362
513
  }
363
514
  }
515
+ else {
516
+ dbg("agent_end actionable_warnings_autofix: fresh report, 0 autofix-eligible warnings, skipping");
517
+ }
364
518
  }
365
519
  }
520
+ logLatency({
521
+ type: "phase",
522
+ toolName: "agent_end",
523
+ filePath: ctxCwd ?? runtime.projectRoot,
524
+ phase: "agent_end_deferred_mutation_drain",
525
+ durationMs: Date.now() - startedAt,
526
+ metadata: {
527
+ autofixRecords: autofixRecords.length,
528
+ formatRecords: formatRecords.length,
529
+ coalescedPaths: records.length,
530
+ requeuedKinds: [...requeuedKinds].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
531
+ },
532
+ });
366
533
  logLatency({
367
534
  type: "tool_result",
368
535
  toolName: "agent_end",
@@ -377,6 +544,19 @@ export async function handleAgentEnd({ ctxCwd, getFlag, getFlagSource, notify, d
377
544
  skipped: summary.skipped.length,
378
545
  },
379
546
  });
547
+ logLatency({
548
+ type: "phase",
549
+ toolName: "agent_end",
550
+ filePath: ctxCwd ?? runtime.projectRoot,
551
+ phase: "agent_end_deferred_format_done",
552
+ durationMs: Date.now() - startedAt,
553
+ metadata: {
554
+ formatted: summary.formatted,
555
+ changed: summary.changed.length,
556
+ failed: summary.failed.length,
557
+ skipped: summary.skipped.length,
558
+ },
559
+ });
380
560
  dbg(`agent_end deferred_format complete: formatted=${summary.formatted} changed=${summary.changed.length} failed=${summary.failed.length} skipped=${summary.skipped.length}`);
381
561
  if (summary.failed.length > 0) {
382
562
  notify(`pi-lens deferred format: ${summary.changed.length} changed, ${summary.failed.length} failed`, "warning");
@@ -1,31 +1,148 @@
1
- export function consumeTurnEndFindings(cacheManager, cwd) {
1
+ import { provenanceStamp, validateAdvisoryProvenance, } from "./advisory-provenance.js";
2
+ import { logLatency } from "./latency-logger.js";
3
+ // Exported so the Stop-hook bin strips exactly what these bridges prepend.
4
+ export const AUTOMATION_FRAMING = "[pi-lens automated check — not a user request] ";
5
+ // #1432 review (S3b): a multi-file bash write can carry hundreds of changed
6
+ // paths, one `reasons` entry apiece — logging all of them shrinks the
7
+ // smells-rollup tail window (a fixed-size ring) to a handful of these
8
+ // records. Cap what this decision row carries; the full list is never
9
+ // needed for triage, only "how many and roughly what kind".
10
+ const MAX_LOGGED_REASONS = 8;
11
+ function boundedReasons(reasons) {
12
+ if (reasons.length <= MAX_LOGGED_REASONS)
13
+ return reasons;
14
+ return [
15
+ ...reasons.slice(0, MAX_LOGGED_REASONS),
16
+ `+${reasons.length - MAX_LOGGED_REASONS} more`,
17
+ ];
18
+ }
19
+ function logProvenanceDecision(validation, provenance, advisoryKind, cwd) {
20
+ logLatency({
21
+ type: "phase",
22
+ phase: "advisory_provenance_decision",
23
+ filePath: cwd,
24
+ durationMs: 0,
25
+ metadata: {
26
+ decision: validation.status === "current" ? "current" : "historical",
27
+ reasons: boundedReasons(validation.reasons),
28
+ changedPathCount: validation.changedPathCount,
29
+ provenanceStamp: provenanceStamp(provenance),
30
+ advisoryKind,
31
+ },
32
+ });
33
+ }
34
+ function historicalPrefix(provenance) {
35
+ return `Historical finding; workspace changed since capture; re-run to confirm. (${provenanceStamp(provenance)})`;
36
+ }
37
+ function historicalTestContent(content, provenance) {
38
+ return content.startsWith("[from a prior turn")
39
+ ? content
40
+ : `${historicalPrefix(provenance)}\n\n${content}`;
41
+ }
42
+ function turnEndMessage(content, current, provenance) {
43
+ return {
44
+ role: "user",
45
+ content: current
46
+ ? `${AUTOMATION_FRAMING}Address 🔴 blockers before continuing; â„šī¸ advisories are informational only.\n\n${content}`
47
+ : `${AUTOMATION_FRAMING}${historicalPrefix(provenance)}\n\n${content}`,
48
+ };
49
+ }
50
+ /** Read a turn-end finding without changing its durable delivery state. */
51
+ export function peekTurnEndFindings(cacheManager, cwd, runtime, logDelivery = false) {
2
52
  const findings = cacheManager.readCache("turn-end-findings", cwd);
3
- if (!findings?.data?.content)
53
+ if (!findings?.data?.content || findings.data.consumed === true)
54
+ return;
55
+ const validation = validateAdvisoryProvenance(findings.data, cwd, runtime);
56
+ if (logDelivery)
57
+ logProvenanceDecision(validation, findings.data.provenance, "turn-end", cwd);
58
+ if (validation.allFilesDeleted)
4
59
  return;
5
- cacheManager.writeCache("turn-end-findings", null, cwd);
6
60
  return {
7
- messages: [
8
- {
9
- role: "user",
10
- content: `[pi-lens automated check — not a user request] Address 🔴 blockers before continuing; â„šī¸ advisories are informational only.\n\n${findings.data.content}`,
11
- },
12
- ],
61
+ messages: [turnEndMessage(findings.data.content, validation.status === "current", findings.data.provenance)],
13
62
  };
14
63
  }
15
- export function consumeTestFindings(cacheManager, cwd) {
64
+ export function consumeTurnEndFindings(cacheManager, cwd, runtime) {
65
+ const findings = cacheManager.readCache("turn-end-findings", cwd);
66
+ if (!findings?.data?.content || findings.data.consumed === true)
67
+ return;
68
+ const validation = validateAdvisoryProvenance(findings.data, cwd, runtime);
69
+ logProvenanceDecision(validation, findings.data.provenance, "turn-end", cwd);
70
+ // A blocker record is also the opt-in commit gate's durable state. Mark the
71
+ // context message consumed without deleting the record; clean/advisory-only
72
+ // records retain the historical consume-and-clear behavior.
73
+ if (findings.data.hasBlockers === true &&
74
+ typeof findings.data.sessionId === "string") {
75
+ cacheManager.writeCache("turn-end-findings", { ...findings.data, consumed: true }, cwd);
76
+ }
77
+ else {
78
+ cacheManager.clearCache("turn-end-findings", cwd);
79
+ }
80
+ if (validation.allFilesDeleted)
81
+ return;
82
+ return {
83
+ messages: [turnEndMessage(findings.data.content, validation.status === "current", findings.data.provenance)],
84
+ };
85
+ }
86
+ /** Read test findings without consuming them; used by acknowledged IPC delivery. */
87
+ export function peekTestFindings(cacheManager, cwd, runtime, logDelivery = false) {
16
88
  const findings = cacheManager.readCache("test-runner-findings", cwd);
17
89
  if (!findings?.data?.content)
18
90
  return;
19
- cacheManager.writeCache("test-runner-findings", null, cwd);
91
+ const validation = validateAdvisoryProvenance(findings.data, cwd, runtime);
92
+ if (logDelivery)
93
+ logProvenanceDecision(validation, findings.data.provenance, "test-findings", cwd);
94
+ if (validation.allFilesDeleted)
95
+ return;
96
+ const current = validation.status === "current";
20
97
  return {
21
98
  messages: [
22
99
  {
23
100
  role: "user",
24
- content: `[pi-lens automated check — not a user request] Test failures detected last turn — fix before continuing:\n\n${findings.data.content}`,
101
+ content: current
102
+ ? `${AUTOMATION_FRAMING}Test failures detected last turn — fix before continuing:\n\n${findings.data.content}`
103
+ : `${AUTOMATION_FRAMING}${historicalTestContent(findings.data.content, findings.data.provenance)}`,
25
104
  },
26
105
  ],
27
106
  };
28
107
  }
108
+ export function consumeTestFindings(cacheManager, cwd, runtime) {
109
+ const record = cacheManager.readCache("test-runner-findings", cwd);
110
+ if (!record?.data?.content)
111
+ return;
112
+ const findings = peekTestFindings(cacheManager, cwd, runtime, true);
113
+ if (!findings)
114
+ return;
115
+ // Retire the content but PRESERVE the generation high-water mark: nulling
116
+ // the whole slot would let a still-in-flight OLDER batch see `undefined`,
117
+ // pass the strictly-greater suppression check, and resurrect a consumed
118
+ // one-shot advisory with stale results. An empty-content record peeks as
119
+ // undelivered while keeping late-generation ordering intact.
120
+ const priorGeneration = cacheManager.readCache("test-runner-findings", cwd)?.data?.testRunGeneration;
121
+ cacheManager.writeCache("test-runner-findings", { content: "", testRunGeneration: priorGeneration }, cwd);
122
+ return findings;
123
+ }
124
+ /** Complete an acknowledged MCP delivery without re-validating or re-rendering it. */
125
+ export function acknowledgeTurnEndFindings(cacheManager, cwd) {
126
+ const findings = cacheManager.readCache("turn-end-findings", cwd);
127
+ if (!findings?.data?.content || findings.data.consumed === true)
128
+ return;
129
+ if (findings.data.hasBlockers === true && typeof findings.data.sessionId === "string") {
130
+ cacheManager.writeCache("turn-end-findings", { ...findings.data, consumed: true }, cwd);
131
+ }
132
+ else {
133
+ cacheManager.clearCache("turn-end-findings", cwd);
134
+ }
135
+ }
136
+ export function acknowledgeTestFindings(cacheManager, cwd) {
137
+ const findings = cacheManager.readCache("test-runner-findings", cwd);
138
+ if (!findings?.data?.content)
139
+ return;
140
+ // Same high-water-mark preservation as consumeTestFindings.
141
+ cacheManager.writeCache("test-runner-findings", {
142
+ content: "",
143
+ testRunGeneration: findings.data.testRunGeneration,
144
+ }, cwd);
145
+ }
29
146
  export function consumeSessionStartGuidance(cacheManager, cwd) {
30
147
  const guidance = cacheManager.readCache("session-start-guidance", cwd);
31
148
  if (!guidance?.data?.content)