@herbertgao/pi-extensions 2026.8.5 → 2026.8.7

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 (389) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +272 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +48 -6
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  17. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  18. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +16 -0
  19. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  20. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  21. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  24. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +22 -15
  25. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  26. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  27. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  28. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  29. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  30. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  32. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  33. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +34 -10
  34. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  35. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +29 -5
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +3 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +46 -10
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +8 -1
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
  51. package/node_modules/@narumitw/pi-btw/README.md +119 -103
  52. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  53. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  54. package/node_modules/@narumitw/pi-btw/package.json +13 -9
  55. package/node_modules/@narumitw/pi-btw/src/btw.ts +40 -42
  56. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  57. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  58. package/node_modules/@narumitw/pi-btw/src/menu.ts +78 -15
  59. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  60. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  61. package/node_modules/pi-lens/CHANGELOG.md +1004 -0
  62. package/node_modules/pi-lens/README.md +11 -3
  63. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  64. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  65. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +427 -0
  66. package/node_modules/pi-lens/dist/clients/agent-nudge.js +79 -16
  67. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  68. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  69. package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
  70. package/node_modules/pi-lens/dist/clients/biome-client.js +176 -37
  71. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  72. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
  73. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  74. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  75. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
  76. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  77. package/node_modules/pi-lens/dist/clients/bus-publish.js +11 -3
  78. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  79. package/node_modules/pi-lens/dist/clients/cascade-format.js +76 -2
  80. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  81. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  82. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  83. package/node_modules/pi-lens/dist/clients/console-guard-install.js +16 -4
  84. package/node_modules/pi-lens/dist/clients/dead-code-client.js +249 -52
  85. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  86. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  87. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
  88. package/node_modules/pi-lens/dist/clients/dependency-checker.js +43 -9
  89. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +153 -37
  90. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  91. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  92. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +165 -11
  93. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +325 -72
  94. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  95. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +81 -41
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +488 -0
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +84 -0
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +943 -93
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +106 -0
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  129. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  130. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  131. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  132. package/node_modules/pi-lens/dist/clients/extension-log.js +317 -3
  133. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  134. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
  135. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  136. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  137. package/node_modules/pi-lens/dist/clients/format-events-publish.js +39 -8
  138. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  139. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  140. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  141. package/node_modules/pi-lens/dist/clients/git-guard.js +49 -21
  142. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  143. package/node_modules/pi-lens/dist/clients/go-client.js +21 -39
  144. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +219 -10
  145. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  146. package/node_modules/pi-lens/dist/clients/host-ports.js +9 -1
  147. package/node_modules/pi-lens/dist/clients/installer/index.js +1119 -101
  148. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  149. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  150. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  151. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  152. package/node_modules/pi-lens/dist/clients/jscpd-client.js +86 -15
  153. package/node_modules/pi-lens/dist/clients/knip-client.js +361 -24
  154. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  155. package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
  156. package/node_modules/pi-lens/dist/clients/latency-logger.js +487 -9
  157. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  158. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  159. package/node_modules/pi-lens/dist/clients/lens-events.js +56 -25
  160. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  161. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +45 -2
  162. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  163. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +160 -20
  164. package/node_modules/pi-lens/dist/clients/lsp/client.js +1666 -148
  165. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +111 -0
  166. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  167. package/node_modules/pi-lens/dist/clients/lsp/index.js +2496 -171
  168. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  169. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  170. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  171. package/node_modules/pi-lens/dist/clients/lsp/server.js +517 -69
  172. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  173. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +172 -0
  175. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  176. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +61 -3
  177. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  178. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  179. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  180. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  181. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +4 -0
  182. package/node_modules/pi-lens/dist/clients/mcp/session.js +39 -18
  183. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  184. package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
  185. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  186. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  187. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  188. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  189. package/node_modules/pi-lens/dist/clients/pipeline.js +178 -30
  190. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  191. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  192. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  193. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +85 -15
  194. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  195. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
  198. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  199. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  200. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  201. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  202. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
  204. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  205. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  206. package/node_modules/pi-lens/dist/clients/review-graph/query.js +76 -4
  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 +248 -13
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +112 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +472 -61
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +359 -13
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +269 -22
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +948 -87
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +21 -37
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  217. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  218. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  219. package/node_modules/pi-lens/dist/clients/security-scan-client.js +224 -8
  220. package/node_modules/pi-lens/dist/clients/sg-runner.js +249 -37
  221. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  222. package/node_modules/pi-lens/dist/clients/smells-rollup.js +18 -11
  223. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  224. package/node_modules/pi-lens/dist/clients/startup-timing.js +26 -2
  225. package/node_modules/pi-lens/dist/clients/test-runner-client.js +574 -32
  226. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  227. package/node_modules/pi-lens/dist/clients/tool-policy.js +127 -20
  228. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  229. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  230. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  233. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  234. package/node_modules/pi-lens/dist/clients/warm-attach.js +17 -0
  235. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  236. package/node_modules/pi-lens/dist/clients/word-index.js +305 -33
  237. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  238. package/node_modules/pi-lens/dist/index.js +64677 -49484
  239. package/node_modules/pi-lens/dist/mcp/server.js +8 -2
  240. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  241. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  242. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  243. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +469 -56
  244. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +190 -46
  245. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  246. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  247. package/node_modules/pi-lens/docs/agent-guide.md +44 -14
  248. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +518 -501
  249. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  250. package/node_modules/pi-lens/docs/features.md +33 -6
  251. package/node_modules/pi-lens/docs/globalconfig.md +14 -0
  252. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  253. package/node_modules/pi-lens/docs/mcp.md +2 -2
  254. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  255. package/node_modules/pi-lens/docs/settings.md +25 -1
  256. package/node_modules/pi-lens/docs/usage.md +24 -5
  257. package/node_modules/pi-lens/docs/word-index.md +35 -0
  258. package/node_modules/pi-lens/package.json +10 -6
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +22 -0
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +9 -0
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +9 -0
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +9 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +9 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +66 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +29 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +30 -0
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +41 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +42 -0
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +32 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  319. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  320. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  321. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  322. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  323. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  324. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +132 -1
  325. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  326. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  327. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +12 -11
  328. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  329. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +87 -116
  330. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +170 -0
  331. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  332. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  333. package/node_modules/pi-mcp-adapter/CHANGELOG.md +49 -0
  334. package/node_modules/pi-mcp-adapter/README.md +51 -6
  335. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  336. package/node_modules/pi-mcp-adapter/cli.js +188 -5
  337. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  338. package/node_modules/pi-mcp-adapter/config.ts +28 -10
  339. package/node_modules/pi-mcp-adapter/direct-tools.ts +23 -19
  340. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  341. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  342. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  343. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  344. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  345. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  346. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  347. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  348. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  349. package/node_modules/pi-mcp-adapter/metadata-cache.ts +46 -25
  350. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  351. package/node_modules/pi-mcp-adapter/package.json +4 -1
  352. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  353. package/node_modules/pi-mcp-adapter/request-headers-command.ts +330 -0
  354. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  355. package/node_modules/pi-mcp-adapter/server-manager.ts +145 -2
  356. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  357. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  358. package/node_modules/pi-mcp-adapter/tool-metadata.ts +38 -18
  359. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  360. package/node_modules/pi-mcp-adapter/types.ts +95 -10
  361. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  362. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  363. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  364. package/node_modules/pi-web-access/README.md +38 -14
  365. package/node_modules/pi-web-access/anysearch.ts +4 -2
  366. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  367. package/node_modules/pi-web-access/brave.ts +16 -4
  368. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  369. package/node_modules/pi-web-access/curator-page.ts +8 -3
  370. package/node_modules/pi-web-access/curator-server.ts +5 -1
  371. package/node_modules/pi-web-access/exa.ts +18 -7
  372. package/node_modules/pi-web-access/extract.ts +134 -37
  373. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  374. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  375. package/node_modules/pi-web-access/gemini-search.ts +33 -7
  376. package/node_modules/pi-web-access/index.ts +160 -104
  377. package/node_modules/pi-web-access/package.json +2 -2
  378. package/node_modules/pi-web-access/page-query.ts +4 -2
  379. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  380. package/node_modules/pi-web-access/parallel.ts +2 -2
  381. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  382. package/node_modules/pi-web-access/serper.ts +211 -0
  383. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  384. package/node_modules/pi-web-access/summary-review.ts +51 -23
  385. package/node_modules/pi-web-access/tavily.ts +16 -4
  386. package/node_modules/pi-web-access/utils.ts +87 -0
  387. package/node_modules/pi-web-access/valyu.ts +199 -0
  388. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  389. package/package.json +13 -13
