@herbertgao/pi-extensions 2026.8.11 → 2026.8.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (476) hide show
  1. package/README.md +23 -10
  2. package/{node_modules/@herbertgao/pi-mermaid-open/LICENSE → THIRD_PARTY_NOTICES.md} +19 -1
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +15 -0
  4. package/node_modules/@czottmann/pi-automode/README.md +5 -3
  5. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +2 -0
  6. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-002-global-config-in-extension-data-directory.md +60 -0
  7. package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +1 -0
  8. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +4 -4
  9. package/node_modules/@czottmann/pi-automode/docs/configuration.md +20 -4
  10. package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +1 -1
  11. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/bash.ts +692 -0
  12. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +181 -3
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +4 -1
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +143 -36
  15. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +103 -148
  16. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +32 -6
  17. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +344 -22
  18. package/node_modules/@czottmann/pi-automode/extensions/auto-mode.ts +1 -0
  19. package/node_modules/@czottmann/pi-automode/package.json +4 -1
  20. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -1
  21. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -1
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +4 -0
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +21 -1
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +1 -1
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +19 -19
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +4 -2
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +2 -1
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +10 -2
  29. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  30. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +10 -0
  31. package/node_modules/@herbertgao/pi-subagents/README.md +21 -15
  32. package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
  33. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +11 -8
  34. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +184 -106
  35. package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +31 -11
  36. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +9 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/index.ts +156 -31
  38. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +17 -0
  39. package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +14 -0
  40. package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +8 -0
  41. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +32 -1
  42. package/node_modules/@herbertgao/pi-subagents/src/types.ts +17 -2
  43. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +23 -2
  44. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +259 -24
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  46. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +376 -0
  47. package/node_modules/@luxusai/pi-hindsight/README.md +92 -0
  48. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +56 -0
  49. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +169 -0
  50. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +107 -0
  51. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +89 -0
  52. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +189 -0
  53. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  54. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  55. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +54 -0
  56. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +75 -0
  57. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +300 -0
  58. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +158 -0
  59. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +164 -0
  60. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +139 -0
  61. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +74 -0
  62. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +261 -0
  63. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +151 -0
  64. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +18 -0
  65. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +46 -0
  66. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +383 -0
  67. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +240 -0
  68. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +176 -0
  69. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +178 -0
  70. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +41 -0
  71. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +386 -0
  72. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +39 -0
  73. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +34 -0
  74. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +140 -0
  75. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +61 -0
  76. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +925 -0
  77. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +247 -0
  78. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +547 -0
  79. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +480 -0
  80. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +182 -0
  81. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +86 -0
  82. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +1010 -0
  83. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +175 -0
  84. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +425 -0
  85. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +210 -0
  86. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +817 -0
  87. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +25 -0
  88. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +319 -0
  89. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +196 -0
  90. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +189 -0
  91. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +65 -0
  92. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +260 -0
  93. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +244 -0
  94. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +59 -0
  95. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +82 -0
  96. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +45 -0
  97. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +331 -0
  98. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +354 -0
  99. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +66 -0
  100. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +132 -0
  101. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +228 -0
  102. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +74 -0
  103. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +16 -0
  104. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +648 -0
  105. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +105 -0
  106. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +68 -0
  107. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +71 -0
  108. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +13 -0
  109. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +162 -0
  110. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +131 -0
  111. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +104 -0
  112. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +37 -0
  113. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +893 -0
  114. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +35 -0
  115. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +177 -0
  116. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +7 -0
  117. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +21 -0
  118. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +112 -0
  119. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +111 -0
  120. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +214 -0
  121. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +70 -0
  122. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +392 -0
  123. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +45 -0
  124. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +9 -0
  125. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +860 -0
  126. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +105 -0
  127. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +189 -0
  128. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +299 -0
  129. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +201 -0
  130. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +47 -0
  131. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +239 -0
  132. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +50 -0
  133. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +259 -0
  134. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +77 -0
  135. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +534 -0
  136. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +319 -0
  137. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +325 -0
  138. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +42 -0
  139. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +244 -0
  140. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +56 -0
  141. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +50 -0
  142. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +167 -0
  143. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +207 -0
  144. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +120 -0
  145. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +8 -0
  146. package/node_modules/@luxusai/pi-hindsight/package.json +118 -0
  147. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +75 -0
  148. package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -46
  149. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  150. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  151. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +136 -22
  152. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/README.md +2 -4
  153. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/package.json +5 -15
  154. package/node_modules/{@herbertgao → @tifan}/pi-handoff/README.md +4 -6
  155. package/node_modules/@tifan/pi-handoff/package.json +43 -0
  156. package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/index.ts +1 -1
  157. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/README.md +2 -4
  158. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/package.json +5 -15
  159. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/README.md +5 -7
  160. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/package.json +5 -19
  161. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/README.md +4 -6
  162. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/package.json +6 -16
  163. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/src/index.ts +1 -6
  164. package/node_modules/{@herbertgao → @tifan}/pi-recap/README.md +4 -6
  165. package/node_modules/@tifan/pi-recap/package.json +42 -0
  166. package/node_modules/{@herbertgao → @tifan}/pi-recap/src/models.ts +1 -6
  167. package/node_modules/{@herbertgao → @tifan}/pi-rename/README.md +13 -8
  168. package/node_modules/@tifan/pi-rename/package.json +47 -0
  169. package/node_modules/@tifan/pi-rename/src/herdr-label.ts +4 -0
  170. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/index.ts +4 -16
  171. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/models.ts +1 -6
  172. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/README.md +2 -4
  173. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/package.json +5 -15
  174. package/node_modules/pi-lens/CHANGELOG.md +96 -1
  175. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +14 -5
  177. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +48 -18
  178. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -3
  179. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +16 -4
  180. package/node_modules/pi-lens/dist/clients/bash-file-access.js +3 -1
  181. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -3
  182. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +21 -8
  183. package/node_modules/pi-lens/dist/clients/bounded-cache.js +24 -8
  184. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +4 -3
  185. package/node_modules/pi-lens/dist/clients/cache-manager.js +6 -7
  186. package/node_modules/pi-lens/dist/clients/cache-observability.js +461 -66
  187. package/node_modules/pi-lens/dist/clients/call-graph.js +238 -63
  188. package/node_modules/pi-lens/dist/clients/codebase-model.js +13 -5
  189. package/node_modules/pi-lens/dist/clients/complexity-client.js +1 -3
  190. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -8
  191. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +1 -2
  192. package/node_modules/pi-lens/dist/clients/deadline-utils.js +3 -1
  193. package/node_modules/pi-lens/dist/clients/debug-heap.js +8 -1
  194. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +1 -1
  195. package/node_modules/pi-lens/dist/clients/dependency-checker.js +11 -7
  196. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -2
  197. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +5 -1
  198. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +2 -3
  199. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +13 -1
  200. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +3 -1
  201. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +2 -1
  202. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -4
  204. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +3 -1
  205. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +6 -2
  206. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +31 -7
  207. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +5 -2
  208. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +10 -14
  209. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +5 -1
  210. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +1 -1
  211. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +3 -1
  212. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +25 -6
  213. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +1 -1
  214. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +1 -1
  215. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +3 -1
  216. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +13 -8
  217. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +4 -1
  218. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +25 -10
  219. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +1 -1
  220. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +1 -1
  221. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +1 -1
  222. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +28 -4
  223. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +6 -8
  224. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +212 -11
  225. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +1 -1
  226. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +8 -4
  227. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -6
  228. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +23 -14
  229. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -1
  230. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +7 -9
  231. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +7 -7
  233. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +6 -8
  234. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +13 -8
  235. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +13 -8
  236. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +17 -3
  237. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +7 -1
  238. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +24 -1
  239. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +35 -0
  240. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +1 -3
  241. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +6 -8
  242. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +1 -1
  243. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +2 -1
  244. package/node_modules/pi-lens/dist/clients/dispatch/types.js +6 -1
  245. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +6 -2
  246. package/node_modules/pi-lens/dist/clients/extension-log.js +5 -3
  247. package/node_modules/pi-lens/dist/clients/feature-hints.js +8 -1
  248. package/node_modules/pi-lens/dist/clients/file-kinds.js +34 -129
  249. package/node_modules/pi-lens/dist/clients/file-utils.js +17 -1
  250. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +57 -2
  251. package/node_modules/pi-lens/dist/clients/formatters.js +144 -27
  252. package/node_modules/pi-lens/dist/clients/freshness.js +38 -0
  253. package/node_modules/pi-lens/dist/clients/git-guard.js +43 -13
  254. package/node_modules/pi-lens/dist/clients/go-client.js +1 -3
  255. package/node_modules/pi-lens/dist/clients/grammar-source.js +1 -1
  256. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +30 -4
  257. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +1 -3
  258. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +4 -2
  259. package/node_modules/pi-lens/dist/clients/installer/index.js +86 -77
  260. package/node_modules/pi-lens/dist/clients/instance-reaper.js +5 -2
  261. package/node_modules/pi-lens/dist/clients/instance-registry.js +4 -2
  262. package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
  263. package/node_modules/pi-lens/dist/clients/knip-client.js +29 -15
  264. package/node_modules/pi-lens/dist/clients/language-profile.js +4 -1
  265. package/node_modules/pi-lens/dist/clients/latency-logger.js +13 -2
  266. package/node_modules/pi-lens/dist/clients/lens-config.js +1 -1
  267. package/node_modules/pi-lens/dist/clients/lens-map.js +8 -3
  268. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +1 -1
  269. package/node_modules/pi-lens/dist/clients/lsp/config.js +4 -6
  270. package/node_modules/pi-lens/dist/clients/lsp/edits.js +119 -32
  271. package/node_modules/pi-lens/dist/clients/lsp/index.js +94 -35
  272. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +2 -1
  273. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +4 -1
  274. package/node_modules/pi-lens/dist/clients/lsp/launch.js +11 -3
  275. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +152 -0
  276. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -7
  277. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +10 -2
  278. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +9 -4
  279. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -3
  280. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +10 -20
  281. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +1 -1
  282. package/node_modules/pi-lens/dist/clients/memory-sampler.js +73 -7
  283. package/node_modules/pi-lens/dist/clients/metrics-client.js +1 -3
  284. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +8 -3
  285. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +7 -1
  286. package/node_modules/pi-lens/dist/clients/module-report.js +14 -17
  287. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +3 -5
  288. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +220 -0
  289. package/node_modules/pi-lens/dist/clients/package-manager.js +6 -1
  290. package/node_modules/pi-lens/dist/clients/pipeline.js +57 -9
  291. package/node_modules/pi-lens/dist/clients/project-conventions.js +2 -8
  292. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +10 -7
  293. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +2 -1
  294. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +3 -1
  295. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +13 -9
  296. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +3 -1
  297. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -2
  298. package/node_modules/pi-lens/dist/clients/project-lens-config.js +12 -5
  299. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +48 -0
  300. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +15 -1
  301. package/node_modules/pi-lens/dist/clients/project-snapshot.js +472 -66
  302. package/node_modules/pi-lens/dist/clients/read-expansion.js +12 -2
  303. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +5 -4
  304. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +5 -2
  305. package/node_modules/pi-lens/dist/clients/read-guard.js +1 -1
  306. package/node_modules/pi-lens/dist/clients/resource-sampler.js +1 -1
  307. package/node_modules/pi-lens/dist/clients/reverse-deps.js +6 -5
  308. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +42 -17
  309. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +8 -2
  310. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +10 -1
  311. package/node_modules/pi-lens/dist/clients/review-graph/query.js +2 -1
  312. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +4 -2
  313. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +2 -2
  314. package/node_modules/pi-lens/dist/clients/ruff-client.js +6 -5
  315. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +63 -31
  316. package/node_modules/pi-lens/dist/clients/runtime-context.js +12 -4
  317. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +83 -4
  318. package/node_modules/pi-lens/dist/clients/runtime-session.js +14 -0
  319. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +59 -3
  320. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +148 -34
  321. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -6
  322. package/node_modules/pi-lens/dist/clients/rust-client.js +1 -3
  323. package/node_modules/pi-lens/dist/clients/safe-spawn.js +150 -11
  324. package/node_modules/pi-lens/dist/clients/security-scan-client.js +1 -3
  325. package/node_modules/pi-lens/dist/clients/session-summary.js +3 -1
  326. package/node_modules/pi-lens/dist/clients/sg-runner.js +1 -3
  327. package/node_modules/pi-lens/dist/clients/source-filter.js +10 -6
  328. package/node_modules/pi-lens/dist/clients/source-walker.js +1 -1
  329. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +96 -0
  330. package/node_modules/pi-lens/dist/clients/startup-scan.js +4 -1
  331. package/node_modules/pi-lens/dist/clients/tool-definition.js +7 -0
  332. package/node_modules/pi-lens/dist/clients/tool-policy.js +26 -11
  333. package/node_modules/pi-lens/dist/clients/tool-render.js +2 -1
  334. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +10 -4
  335. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  336. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +12 -5
  337. package/node_modules/pi-lens/dist/clients/warm-attach.js +12 -5
  338. package/node_modules/pi-lens/dist/clients/widget-state.js +27 -11
  339. package/node_modules/pi-lens/dist/clients/word-index.js +3 -1
  340. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -2
  341. package/node_modules/pi-lens/dist/clients/zizmor-config.js +9 -1
  342. package/node_modules/pi-lens/dist/i18n.js +13 -5
  343. package/node_modules/pi-lens/dist/index.js +10797 -8627
  344. package/node_modules/pi-lens/dist/mcp/server.js +3 -1
  345. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +68 -12
  346. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +21 -7
  347. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +164 -35
  348. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +24 -7
  349. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
  350. package/node_modules/pi-lens/dist/tools/module-report.js +1 -1
  351. package/node_modules/pi-lens/dist/tools/project-report.js +1 -1
  352. package/node_modules/pi-lens/dist/tools/symbol-search.js +5 -2
  353. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +1 -1
  354. package/node_modules/pi-lens/docs/servercapabilities.md +1 -1
  355. package/node_modules/pi-lens/package.json +160 -156
  356. package/node_modules/pi-lens/rules/typos/_typos.toml +2 -2
  357. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +31 -13
  358. package/node_modules/pi-lens/scripts/download-grammars.js +9 -3
  359. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +30 -9
  360. package/node_modules/pi-mcp-adapter/CHANGELOG.md +47 -0
  361. package/node_modules/pi-mcp-adapter/README.md +42 -13
  362. package/node_modules/pi-mcp-adapter/commands.ts +4 -2
  363. package/node_modules/pi-mcp-adapter/config.ts +45 -5
  364. package/node_modules/pi-mcp-adapter/direct-tools.ts +103 -92
  365. package/node_modules/pi-mcp-adapter/dist/agent-dir.d.ts +10 -0
  366. package/node_modules/pi-mcp-adapter/dist/agent-dir.js +63 -0
  367. package/node_modules/pi-mcp-adapter/dist/agent-dir.js.map +1 -0
  368. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.d.ts +8 -0
  369. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js +356 -0
  370. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js.map +1 -0
  371. package/node_modules/pi-mcp-adapter/dist/config.d.ts +123 -0
  372. package/node_modules/pi-mcp-adapter/dist/config.js +1087 -0
  373. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -0
  374. package/node_modules/pi-mcp-adapter/dist/metadata-cache.d.ts +19 -0
  375. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +319 -0
  376. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -0
  377. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.d.ts +2 -0
  378. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js +156 -0
  379. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js.map +1 -0
  380. package/node_modules/pi-mcp-adapter/dist/resource-tools.d.ts +1 -0
  381. package/node_modules/pi-mcp-adapter/dist/resource-tools.js +15 -0
  382. package/node_modules/pi-mcp-adapter/dist/resource-tools.js.map +1 -0
  383. package/node_modules/pi-mcp-adapter/dist/types.d.ts +564 -0
  384. package/node_modules/pi-mcp-adapter/dist/types.js +287 -0
  385. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -0
  386. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.d.ts +6 -0
  387. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js +37 -0
  388. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js.map +1 -0
  389. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.d.ts +104 -0
  390. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js +59 -0
  391. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js.map +1 -0
  392. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.d.ts +4 -0
  393. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js +27 -0
  394. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js.map +1 -0
  395. package/node_modules/pi-mcp-adapter/dist/utils.d.ts +32 -0
  396. package/node_modules/pi-mcp-adapter/dist/utils.js +338 -0
  397. package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -0
  398. package/node_modules/pi-mcp-adapter/failure-backoff.ts +23 -0
  399. package/node_modules/pi-mcp-adapter/index.ts +204 -82
  400. package/node_modules/pi-mcp-adapter/init.ts +41 -30
  401. package/node_modules/pi-mcp-adapter/lifecycle.ts +16 -8
  402. package/node_modules/pi-mcp-adapter/mcp-code.ts +2 -0
  403. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +66 -16
  404. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +95 -7
  405. package/node_modules/pi-mcp-adapter/mcp-probe.ts +18 -4
  406. package/node_modules/pi-mcp-adapter/mcp-references.ts +368 -0
  407. package/node_modules/pi-mcp-adapter/mcp-status.ts +8 -19
  408. package/node_modules/pi-mcp-adapter/metadata-cache.ts +20 -12
  409. package/node_modules/pi-mcp-adapter/namespace-tools.ts +276 -0
  410. package/node_modules/pi-mcp-adapter/package.json +24 -6
  411. package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -10
  412. package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -0
  413. package/node_modules/pi-mcp-adapter/server-manager.ts +63 -12
  414. package/node_modules/pi-mcp-adapter/state.ts +1 -3
  415. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +16 -2
  416. package/node_modules/pi-mcp-adapter/types.ts +48 -1
  417. package/node_modules/pi-mcp-adapter/ui-server.ts +3 -19
  418. package/node_modules/pi-mcp-adapter/ui-session.ts +2 -1
  419. package/node_modules/pi-mcp-adapter/utils.ts +21 -19
  420. package/node_modules/pi-web-access/CHANGELOG.md +26 -0
  421. package/node_modules/pi-web-access/README.md +71 -14
  422. package/node_modules/pi-web-access/chrome-cookies.ts +115 -35
  423. package/node_modules/pi-web-access/credential-source.ts +6 -2
  424. package/node_modules/pi-web-access/curator-page.ts +5 -3
  425. package/node_modules/pi-web-access/curator-server.ts +2 -1
  426. package/node_modules/pi-web-access/extract.ts +89 -9
  427. package/node_modules/pi-web-access/fetch-params.ts +13 -0
  428. package/node_modules/pi-web-access/gemini-adc.ts +298 -0
  429. package/node_modules/pi-web-access/gemini-api.ts +59 -15
  430. package/node_modules/pi-web-access/gemini-search.ts +58 -18
  431. package/node_modules/pi-web-access/gemini-url-context.ts +3 -2
  432. package/node_modules/pi-web-access/gemini-web-config.ts +57 -7
  433. package/node_modules/pi-web-access/gemini-web.ts +9 -3
  434. package/node_modules/pi-web-access/github-api.ts +5 -4
  435. package/node_modules/pi-web-access/github-issue-pr.ts +700 -0
  436. package/node_modules/pi-web-access/index.ts +403 -297
  437. package/node_modules/pi-web-access/kimi-search.ts +234 -0
  438. package/node_modules/pi-web-access/openai-search.ts +118 -21
  439. package/node_modules/pi-web-access/package.json +3 -2
  440. package/node_modules/pi-web-access/ssrf-protection.ts +4 -1
  441. package/node_modules/pi-web-access/utils.ts +307 -1
  442. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  443. package/package.json +46 -37
  444. package/node_modules/@herbertgao/pi-copy-response/CHANGELOG.md +0 -49
  445. package/node_modules/@herbertgao/pi-copy-response/LICENSE +0 -22
  446. package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +0 -83
  447. package/node_modules/@herbertgao/pi-handoff/LICENSE +0 -22
  448. package/node_modules/@herbertgao/pi-handoff/package.json +0 -60
  449. package/node_modules/@herbertgao/pi-inline-skills/CHANGELOG.md +0 -57
  450. package/node_modules/@herbertgao/pi-inline-skills/LICENSE +0 -22
  451. package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +0 -39
  452. package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +0 -63
  453. package/node_modules/@herbertgao/pi-preferred-thinking/LICENSE +0 -22
  454. package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +0 -101
  455. package/node_modules/@herbertgao/pi-recap/LICENSE +0 -22
  456. package/node_modules/@herbertgao/pi-recap/package.json +0 -55
  457. package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +0 -49
  458. package/node_modules/@herbertgao/pi-rename/LICENSE +0 -22
  459. package/node_modules/@herbertgao/pi-rename/package.json +0 -63
  460. package/node_modules/@herbertgao/pi-titlebar-spinner/CHANGELOG.md +0 -25
  461. package/node_modules/@herbertgao/pi-titlebar-spinner/LICENSE +0 -22
  462. /package/node_modules/{@herbertgao → @tifan}/pi-copy-response/src/index.ts +0 -0
  463. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/complete-text.ts +0 -0
  464. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/session-query.ts +0 -0
  465. /package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/src/index.ts +0 -0
  466. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +0 -0
  467. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/viewer.mjs +0 -0
  468. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/src/index.ts +0 -0
  469. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/index.ts +0 -0
  470. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/model-picker.ts +0 -0
  471. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/sanitize.ts +0 -0
  472. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/tui.ts +0 -0
  473. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/model-picker.ts +0 -0
  474. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/naming.ts +0 -0
  475. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/sanitize.ts +0 -0
  476. /package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/src/index.ts +0 -0