@@ -1,21 +1,27 @@
1
1
  import * as nodeCrypto from "node:crypto";
2
2
  import * as nodeFs from "node:fs";
3
3
  import * as path from "node:path";
4
- import { extractReadPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, } from "./bash-file-access.js";
4
+ import { noteAuthoritativeContentAttachment } from "./agent-nudge.js";
5
+ import { extractReadPathsFromCommand, extractDeletedPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, } from "./bash-file-access.js";
5
6
  import { registerSearchReads, } from "./search-read-registration.js";
6
7
  import { createFileTime } from "./file-time.js";
7
8
  import { publishFormatQueued } from "./format-events-publish.js";
8
9
  import { isPathIgnoredByProject } from "./file-utils.js";
9
10
  import { getFormatService } from "./format-service.js";
10
- import { isExternalOrVendorFile, normalizeEphemeralMapKey } from "./path-utils.js";
11
+ import { isExternalOrVendorFile, normalizeEphemeralMapKey, pathsEqual } from "./path-utils.js";
11
12
  import { PathKeyedMap } from "./path-keyed-map.js";
12
13
  import { resolveLanguageRootForFile } from "./language-profile.js";
13
14
  import { logLatency } from "./latency-logger.js";
15
+ import { resolveToolCallCorrelationId } from "./tool-event.js";
14
16
  import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
17
+ import { notifyExternalFileChange } from "./lsp/index.js";
15
18
  import { runPipeline } from "./pipeline.js";
19
+ import { renderPostAutofixNotice, } from "./post-autofix-notice.js";
16
20
  import { appendProjectChange, } from "./project-changes.js";
17
21
  import { syncGitGuardRecord } from "./git-guard.js";
18
22
  import { scheduleWordIndexPersist } from "./word-index.js";
23
+ import { RUNTIME_CONFIG } from "./runtime-config.js";
24
+ const AUTHORITATIVE_CONTENT_MAX_BYTES = RUNTIME_CONFIG.pipeline.lspMaxFileBytes;
19
25
  function parseDiffRanges(diff) {
20
26
  const changedLines = [];
21
27
  for (const line of diff.split("\n")) {
@@ -201,12 +207,104 @@ export async function handleToolResult(deps) {
201
207
  const { event, getFlag, getFlagSource, dbg, runtime, cacheManager, biomeClient, ruffClient, metricsClient, resetLSPService, agentBehaviorRecord, formatBehaviorWarnings, } = deps;
202
208
  const rawFilePath = event.input.path;
203
209
  const workspaceRoot = runtime.projectRoot || process.cwd();
210
+ // #1642: a gitignored worktree edit got re-attributed onto a
211
+ // same-relative-path file in the parent checkout because this handler
212
+ // used to always resolve a relative path against `workspaceRoot`
213
+ // (`runtime.projectRoot`), with no idea the call actually ran under a
214
+ // different cwd/worktree.
215
+ //
216
+ // Source-level correction (pi host audit, earendil-works/pi): tool_call's
217
+ // own resolved path is NOT authoritative for what executed —
218
+ // `agent-session.ts:914-919`'s extension-handler contract lets a LATER
219
+ // `tool_call` handler mutate `event.input` in place with no
220
+ // re-validation, and edit's `prepareArguments` rewrites args before the
221
+ // event fires at all. `tool_result.input`, by contrast, is populated
222
+ // from the EXECUTED args (`agent-session.ts:502-516`) — it is the
223
+ // authoritative path source. So the correlation record's job is narrower
224
+ // than "the path": it is the RESOLUTION BASIS (the cwd/worktree the call
225
+ // actually ran under). Every tool_result resolves ITS OWN authoritative
226
+ // `rawFilePath` against that basis, rather than trusting a call-time path
227
+ // that a later handler may have superseded.
228
+ const toolCallId = resolveToolCallCorrelationId(event);
229
+ const attribution = toolCallId !== undefined
230
+ ? runtime.takeToolCallAttribution(toolCallId)
231
+ : undefined;
232
+ let resolutionBasis;
233
+ if (attribution) {
234
+ resolutionBasis = attribution.originCwd;
235
+ }
236
+ else if (toolCallId !== undefined && rawFilePath && !path.isAbsolute(rawFilePath)) {
237
+ // A real correlation id existed (the host DOES support one) but no
238
+ // attribution was recorded under it — evicted, cleared because the
239
+ // call was blocked before it could execute, or simply never seen by
240
+ // `handleToolCall`. A RELATIVE path here is ambiguous: we have no
241
+ // idea which cwd it is relative to, and guessing `workspaceRoot` is
242
+ // exactly the #1642 collapse. Fail CLOSED instead of guessing — no
243
+ // turn state, no deferred work — and log it so a real incident is
244
+ // countable rather than silently mis-attributed.
245
+ const guessedPath = path.resolve(workspaceRoot, rawFilePath);
246
+ // Existence is not execution evidence: a same-named file can exist in
247
+ // the workspace while the tool ran in another cwd. Without the recorded
248
+ // call target and origin cwd there is no comparison to make, so retain the
249
+ // full record and fail closed.
250
+ dbg(`path_attribution_missing: no recorded resolution basis for toolCallId=${toolCallId}, refusing relative path ${rawFilePath} (would have guessed ${guessedPath})`);
251
+ logLatency({
252
+ type: "phase",
253
+ toolName: event.toolName,
254
+ filePath: guessedPath,
255
+ phase: "path_attribution_missing",
256
+ durationMs: 0,
257
+ metadata: { toolCallId, rawFilePath, guessedPath },
258
+ });
259
+ return;
260
+ }
261
+ else {
262
+ // Either an ABSOLUTE path (bash-synthetic writes always pass one —
263
+ // unambiguous regardless of any basis, see the bash-write dispatch
264
+ // below) or a host that supplies NO correlation id at all under any
265
+ // known field name. The latter cannot be correlated by identity full
266
+ // stop; this is the SAME exposure every host had before this fix,
267
+ // not a regression introduced by it.
268
+ resolutionBasis = workspaceRoot;
269
+ }
204
270
  const filePath = rawFilePath
205
271
  ? path.isAbsolute(rawFilePath)
206
272
  ? rawFilePath
207
- : path.resolve(workspaceRoot, rawFilePath)
273
+ : path.resolve(resolutionBasis, rawFilePath)
208
274
  : rawFilePath;
275
+ // Purely diagnostic: tool_call's call-time verdict (computed on ITS OWN
276
+ // resolved path, which may since have been superseded) disagreed with
277
+ // what actually executed. This does NOT gate anything by itself — the
278
+ // ignore re-check below, running on the freshly & correctly resolved
279
+ // `filePath`, is the real decision — but a divergence is exactly the
280
+ // shape of the reported incident, so it is named legibly.
281
+ if (attribution?.skipped &&
282
+ filePath &&
283
+ attribution.resolvedPath &&
284
+ !pathsEqual(filePath, attribution.resolvedPath)) {
285
+ const message = `path_attribution_refused: call target ${attribution.resolvedPath} (originCwd=${attribution.originCwd}) vs tool_result resolved ${filePath}`;
286
+ dbg(message);
287
+ logLatency({
288
+ type: "phase",
289
+ toolName: event.toolName,
290
+ filePath,
291
+ phase: "path_attribution_refused",
292
+ durationMs: 0,
293
+ metadata: {
294
+ callTarget: attribution.resolvedPath,
295
+ resolvedPath: filePath,
296
+ originCwd: attribution.originCwd,
297
+ },
298
+ });
299
+ }
209
300
  const behaviorWarnings = agentBehaviorRecord(event.toolName, filePath);
301
+ const syntheticWriteContent = [];
302
+ // #1590: one shared authoritative-content budget for every path this bash
303
+ // command wrote. It is handed DOWN to each synthetic call so the single
304
+ // attachment decision there sees both limits; nothing re-decides out here.
305
+ const syntheticAttachmentBudget = {
306
+ remaining: AUTHORITATIVE_CONTENT_MAX_BYTES,
307
+ };
210
308
  // Bash writes (redirects, tee, sed -i, cp/mv, touch, git checkout/restore) —
211
309
  // these change file content but never go through the edit tool, so bash
212
310
  // early-returns before the dispatch pipeline below. For each in-project file
@@ -224,11 +322,24 @@ export async function handleToolResult(deps) {
224
322
  for (const wp of written) {
225
323
  if (!getFlag("no-read-guard"))
226
324
  deps.readGuard?.recordWritten(wp);
227
- await handleToolResult({
325
+ const receipt = runtime.recordMutationToolReceipt;
326
+ const autofixMode = receipt
327
+ ? receipt.call(runtime, wp, "write").autofixMode
328
+ : "immediate";
329
+ const syntheticResult = await handleToolResult({
228
330
  ...deps,
229
331
  event: { ...event, toolName: "write", input: { path: wp } },
230
332
  _bypassDebounce: true,
333
+ _autofixMode: autofixMode,
334
+ _attachmentBudget: syntheticAttachmentBudget,
231
335
  });
336
+ if (syntheticResult) {
337
+ // #1590: forward verbatim. The synthetic call already charged the
338
+ // shared budget above and phrased its own notice from the decision
339
+ // it made, so a second verdict out here could only contradict it —
340
+ // which is exactly the defect this shape produced before.
341
+ syntheticWriteContent.push(...syntheticResult.content.slice(event.content.length));
342
+ }
232
343
  }
233
344
  if (event.isError !== true && !getFlag("no-read-guard")) {
234
345
  for (const span of extractReadPathsFromCommand(command, workspaceRoot)) {
@@ -249,6 +360,42 @@ export async function handleToolResult(deps) {
249
360
  });
250
361
  }
251
362
  }
363
+ // #1668: bash-deleted files never go through the edit tool, so nothing
364
+ // else tells an LSP server one of its watched files is gone — the ONLY
365
+ // existing enqueue site fires on first open and can only emit type 1/2.
366
+ // Extract the command's likely delete targets, confirm each by existence
367
+ // (never scan the workspace — only the paths the command named), and only
368
+ // act on paths pi-lens already knows about (a read or a write this
369
+ // session) so an `rm` on something pi-lens never touched is not treated
370
+ // as a signal. Each match is routed to already-active LSP clients as a
371
+ // type-3 watched-files event through the same #271 coalescing queue a
372
+ // burst of deletes still flushes as one notification per server.
373
+ if (event.isError !== true &&
374
+ !getFlag("no-lsp") &&
375
+ !getFlag("no-read-guard")) {
376
+ for (const dp of extractDeletedPathsFromCommand(command, workspaceRoot)) {
377
+ if (isExternalOrVendorFile(dp, workspaceRoot))
378
+ continue;
379
+ if (isPathIgnoredByProject(dp, workspaceRoot, false))
380
+ continue;
381
+ if (!deps.readGuard || !deps.readGuard.hasKnownPath(dp))
382
+ continue;
383
+ // #1668 review F4: this is the ONLY gate standing between a merely
384
+ // NAMED path and an actual confirmed delete — extractDeletedPathsFromCommand
385
+ // only proposes candidates from parsing the command text, so it can't
386
+ // tell `git rm --cached f` (index-only, file still on disk) from a
387
+ // real delete, can't see a short-circuited `rm f && false` that never
388
+ // ran, and can't resolve a relative path run from a `cd`-ed subdirectory
389
+ // against the wrong cwd. Every one of those is caught here, and only
390
+ // here — do not remove or reorder this check relative to the loop body.
391
+ if (nodeFs.existsSync(dp))
392
+ continue; // still there — not a real delete
393
+ deps.readGuard.forgetPath(dp);
394
+ void notifyExternalFileChange(dp, 3).catch((err) => {
395
+ dbg(`tool_result: external-delete notify failed for ${dp}: ${err}`);
396
+ });
397
+ }
398
+ }
252
399
  }
253
400
  // Search tools reveal specific lines (file:line) the agent then edits — register
254
401
  // those shown lines (± context) as reads so the follow-up edit isn't blocked (#169).
@@ -277,7 +424,9 @@ export async function handleToolResult(deps) {
277
424
  }
278
425
  if (event.toolName !== "write" && event.toolName !== "edit") {
279
426
  dbg(`tool_result: skipped turn tracking - toolName="${event.toolName}" (not write/edit)`);
280
- return;
427
+ return syntheticWriteContent.length > 0
428
+ ? { content: [...event.content, ...syntheticWriteContent] }
429
+ : undefined;
281
430
  }
282
431
  if (!filePath) {
283
432
  dbg(`tool_result: skipped turn tracking - no filePath for toolName="${event.toolName}"`);
@@ -324,6 +473,16 @@ export async function handleToolResult(deps) {
324
473
  });
325
474
  return { content: event.content, isError: true };
326
475
  }
476
+ // Must happen before debounce admission: latestDeps intentionally retains only
477
+ // the latest event, but write -> edit is a sticky turn transition.
478
+ const receipt = runtime.recordMutationToolReceipt;
479
+ const autofixMode = deps._bypassDebounce
480
+ ? (deps._autofixMode ?? (event.toolName === "edit" ? "deferred" : "immediate"))
481
+ : receipt
482
+ ? receipt.call(runtime, filePath, event.toolName).autofixMode
483
+ : event.toolName === "edit"
484
+ ? "deferred"
485
+ : "immediate";
327
486
  // Coalesce sequential edits to the same file into one pipeline run against
328
487
  // the final state. Only the debounce-fired call (with _bypassDebounce=true)
329
488
  // proceeds to the pipeline body; in-window callers share its promise.
@@ -332,6 +491,7 @@ export async function handleToolResult(deps) {
332
491
  if (debounceMs > 0) {
333
492
  return scheduleDebounced(filePath, debounceMs, {
334
493
  ...deps,
494
+ _autofixMode: autofixMode,
335
495
  _telemetryParticipantIds: [readGuardCorrelationId],
336
496
  _telemetryParticipantTotal: 1,
337
497
  });
@@ -402,13 +562,15 @@ export async function handleToolResult(deps) {
402
562
  const dispatchCwd = resolveLanguageRootForFile(filePath, workspaceRoot);
403
563
  const turnStateCwd = path.resolve(workspaceRoot);
404
564
  dbg(`tool_result: resolved dispatch cwd ${dispatchCwd} for ${filePath} (turnState cwd ${turnStateCwd})`);
405
- if (event.model || event.provider || event.sessionId || event.session?.id) {
406
- runtime.setTelemetryIdentity({
407
- model: event.model,
408
- provider: event.provider,
409
- sessionId: event.sessionId ?? event.session?.id,
410
- });
411
- }
565
+ // #1655 item 2: a `setTelemetryIdentity` call used to sit here, gated on
566
+ // `event.model`/`provider`/`sessionId`/`session.id`. pi sets none of those on
567
+ // a `tool_result` — `afterToolCall` builds the event with exactly
568
+ // `type`/`toolName`/`toolCallId`/`input`/`content`/`details`/`isError`/`usage`
569
+ // (`@earendil-works/pi-coding-agent/dist/core/agent-session.js:243-256`,
570
+ // source `src/core/agent-session.ts:502-516`), so the gate was always false
571
+ // against a real host and the branch never ran. Identity for this dispatch
572
+ // comes from the runtime, which `message_start`/`session_start` populate —
573
+ // see the `telemetry:` block handed to `runPipeline` below.
412
574
  const writeIndex = runtime.nextWriteIndex();
413
575
  let modifiedRanges;
414
576
  try {
@@ -469,12 +631,15 @@ export async function handleToolResult(deps) {
469
631
  cwd: dispatchCwd,
470
632
  projectRoot: turnStateCwd,
471
633
  toolName: event.toolName,
634
+ autofixMode,
472
635
  modifiedRanges,
473
636
  telemetry: {
474
637
  model: runtime.telemetryModel,
475
638
  sessionId: runtime.telemetrySessionId,
476
639
  turnIndex: runtime.turnIndex,
477
640
  writeIndex,
641
+ modelId: runtime.telemetryModelId,
642
+ provider: runtime.telemetryProviderId,
478
643
  },
479
644
  getFlag,
480
645
  getFlagSource,
@@ -487,6 +652,9 @@ export async function handleToolResult(deps) {
487
652
  projectSeq: () => runtime.projectSeq,
488
653
  getFilesChangedSince: (seq) => runtime.getFilesChangedSince(seq),
489
654
  },
655
+ // The settle clock is live because the deferred cascade may reach its
656
+ // budget derivation before or after turn_end starts waiting.
657
+ turnEndCascadeSettleStart: () => runtime.getTurnEndCascadeSettleStart(),
490
658
  // #348 phase 2: live reference so the deferred cascade can update the
491
659
  // warm word index in place at the same seam as the graph rebuild.
492
660
  // `runtime.wordIndex` is read fresh (not captured) via this closure-free
@@ -638,11 +806,19 @@ export async function handleToolResult(deps) {
638
806
  }
639
807
  }
640
808
  }
809
+ let autofixNewlyQueued = false;
810
+ if (!result.isError && autofixMode === "deferred" && nodeFs.existsSync(filePath)) {
811
+ autofixNewlyQueued =
812
+ runtime.deferMutation?.call(runtime, filePath, dispatchCwd, event.toolName, turnStateCwd, "autofix", deps.sessionId, resolutionBasis) ?? false;
813
+ dbg(`tool_result: queued deferred autofix for ${filePath}`);
814
+ }
815
+ let formatQueued = false;
641
816
  if (!result.isError &&
642
817
  !getFlag("no-autoformat", filePath) &&
643
- !getFlag("immediate-format") &&
818
+ (autofixMode === "deferred" || !getFlag("immediate-format")) &&
644
819
  nodeFs.existsSync(filePath)) {
645
- const isNewlyQueued = runtime.deferFormat(filePath, dispatchCwd, event.toolName, turnStateCwd, deps.sessionId);
820
+ const isNewlyQueued = runtime.deferFormat(filePath, dispatchCwd, event.toolName, turnStateCwd, deps.sessionId, resolutionBasis);
821
+ formatQueued = true;
646
822
  dbg(`tool_result: queued deferred format for ${filePath}`);
647
823
  logLatency({
648
824
  type: "phase",
@@ -652,19 +828,21 @@ export async function handleToolResult(deps) {
652
828
  durationMs: 0,
653
829
  metadata: { cwd: dispatchCwd },
654
830
  });
655
- // #673: only publish on first queue entry — a re-touch of an already
656
- // queued file (a second edit before agent_end) is a structural no-op
657
- // for a listener that just wants to know "has this file entered the
658
- // queue", so re-emitting would be spam with zero new information.
659
- if (isNewlyQueued) {
831
+ // Publish a file's first queue entry and each newly added kind. A same-kind
832
+ // re-touch before agent_end carries no new information and stays silent.
833
+ if (isNewlyQueued || autofixNewlyQueued) {
660
834
  publishFormatQueued({
661
835
  filePath,
662
836
  cwd: dispatchCwd,
663
837
  tool: event.toolName,
664
838
  dbg,
839
+ kinds: autofixMode === "deferred" ? ["autofix", "format"] : ["format"],
665
840
  });
666
841
  }
667
842
  }
843
+ if (autofixNewlyQueued && !formatQueued) {
844
+ publishFormatQueued({ filePath, cwd: dispatchCwd, tool: event.toolName, kinds: ["autofix"], dbg });
845
+ }
668
846
  for (const changedFile of result.changedFiles ?? []) {
669
847
  const resolvedChanged = path.resolve(changedFile);
670
848
  if (!nodeFs.existsSync(resolvedChanged))
@@ -733,7 +911,10 @@ export async function handleToolResult(deps) {
733
911
  }
734
912
  }
735
913
  if (result.inlineBlockerSummary) {
736
- runtime.recordInlineBlockers(filePath, result.inlineBlockerSummary);
914
+ // #1561: stamp the verdict with THIS dispatch's write token — the same
915
+ // counter `lsp_diagnostics`' reconciliation seam draws from — so a later
916
+ // confirmed-clean result can be ordered against it instead of racing it.
917
+ runtime.recordInlineBlockers(filePath, result.inlineBlockerSummary, writeIndex, result.inlineBlockerSources, result.inlineBlockerLines);
737
918
  }
738
919
  else {
739
920
  runtime.clearInlineBlockers(filePath);
@@ -764,9 +945,75 @@ export async function handleToolResult(deps) {
764
945
  result: output ? "completed" : "no_output",
765
946
  });
766
947
  runtime.reportedThisTurn.add(filePath);
767
- if (!output)
948
+ // --- The ONE authoritative-attachment decision (#1590) ---
949
+ // Everything downstream — the attached block, the telemetry row, the nudge
950
+ // suppression, and the notice sentence — reads this single verdict. It is
951
+ // the only place that sees both limits: the per-file cap and the shared
952
+ // per-command budget a multi-file bash write threads in.
953
+ const postMutation = result.postMutation;
954
+ const attachmentText = postMutation
955
+ ? `pi-lens applied autofix to ${postMutation.filePath}. The following full content is authoritative for subsequent edits:\n\n${postMutation.content}`
956
+ : "";
957
+ const contentBytes = postMutation
958
+ ? Buffer.byteLength(postMutation.content, "utf-8")
959
+ : 0;
960
+ const withinPerFileCap = contentBytes <= AUTHORITATIVE_CONTENT_MAX_BYTES;
961
+ const budget = deps._attachmentBudget;
962
+ const withinSharedBudget = !budget || Buffer.byteLength(attachmentText, "utf-8") <= budget.remaining;
963
+ const attachAuthoritativeContent = postMutation !== undefined && withinPerFileCap && withinSharedBudget;
964
+ const attachmentDecision = !postMutation
965
+ ? "none"
966
+ : attachAuthoritativeContent
967
+ ? "attached"
968
+ : withinPerFileCap
969
+ ? "aggregate-budget-degraded"
970
+ : "size-capped";
971
+ // #1590: the pipeline hands up the changed-file data and this layer renders
972
+ // the sentence, so a size-capped write can no longer carry both "attached
973
+ // content is authoritative" and "too large to attach". The fallback covers
974
+ // a post-mutation with no notice data, which must still say re-read.
975
+ const notice = result.postAutofixNotice ??
976
+ (postMutation
977
+ ? { targetPath: postMutation.filePath, changedFiles: [] }
978
+ : undefined);
979
+ if (postMutation && attachAuthoritativeContent && budget) {
980
+ budget.remaining -= Buffer.byteLength(attachmentText, "utf-8");
981
+ }
982
+ // #1590 review F1: every mutation that produced a notice logs a row,
983
+ // INCLUDING the `none` decision a format-only change makes. Gating the row
984
+ // on `postMutation` made a legitimate "nothing was attachable here" verdict
985
+ // indistinguishable from missing instrumentation, which is the same
986
+ // empty-vs-errored confusion the read paths already guard against.
987
+ if (postMutation || notice) {
988
+ logLatency({
989
+ type: "phase",
990
+ phase: "authoritative_content_attachment_decision",
991
+ filePath: postMutation?.filePath ?? filePath,
992
+ durationMs: 0,
993
+ metadata: {
994
+ path: postMutation?.filePath ?? filePath,
995
+ bytes: contentBytes,
996
+ decision: attachmentDecision,
997
+ },
998
+ });
999
+ }
1000
+ if (postMutation) {
1001
+ // #1464: the nudge suppresses exactly the paths this decision
1002
+ // delivered. Same boolean the attachment below reads — the nudge layer
1003
+ // never re-derives the cap or the budget for itself.
1004
+ noteAuthoritativeContentAttachment(postMutation.filePath, attachAuthoritativeContent);
1005
+ }
1006
+ const returnedContent = attachAuthoritativeContent
1007
+ ? [...event.content, { type: "text", text: attachmentText }]
1008
+ : event.content;
1009
+ if (notice) {
1010
+ output = `${output ? `${output}\n\n` : ""}${renderPostAutofixNotice(notice, attachmentDecision)}`;
1011
+ }
1012
+ if (!output && !result.postMutation)
768
1013
  return;
769
1014
  return {
770
- content: [...event.content, { type: "text", text: output }],
1015
+ content: output
1016
+ ? [...returnedContent, { type: "text", text: output }]
1017
+ : returnedContent,
771
1018
  };
772
1019
  }