@@ -2,6 +2,7 @@ import { randomBytes } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { logCascade } from "./cascade-logger.js";
5
+ import { appendProjectChange, } from "./project-changes.js";
5
6
  import { normalizeMapKey, pathsEqual } from "./path-utils.js";
6
7
  import { PathKeyedMap } from "./path-keyed-map.js";
7
8
  import { BoundedLruCache } from "./bounded-cache.js";
@@ -9,6 +10,15 @@ import { ReadGuard } from "./read-guard.js";
9
10
  import { RUNTIME_CONFIG } from "./runtime-config.js";
10
11
  import { TurnSummaryCollector } from "./turn-summary.js";
11
12
  import { deriveProviderFromModelId } from "./model-provider.js";
13
+ /**
14
+ * Bounded receipt ring capacity (defect shape 9: bound the axis that grows —
15
+ * per-mutation receipts are unbounded across a long session). Oldest receipts
16
+ * evict first; eviction is counted and surfaced via
17
+ * {@link RuntimeCoordinator.droppedMutationReceiptCount} so a consumer that
18
+ * needs a complete window knows the answer was truncated, never silently
19
+ * incomplete (#936 honesty rule).
20
+ */
21
+ const MAX_MUTATION_RECEIPTS = 512;
12
22
  /**
13
23
  * Bound on in-flight tool_call → tool_result correlations. A tool_result
14
24
  * follows its tool_call almost immediately, so this only needs to cover
@@ -49,6 +59,8 @@ export class RuntimeCoordinator {
49
59
  _writtenThisTurn = new PathKeyedMap(normalizeMapKey);
50
60
  _autofixDemotedThisTurn = new PathKeyedMap(normalizeMapKey);
51
61
  _reportedThisTurn = new Set();
62
+ _mutationReceipts = [];
63
+ _droppedMutationReceipts = 0;
52
64
  _projectRulesScan = {
53
65
  rules: [],
54
66
  hasCustomRules: false,
@@ -119,6 +131,8 @@ export class RuntimeCoordinator {
119
131
  this._writtenThisTurn.clear();
120
132
  this._autofixDemotedThisTurn.clear();
121
133
  this._reportedThisTurn.clear();
134
+ this._mutationReceipts = [];
135
+ this._droppedMutationReceipts = 0;
122
136
  this._telemetrySessionId = `lens-${Date.now().toString(36)}-${randomBytes(4).toString("hex")}`;
123
137
  this._hasStableSessionId = false;
124
138
  this._telemetryModel = "unknown";
@@ -174,7 +188,9 @@ export class RuntimeCoordinator {
174
188
  const summaries = this.getInlineBlockersSnapshot()
175
189
  .map((entry) => entry.summary.trim())
176
190
  .filter(Boolean);
177
- this._gitGuardSummary = (summaries[0] ?? firstLine ?? "Unresolved blockers detected").slice(0, 160);
191
+ this._gitGuardSummary = (summaries[0] ??
192
+ firstLine ??
193
+ "Unresolved blockers detected").slice(0, 160);
178
194
  }
179
195
  get gitGuardHasBlockers() {
180
196
  return this._gitGuardHasBlockers;
@@ -239,6 +255,68 @@ export class RuntimeCoordinator {
239
255
  this._writtenThisTurn.clear();
240
256
  this._autofixDemotedThisTurn.clear();
241
257
  }
258
+ /**
259
+ * THE one mutation seam. Every producer of an in-project file mutation —
260
+ * native write/edit, recognized bash writes, format/autofix, LSP workspace
261
+ * edits, and (phase 2) opaque script-write recovery — records through here,
262
+ * once: it bumps the seq store (`bumpFileSeq`), appends a bounded attributed
263
+ * receipt, and optionally appends the durable change-log entry. Consumers
264
+ * derive from `getFilesChangedSince` / `getMutationsSince`; no producer or
265
+ * consumer may hand-roll a parallel bump+log pairing (#2000 phase 1).
266
+ *
267
+ * Receipt recording never throws; change-log append failures route to
268
+ * `onAppendError` (default: swallowed) so telemetry cannot break dispatch.
269
+ */
270
+ recordProjectMutation(args) {
271
+ const { projectSeq, fileSeq, key } = this.bumpFileSeq(args.filePath);
272
+ if (this._mutationReceipts.length >= MAX_MUTATION_RECEIPTS) {
273
+ this._mutationReceipts.shift();
274
+ this._droppedMutationReceipts += 1;
275
+ }
276
+ this._mutationReceipts.push({
277
+ seq: projectSeq,
278
+ // Reuse the bump's normalized key (~200us realpath on Windows) —
279
+ // never re-derive it here.
280
+ filePath: key,
281
+ source: args.source,
282
+ turnIndex: this._turnIndex,
283
+ ts: Date.now(),
284
+ });
285
+ if (args.cwd !== undefined) {
286
+ try {
287
+ appendProjectChange(args.cwd, {
288
+ seq: projectSeq,
289
+ timestamp: new Date().toISOString(),
290
+ sessionId: this.telemetrySessionId,
291
+ turnIndex: this.turnIndex,
292
+ source: args.source,
293
+ filePath: path.resolve(args.filePath),
294
+ fileSeq,
295
+ changedRange: args.changedRange,
296
+ });
297
+ }
298
+ catch (err) {
299
+ args.onAppendError?.(err);
300
+ }
301
+ }
302
+ return { projectSeq, fileSeq };
303
+ }
304
+ /**
305
+ * Attributed mutations whose seq is strictly after `seq` — the receipt-level
306
+ * counterpart of {@link getFilesChangedSince}. Bounded: entries evicted by
307
+ * the ring cap are gone; compare `droppedMutationReceiptCount` against zero
308
+ * before treating the result as a complete window.
309
+ */
310
+ getMutationsSince(seq) {
311
+ // Shallow copies: a consumer mutating a returned receipt must not
312
+ // corrupt the ring's internal state.
313
+ return this._mutationReceipts
314
+ .filter((r) => r.seq > seq)
315
+ .map((r) => ({ ...r }));
316
+ }
317
+ get droppedMutationReceiptCount() {
318
+ return this._droppedMutationReceipts;
319
+ }
242
320
  /** Atomically records write/edit ordering before debounce can coalesce it. */
243
321
  recordMutationToolReceipt(filePath, toolName) {
244
322
  if (toolName === "write") {
@@ -359,12 +437,14 @@ export class RuntimeCoordinator {
359
437
  }
360
438
  }
361
439
  bumpFileSeq(filePath) {
440
+ // normalizeMapKey costs ~200us/call on Windows (realpath); every caller
441
+ // that also needs the key must reuse this one instead of paying it twice.
362
442
  const key = normalizeMapKey(path.resolve(filePath));
363
443
  this._projectSeq += 1;
364
444
  const fileSeq = (this._fileSeq.get(key) ?? 0) + 1;
365
445
  this._fileSeq.set(key, fileSeq);
366
446
  this._fileLastProjectSeq.set(key, this._projectSeq);
367
- return { projectSeq: this._projectSeq, fileSeq };
447
+ return { projectSeq: this._projectSeq, fileSeq, key };
368
448
  }
369
449
  /**
370
450
  * Files whose most recent bump happened AFTER `seq` — i.e. every file the
@@ -1036,8 +1116,7 @@ export class RuntimeCoordinator {
1036
1116
  */
1037
1117
  export function readHostModelIdentity(ctx) {
1038
1118
  try {
1039
- const model = ctx
1040
- ?.model;
1119
+ const model = ctx?.model;
1041
1120
  return {
1042
1121
  model: typeof model?.id === "string" ? model.id : undefined,
1043
1122
  provider: typeof model?.provider === "string" ? model.provider : undefined,
@@ -43,8 +43,11 @@ import { TrivyClient } from "./trivy-client.js";
43
43
  import { isWarmAttached } from "./warm-attach.js";
44
44
  import { setSessionLanguages } from "./widget-state.js";
45
45
  import { logWordIndex } from "./word-index-logger.js";
46
+ import { resetOpaqueMutationState } from "./opaque-mutation-scan.js";
47
+ import { resetPendingAuxiliaryCoverage } from "./lsp/pending-aux-coverage.js";
46
48
  import { resetWorkspaceTopology } from "./workspace-topology.js";
47
49
  import { resetZizmorTokenAvailability } from "./zizmor-config.js";
50
+ import { resetSpawnTimeoutCooldowns } from "./spawn-timeout-cooldown.js";
48
51
  const HOST_STALL_THRESHOLD_MS = 30_000;
49
52
  function logHostReadyDelay(deps, cwd) {
50
53
  if (!deps.emitHostReadyDelay ||
@@ -1608,6 +1611,12 @@ export async function handleSessionStart(deps) {
1608
1611
  // previously session-lived with no reset hook at all).
1609
1612
  resetWorkspaceTopology();
1610
1613
  clearTsconfigPathsCache();
1614
+ // #2000: opaque-recovery baselines are keyed cwd:generation (unreachable
1615
+ // after reset) and the git-worktree memo must re-probe after a session
1616
+ // that may have seen a non-git dir become one.
1617
+ resetOpaqueMutationState();
1618
+ // #2026: pending auxiliary baselines are unreachable after generation bump.
1619
+ resetPendingAuxiliaryCoverage();
1611
1620
  // #817/#1199: Windows command resolution is cached per (command, canonical
1612
1621
  // effective child PATH/PATHEXT/cwd/per-drive provenance); drop it each
1613
1622
  // session so environment changes (e.g.
@@ -1621,6 +1630,11 @@ export async function handleSessionStart(deps) {
1621
1630
  // the tool for the rest of the process lifetime. Clear it here, same
1622
1631
  // boundary as the other per-session caches on this line.
1623
1632
  resetDispatchAvailabilityState();
1633
+ // #1995: a command that TIMED OUT (not merely failed a probe) cools down
1634
+ // for the rest of the session so a hot loop of edits cannot hand the same
1635
+ // wedged .cmd shim a second budget. A new session may retry: the executable
1636
+ // or its environment may have changed.
1637
+ resetSpawnTimeoutCooldowns();
1624
1638
  // #1895: formatter PATH verdicts are session-scoped, but they live in
1625
1639
  // formatters.ts and are not covered by the dispatch generation. Re-arm them
1626
1640
  // here so a formatter installed or removed between sessions is observed by
@@ -4,7 +4,10 @@ import { loadBootstrapClients } from "./bootstrap.js";
4
4
  import { recordDegradationOnce } from "./degradation-ledger.js";
5
5
  import { detectFileKind } from "./file-kinds.js";
6
6
  import { isPathIgnoredByProject } from "./file-utils.js";
7
- import { evaluateGitGuard, isGitCommitOrPushAttempt, } from "./git-guard.js";
7
+ import { evaluateGitGuard, isGitCommitOrPushAttempt } from "./git-guard.js";
8
+ import { logLatency } from "./latency-logger.js";
9
+ import { normalizeMapKey } from "./path-utils.js";
10
+ import { captureFileStats, getOpaqueBaselineStore, isGitWorktree, } from "./opaque-mutation-scan.js";
8
11
  import { normalizeForGuardMatch } from "./host-edit-normalize.js";
9
12
  import { retargetReplacementIndentation } from "./indent-retarget.js";
10
13
  import { LANGUAGE_POLICY } from "./language-policy.js";
@@ -17,7 +20,7 @@ import { EXPANSION_BUDGET_MS, EXPANSION_LIMIT_LINES, tryExpandRead, } from "./re
17
20
  import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
18
21
  import { countFileLines, getTouchedLinesForGuard, relocateEditRange, tryCorrectIndentationMismatch, tryCorrectIndentationMismatchFromContent, } from "./read-guard-tool-lines.js";
19
22
  import { handleToolResult } from "./runtime-tool-result.js";
20
- import { isToolCallEventType, resolveToolCallCorrelationId } from "./tool-event.js";
23
+ import { isToolCallEventType, resolveToolCallCorrelationId, } from "./tool-event.js";
21
24
  import { getSharedTreeSitterClient } from "./tree-sitter-shared.js";
22
25
  const LSP_TOOLCALL_NAV_TOUCH_BUDGET_MS = Math.max(0, Number.parseInt(process.env.PI_LENS_TOOLCALL_NAV_TOUCH_MS ??
23
26
  process.env.PI_LENS_LSP_NAV_CLIENT_WAIT_MS ??
@@ -317,6 +320,59 @@ async function handleToolCallImpl(deps) {
317
320
  });
318
321
  if (!lensEnabled)
319
322
  return;
323
+ // #2000 phase 2: opaque-command pre-snapshot. A bash command whose writes
324
+ // the extractor will not recognize gets a bounded stat snapshot of the
325
+ // project source universe BEFORE it runs; the tool_result side diffs it.
326
+ // Fire-and-forget capture is WRONG here (the child may finish first), but
327
+ // the capture is stat-only and budgeted, so awaiting it is bounded work on
328
+ // an already-second-scale bash path.
329
+ if (toolName === "bash") {
330
+ const commandInput = event.input;
331
+ if (typeof commandInput?.command === "string" && commandInput.command) {
332
+ const scanRoot = ctx.cwd ?? runtime.projectRoot;
333
+ if (scanRoot) {
334
+ const started = Date.now();
335
+ const rootKey = `${normalizeMapKey(path.resolve(scanRoot))}:${runtime.sessionGeneration}`;
336
+ let baseline;
337
+ let resultNote;
338
+ if (await isGitWorktree(scanRoot)) {
339
+ // Git-first: the timestamp IS the baseline; git answers what
340
+ // changed, at any repo size, with no file-universe cap.
341
+ baseline = { startedAt: started, strategy: "git" };
342
+ resultNote = "git";
343
+ }
344
+ else {
345
+ const outcome = await captureFileStats(scanRoot, {
346
+ withHashes: true,
347
+ });
348
+ baseline = outcome.snapshot
349
+ ? {
350
+ startedAt: started,
351
+ strategy: "stat-diff",
352
+ stats: outcome.snapshot,
353
+ }
354
+ : {
355
+ startedAt: started,
356
+ strategy: "stat-diff",
357
+ statsUnknownReason: outcome.unknownReason ?? "walk-failed",
358
+ };
359
+ resultNote =
360
+ outcome.unknownReason ?? `scanned:${outcome.scannedCount}`;
361
+ }
362
+ // Session-stamped key: a concurrent-secondary session (#473)
363
+ // replacing this slot must yield a no-pending-snapshot UNKNOWN
364
+ // for us - never a diff against another session's baseline.
365
+ getOpaqueBaselineStore().record(rootKey, baseline);
366
+ logLatency({
367
+ type: "phase",
368
+ phase: "opaque_mutation_prescan",
369
+ filePath: commandInput.command.slice(0, 80),
370
+ durationMs: Date.now() - started,
371
+ result: resultNote,
372
+ });
373
+ }
374
+ }
375
+ }
320
376
  if (getFlag("lens-guard") &&
321
377
  isGitCommitOrPushAttempt(toolName, event.input)) {
322
378
  const guard = evaluateGitGuard(runtime, cacheManager, ctx.cwd ?? runtime.projectRoot);
@@ -456,7 +512,7 @@ async function handleToolCallImpl(deps) {
456
512
  }
457
513
  }
458
514
  if (ctx.ui) {
459
- ctx.ui && updateLspStatus(ctx.ui.setStatus, ctx.ui.theme);
515
+ updateLspStatus(ctx.ui.setStatus, ctx.ui.theme);
460
516
  }
461
517
  })
462
518
  .catch((err) => {
@@ -2,13 +2,15 @@ import * as nodeCrypto from "node:crypto";
2
2
  import * as nodeFs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { noteAuthoritativeContentAttachment } from "./agent-nudge.js";
5
+ import { captureFileStats, diffFileStats, getOpaqueBaselineStore, recoverOpaqueChangesViaGit, } from "./opaque-mutation-scan.js";
6
+ import { normalizeMapKey } from "./path-utils.js";
5
7
  import { extractReadPathsFromCommand, extractDeletedPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, } from "./bash-file-access.js";
6
8
  import { registerSearchReads, } from "./search-read-registration.js";
7
9
  import { createFileTime } from "./file-time.js";
8
10
  import { publishFormatQueued } from "./format-events-publish.js";
9
11
  import { isPathIgnoredByProject } from "./file-utils.js";
10
12
  import { getFormatService } from "./format-service.js";
11
- import { isExternalOrVendorFile, normalizeEphemeralMapKey, pathsEqual } from "./path-utils.js";
13
+ import { isExternalOrVendorFile, normalizeEphemeralMapKey, pathsEqual, } from "./path-utils.js";
12
14
  import { PathKeyedMap } from "./path-keyed-map.js";
13
15
  import { resolveLanguageRootForFile } from "./language-profile.js";
14
16
  import { logLatency } from "./latency-logger.js";
@@ -17,7 +19,6 @@ import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCo
17
19
  import { notifyExternalFileChange } from "./lsp/index.js";
18
20
  import { runPipeline } from "./pipeline.js";
19
21
  import { renderPostAutofixNotice, } from "./post-autofix-notice.js";
20
- import { appendProjectChange, } from "./project-changes.js";
21
22
  import { syncGitGuardRecord } from "./git-guard.js";
22
23
  import { scheduleWordIndexPersist } from "./word-index.js";
23
24
  import { RUNTIME_CONFIG } from "./runtime-config.js";
@@ -111,7 +112,8 @@ function scheduleDebounced(filePath, debounceMs, deps) {
111
112
  const existing = debouncedPipelines.get(filePath);
112
113
  if (existing) {
113
114
  clearTimeout(existing.timer);
114
- const incomingId = deps._telemetryParticipantIds?.[0] ?? getReadGuardCorrelationId(deps.event);
115
+ const incomingId = deps._telemetryParticipantIds?.[0] ??
116
+ getReadGuardCorrelationId(deps.event);
115
117
  const priorIds = existing.latestDeps._telemetryParticipantIds ?? [];
116
118
  existing.latestDeps = {
117
119
  ...deps,
@@ -133,7 +135,9 @@ function scheduleDebounced(filePath, debounceMs, deps) {
133
135
  resolveFn = res;
134
136
  rejectFn = rej;
135
137
  });
136
- const initialParticipantIds = deps._telemetryParticipantIds ?? [getReadGuardCorrelationId(deps.event)];
138
+ const initialParticipantIds = deps._telemetryParticipantIds ?? [
139
+ getReadGuardCorrelationId(deps.event),
140
+ ];
137
141
  const entry = {
138
142
  timer: setTimeout(() => {
139
143
  debouncedPipelines.delete(filePath);
@@ -183,25 +187,16 @@ function singleRange(ranges) {
183
187
  return ranges?.length === 1 ? ranges[0] : undefined;
184
188
  }
185
189
  function recordProjectChange(args) {
186
- const bump = args.runtime.bumpFileSeq;
187
- if (!bump)
188
- return;
189
- const { projectSeq, fileSeq } = bump.call(args.runtime, args.filePath);
190
- try {
191
- appendProjectChange(args.cwd, {
192
- seq: projectSeq,
193
- timestamp: new Date().toISOString(),
194
- sessionId: args.runtime.telemetrySessionId,
195
- turnIndex: args.runtime.turnIndex,
196
- source: args.source,
197
- filePath: path.resolve(args.filePath),
198
- fileSeq,
199
- changedRange: args.changedRange,
200
- });
201
- }
202
- catch (err) {
203
- args.dbg(`project change log append failed for ${args.filePath}: ${err}`);
204
- }
190
+ // One mutation seam (#2000 phase 1): bump + receipt + change-log live in
191
+ // RuntimeCoordinator.recordProjectMutation; this wrapper only carries the
192
+ // legacy dbg shape.
193
+ args.runtime.recordProjectMutation?.({
194
+ filePath: args.filePath,
195
+ source: args.source,
196
+ cwd: args.cwd,
197
+ changedRange: args.changedRange,
198
+ onAppendError: (err) => args.dbg(`project change log append failed for ${args.filePath}: ${err}`),
199
+ });
205
200
  }
206
201
  export async function handleToolResult(deps) {
207
202
  const { event, getFlag, getFlagSource, dbg, runtime, cacheManager, biomeClient, ruffClient, metricsClient, resetLSPService, agentBehaviorRecord, formatBehaviorWarnings, } = deps;
@@ -233,7 +228,9 @@ export async function handleToolResult(deps) {
233
228
  if (attribution) {
234
229
  resolutionBasis = attribution.originCwd;
235
230
  }
236
- else if (toolCallId !== undefined && rawFilePath && !path.isAbsolute(rawFilePath)) {
231
+ else if (toolCallId !== undefined &&
232
+ rawFilePath &&
233
+ !path.isAbsolute(rawFilePath)) {
237
234
  // A real correlation id existed (the host DOES support one) but no
238
235
  // attribution was recorded under it — evicted, cleared because the
239
236
  // call was blocked before it could execute, or simply never seen by
@@ -316,22 +313,128 @@ export async function handleToolResult(deps) {
316
313
  if (event.toolName === "bash" &&
317
314
  typeof event.input.command === "string") {
318
315
  const command = event.input.command;
319
- const written = extractWrittenPathsFromCommand(command, workspaceRoot).filter((wp) => event.isError !== true &&
320
- !isExternalOrVendorFile(wp, workspaceRoot) &&
321
- !isPathIgnoredByProject(wp, workspaceRoot, false));
316
+ const recognized = extractWrittenPathsFromCommand(command, workspaceRoot);
317
+ // The SURVIVING recognized set: what will actually dispatch. Failure
318
+ // atomicity (#2000 invariant 5) means opaque recovery must subtract
319
+ // THIS set, not raw recognized - otherwise a redirect target dropped
320
+ // by the isError filter would be subtracted from recovery AND
321
+ // excluded here, attributed nowhere.
322
+ const recognizedWritten = event.isError !== true
323
+ ? recognized.filter((wp) => !isExternalOrVendorFile(wp, workspaceRoot) &&
324
+ !isPathIgnoredByProject(wp, workspaceRoot, false))
325
+ : [];
326
+ // #2000 phase 2: when the extractor recognizes NOTHING, the command is
327
+ // opaque-candidate — recover its actual changed set by diffing the pre
328
+ // snapshot taken at tool_call. Partial writes that landed before a
329
+ // nonzero exit ARE attributed (the files changed and the agent authored
330
+ // them) — a deliberate divergence from the isError filter above, which
331
+ // exists for restore semantics where attribution would lie.
332
+ let opaquePaths = [];
333
+ // Recovery runs for EVERY bash command with a pending baseline - not
334
+ // only recognized-empty ones. A mixed command (`python x.py > out.ts`
335
+ // plus script-internal writes) previously skipped observation entirely
336
+ // with zero telemetry; git-first recovery is cheap enough (~60ms) to
337
+ // close that gap, subtracting already-recognized paths so nothing
338
+ // double-dispatches.
339
+ if (workspaceRoot && !getFlag("no-read-guard")) {
340
+ const scanRoot = workspaceRoot;
341
+ const started = Date.now();
342
+ const pending = getOpaqueBaselineStore().take(`${normalizeMapKey(path.resolve(scanRoot))}:${runtime.sessionGeneration}`);
343
+ let unknownReason;
344
+ if (!pending && recognized.length > 0) {
345
+ // Partial coverage without observation: the explicit verdict
346
+ // invariant 1 demands (never silently imply no change).
347
+ unknownReason = "partial-recognition-no-baseline";
348
+ }
349
+ else if (!pending) {
350
+ unknownReason = "no-pending-snapshot";
351
+ }
352
+ else if (pending.strategy === "git") {
353
+ // Git-first: no universe cap - works on any repo size.
354
+ const recovery = await recoverOpaqueChangesViaGit(scanRoot, pending.startedAt);
355
+ if (recovery.verdict === "recovered") {
356
+ opaquePaths = recovery.paths.filter((p) => !isExternalOrVendorFile(p, scanRoot) &&
357
+ !isPathIgnoredByProject(p, scanRoot, false));
358
+ }
359
+ else if (recovery.verdict === "unknown" && recognized.length > 0) {
360
+ // Git hiccup on a partially-recognized command: the
361
+ // remainder's coverage is unknown, never clean-by-default.
362
+ unknownReason = recovery.unknownReason;
363
+ }
364
+ }
365
+ else if (pending.stats) {
366
+ const outcome = await captureFileStats(scanRoot, {
367
+ withHashes: true,
368
+ });
369
+ if (outcome.snapshot && !outcome.unknownReason) {
370
+ opaquePaths = diffFileStats(pending.stats, outcome.snapshot);
371
+ }
372
+ else {
373
+ unknownReason =
374
+ outcome.unknownReason ??
375
+ pending.statsUnknownReason ??
376
+ "walk-failed";
377
+ }
378
+ }
379
+ else {
380
+ unknownReason = pending.statsUnknownReason ?? "walk-failed";
381
+ }
382
+ if (opaquePaths.length > 0 && recognizedWritten.length > 0) {
383
+ const survivingKeys = new Set(recognizedWritten.map((p) => normalizeMapKey(path.resolve(p))));
384
+ opaquePaths = opaquePaths.filter((p) => !survivingKeys.has(p));
385
+ }
386
+ if (unknownReason) {
387
+ logLatency({
388
+ type: "phase",
389
+ phase: "opaque_mutation_coverage_unknown",
390
+ filePath: command.slice(0, 80),
391
+ durationMs: Date.now() - started,
392
+ result: unknownReason,
393
+ });
394
+ }
395
+ if (opaquePaths.length > 0) {
396
+ logLatency({
397
+ type: "phase",
398
+ phase: "opaque_mutation_recovered",
399
+ filePath: opaquePaths.slice(0, 5).join(","),
400
+ durationMs: Date.now() - started,
401
+ result: `changed:${opaquePaths.length}`,
402
+ });
403
+ }
404
+ }
405
+ // wp iterates opaquePaths VERBATIM (already normalizeMapKey keys), so the
406
+ // set must hold those exact strings - no re-resolution.
407
+ const opaqueSet = new Set(opaquePaths);
408
+ const written = [...recognizedWritten, ...opaquePaths];
322
409
  for (const wp of written) {
323
410
  if (!getFlag("no-read-guard"))
324
411
  deps.readGuard?.recordWritten(wp);
325
- const receipt = runtime.recordMutationToolReceipt;
412
+ const receipt = runtime
413
+ .recordMutationToolReceipt;
326
414
  const autofixMode = receipt
327
415
  ? receipt.call(runtime, wp, "write").autofixMode
328
416
  : "immediate";
417
+ // Recovered opaque writes carry their own source so the change log
418
+ // distinguishes them from parsed writes (auditable in production).
419
+ const isOpaque = opaqueSet.has(wp);
420
+ // Failure atomicity: an opaque-recovered file VERIFIABLY exists on
421
+ // disk, so its synthetic event must not inherit isError - the main
422
+ // path early-returns on failed host results before attribution,
423
+ // which would silently drop exactly the partial writes invariant 5
424
+ // says to attribute.
425
+ const syntheticEvent = {
426
+ ...event,
427
+ toolName: "write",
428
+ input: { path: wp },
429
+ isError: false,
430
+ };
329
431
  const syntheticResult = await handleToolResult({
330
432
  ...deps,
331
- event: { ...event, toolName: "write", input: { path: wp } },
433
+ event: syntheticEvent,
332
434
  _bypassDebounce: true,
333
435
  _autofixMode: autofixMode,
334
436
  _attachmentBudget: syntheticAttachmentBudget,
437
+ _mutationSourceOverride: isOpaque ? "opaque-script" : undefined,
335
438
  });
336
439
  if (syntheticResult) {
337
440
  // #1590: forward verbatim. The synthetic call already charged the
@@ -475,9 +578,11 @@ export async function handleToolResult(deps) {
475
578
  }
476
579
  // Must happen before debounce admission: latestDeps intentionally retains only
477
580
  // the latest event, but write -> edit is a sticky turn transition.
478
- const receipt = runtime.recordMutationToolReceipt;
581
+ const receipt = runtime
582
+ .recordMutationToolReceipt;
479
583
  const autofixMode = deps._bypassDebounce
480
- ? (deps._autofixMode ?? (event.toolName === "edit" ? "deferred" : "immediate"))
584
+ ? (deps._autofixMode ??
585
+ (event.toolName === "edit" ? "deferred" : "immediate"))
481
586
  : receipt
482
587
  ? receipt.call(runtime, filePath, event.toolName).autofixMode
483
588
  : event.toolName === "edit"
@@ -612,7 +717,8 @@ export async function handleToolResult(deps) {
612
717
  runtime,
613
718
  cwd: turnStateCwd,
614
719
  filePath,
615
- source: sourceForToolName(event.toolName, event.details),
720
+ source: deps._mutationSourceOverride ??
721
+ sourceForToolName(event.toolName, event.details),
616
722
  changedRange: singleRange(modifiedRanges),
617
723
  dbg,
618
724
  });
@@ -807,7 +913,9 @@ export async function handleToolResult(deps) {
807
913
  }
808
914
  }
809
915
  let autofixNewlyQueued = false;
810
- if (!result.isError && autofixMode === "deferred" && nodeFs.existsSync(filePath)) {
916
+ if (!result.isError &&
917
+ autofixMode === "deferred" &&
918
+ nodeFs.existsSync(filePath)) {
811
919
  autofixNewlyQueued =
812
920
  runtime.deferMutation?.call(runtime, filePath, dispatchCwd, event.toolName, turnStateCwd, "autofix", deps.sessionId, resolutionBasis) ?? false;
813
921
  dbg(`tool_result: queued deferred autofix for ${filePath}`);
@@ -841,7 +949,13 @@ export async function handleToolResult(deps) {
841
949
  }
842
950
  }
843
951
  if (autofixNewlyQueued && !formatQueued) {
844
- publishFormatQueued({ filePath, cwd: dispatchCwd, tool: event.toolName, kinds: ["autofix"], dbg });
952
+ publishFormatQueued({
953
+ filePath,
954
+ cwd: dispatchCwd,
955
+ tool: event.toolName,
956
+ kinds: ["autofix"],
957
+ dbg,
958
+ });
845
959
  }
846
960
  for (const changedFile of result.changedFiles ?? []) {
847
961
  const resolvedChanged = path.resolve(changedFile);