@herbertgao/pi-extensions 2026.10.1 → 2026.10.3

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 (934) hide show
  1. package/README.md +14 -17
  2. package/THIRD_PARTY_NOTICES.md +2 -2
  3. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +2 -2
  4. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +2 -2
  5. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +1 -1
  6. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +1 -1
  7. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +2 -2
  8. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +1 -1
  9. package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +21 -21
  10. package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +1 -1
  11. package/node_modules/@dietrichgebert/ponytail/AGENTS.md +21 -21
  12. package/node_modules/@dietrichgebert/ponytail/README.md +68 -72
  13. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +7 -0
  14. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +30 -30
  15. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-map.js +103 -0
  16. package/node_modules/@dietrichgebert/ponytail/package.json +2 -2
  17. package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +33 -101
  18. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +89 -32
  19. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +13 -12
  20. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +17 -16
  21. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +9 -10
  22. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +96 -57
  23. package/node_modules/{remote-pi → @herbertgao/pi-agency}/LICENSE +1 -1
  24. package/node_modules/@herbertgao/pi-agency/README.md +40 -0
  25. package/node_modules/@herbertgao/pi-agency/package.json +53 -0
  26. package/node_modules/@herbertgao/pi-agency/src/index.ts +441 -0
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +12 -12
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +30 -6
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +15 -9
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +27 -9
  31. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +4 -1
  32. package/node_modules/@herbertgao/pi-cc-extensions/package.json +2 -2
  33. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  34. package/node_modules/@herbertgao/pi-subagents/README.md +1 -1
  35. package/node_modules/@herbertgao/pi-subagents/package.json +4 -5
  36. package/node_modules/@herbertgao/pi-subagents/src/index.ts +1 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +1 -1
  38. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +48 -72
  39. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +1 -1
  40. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +15 -6
  41. package/node_modules/@herbertgao/pi-subagents/src/workflow/collisions.ts +4 -1
  42. package/node_modules/@herbertgao/pi-subagents/src/workflow/json-schema.ts +9 -8
  43. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +6 -1
  44. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +2 -2
  45. package/node_modules/@narumitw/pi-caffeinate/package.json +3 -3
  46. package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +13 -1
  47. package/node_modules/@tifan/pi-mermaid-open/package.json +5 -1
  48. package/node_modules/@tifan/pi-mermaid-open/src/index.ts +26 -9
  49. package/node_modules/@tifan/pi-recap/package.json +1 -1
  50. package/node_modules/@tifan/pi-recap/src/index.ts +104 -20
  51. package/node_modules/@tifan/pi-recap/src/models.ts +46 -4
  52. package/node_modules/pi-antigravity/README.md +23 -2
  53. package/node_modules/pi-antigravity/package.json +5 -3
  54. package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +3 -2
  55. package/node_modules/pi-antigravity/src/features/generate-image.ts +72 -0
  56. package/node_modules/pi-antigravity/src/features/google-search.ts +71 -0
  57. package/node_modules/pi-antigravity/src/image/image.ts +86 -47
  58. package/node_modules/pi-antigravity/src/image/native.ts +69 -0
  59. package/node_modules/pi-antigravity/src/index.ts +52 -137
  60. package/node_modules/pi-antigravity/src/search/search.ts +130 -31
  61. package/node_modules/pi-antigravity/src/stream/stream.ts +162 -113
  62. package/node_modules/pi-antigravity/src/types/enums.ts +1 -0
  63. package/node_modules/pi-antigravity/src/types/types.ts +1 -1
  64. package/node_modules/pi-antigravity/src/utils/security.ts +47 -1
  65. package/node_modules/pi-antigravity/src/utils/util.ts +38 -6
  66. package/node_modules/pi-lens/CHANGELOG.md +1159 -0
  67. package/node_modules/pi-lens/README.md +116 -25
  68. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +6 -2
  69. package/node_modules/pi-lens/dist/chunk-2BEMIWEW.js +51 -0
  70. package/node_modules/pi-lens/dist/chunk-2EECBNC5.js +89 -0
  71. package/node_modules/pi-lens/dist/chunk-2FQ62SPM.js +83 -0
  72. package/node_modules/pi-lens/dist/chunk-2UMYMRI3.js +118 -0
  73. package/node_modules/pi-lens/dist/chunk-34OCDWOS.js +48 -0
  74. package/node_modules/pi-lens/dist/chunk-3FERWMCH.js +144 -0
  75. package/node_modules/pi-lens/dist/chunk-3JL6IFD7.js +97 -0
  76. package/node_modules/pi-lens/dist/chunk-3JSEWUWI.js +327 -0
  77. package/node_modules/pi-lens/dist/chunk-3MED75HT.js +37 -0
  78. package/node_modules/pi-lens/dist/chunk-3MRXIJ6I.js +79 -0
  79. package/node_modules/pi-lens/dist/chunk-3P4PF2BX.js +2250 -0
  80. package/node_modules/pi-lens/dist/chunk-3PNFWVHT.js +201 -0
  81. package/node_modules/pi-lens/dist/chunk-3TTPKMEF.js +162 -0
  82. package/node_modules/pi-lens/dist/chunk-5JHXUETW.js +326 -0
  83. package/node_modules/pi-lens/dist/chunk-5W3R6LFT.js +24 -0
  84. package/node_modules/pi-lens/dist/chunk-64LU2OVH.js +341 -0
  85. package/node_modules/pi-lens/dist/chunk-6B5I6ICN.js +44 -0
  86. package/node_modules/pi-lens/dist/chunk-6P54TMWL.js +274 -0
  87. package/node_modules/pi-lens/dist/chunk-6UYA642J.js +145 -0
  88. package/node_modules/pi-lens/dist/chunk-6XX5HCLK.js +398 -0
  89. package/node_modules/pi-lens/dist/chunk-7AXO3ZDF.js +30 -0
  90. package/node_modules/pi-lens/dist/chunk-7BX5DWSA.js +1907 -0
  91. package/node_modules/pi-lens/dist/chunk-7ELY2CSM.js +902 -0
  92. package/node_modules/pi-lens/dist/chunk-7M4T5N3V.js +38 -0
  93. package/node_modules/pi-lens/dist/chunk-7U2IDNXN.js +37 -0
  94. package/node_modules/pi-lens/dist/chunk-ABBOA7UD.js +157 -0
  95. package/node_modules/pi-lens/dist/chunk-AFZYMAIV.js +756 -0
  96. package/node_modules/pi-lens/dist/chunk-ALQRYH6O.js +112 -0
  97. package/node_modules/pi-lens/dist/chunk-AXKPQ6ZI.js +1610 -0
  98. package/node_modules/pi-lens/dist/chunk-BHWHXMQ2.js +62 -0
  99. package/node_modules/pi-lens/dist/chunk-BJF25SUG.js +22 -0
  100. package/node_modules/pi-lens/dist/chunk-BNKLYOOO.js +18 -0
  101. package/node_modules/pi-lens/dist/chunk-BW5KFIQC.js +59 -0
  102. package/node_modules/pi-lens/dist/chunk-CBD2B5CP.js +599 -0
  103. package/node_modules/pi-lens/dist/chunk-CFYISHUW.js +42 -0
  104. package/node_modules/pi-lens/dist/chunk-CMU4RMJB.js +30 -0
  105. package/node_modules/pi-lens/dist/chunk-CULQYFLU.js +14 -0
  106. package/node_modules/pi-lens/dist/chunk-D65GOCJB.js +289 -0
  107. package/node_modules/pi-lens/dist/chunk-D6YF5HKX.js +59 -0
  108. package/node_modules/pi-lens/dist/chunk-DMS52BEP.js +342 -0
  109. package/node_modules/pi-lens/dist/chunk-ELVWJYRV.js +211 -0
  110. package/node_modules/pi-lens/dist/chunk-EUT3B22Y.js +27 -0
  111. package/node_modules/pi-lens/dist/chunk-F5VLZHUW.js +146 -0
  112. package/node_modules/pi-lens/dist/chunk-FC4RP4I2.js +12 -0
  113. package/node_modules/pi-lens/dist/chunk-FGALODG3.js +55 -0
  114. package/node_modules/pi-lens/dist/chunk-G3RLJYA2.js +2358 -0
  115. package/node_modules/pi-lens/dist/chunk-GAYGGICG.js +32 -0
  116. package/node_modules/pi-lens/dist/chunk-H2W2AXD3.js +419 -0
  117. package/node_modules/pi-lens/dist/chunk-H5EV3VMF.js +114 -0
  118. package/node_modules/pi-lens/dist/chunk-HREZQCT3.js +106 -0
  119. package/node_modules/pi-lens/dist/chunk-HSIRMK2D.js +517 -0
  120. package/node_modules/pi-lens/dist/chunk-IMSQR4WO.js +184 -0
  121. package/node_modules/pi-lens/dist/chunk-IQZXOZ7S.js +4816 -0
  122. package/node_modules/pi-lens/dist/chunk-IR6XFA5P.js +37 -0
  123. package/node_modules/pi-lens/dist/chunk-IUKPRZER.js +78 -0
  124. package/node_modules/pi-lens/dist/chunk-IUR76K6A.js +262 -0
  125. package/node_modules/pi-lens/dist/chunk-J3FZR3YY.js +98 -0
  126. package/node_modules/pi-lens/dist/chunk-J6DFZDFA.js +562 -0
  127. package/node_modules/pi-lens/dist/chunk-J7WJZ6W7.js +50 -0
  128. package/node_modules/pi-lens/dist/chunk-JONGANYH.js +202 -0
  129. package/node_modules/pi-lens/dist/chunk-KJCWXUUS.js +425 -0
  130. package/node_modules/pi-lens/dist/chunk-KJN4IOEJ.js +17 -0
  131. package/node_modules/pi-lens/dist/chunk-KMGPUKFD.js +25 -0
  132. package/node_modules/pi-lens/dist/chunk-LD7WFTRX.js +4533 -0
  133. package/node_modules/pi-lens/dist/chunk-LJDODBBZ.js +78 -0
  134. package/node_modules/pi-lens/dist/chunk-LNOMA3MP.js +169 -0
  135. package/node_modules/pi-lens/dist/chunk-MGIWSROG.js +2334 -0
  136. package/node_modules/pi-lens/dist/chunk-MQA2YBAH.js +308 -0
  137. package/node_modules/pi-lens/dist/chunk-MTDRLSI7.js +21720 -0
  138. package/node_modules/pi-lens/dist/chunk-N2IRDBZI.js +2355 -0
  139. package/node_modules/pi-lens/dist/chunk-N77WFUL7.js +50 -0
  140. package/node_modules/pi-lens/dist/chunk-N7YNJE5R.js +466 -0
  141. package/node_modules/pi-lens/dist/chunk-NABLC7W3.js +148 -0
  142. package/node_modules/pi-lens/dist/chunk-NFXP47RV.js +999 -0
  143. package/node_modules/pi-lens/dist/chunk-NJF2X5XF.js +45 -0
  144. package/node_modules/pi-lens/dist/chunk-NXL4FFQQ.js +47 -0
  145. package/node_modules/pi-lens/dist/chunk-O7HZX7CA.js +309 -0
  146. package/node_modules/pi-lens/dist/chunk-OC7LYAU5.js +708 -0
  147. package/node_modules/pi-lens/dist/chunk-OEX24ECI.js +348 -0
  148. package/node_modules/pi-lens/dist/chunk-OYOB3ZFG.js +78 -0
  149. package/node_modules/pi-lens/dist/chunk-OYTMZXRF.js +41 -0
  150. package/node_modules/pi-lens/dist/chunk-OZJINN4O.js +84 -0
  151. package/node_modules/pi-lens/dist/chunk-PCHDGUKT.js +23 -0
  152. package/node_modules/pi-lens/dist/chunk-QOZXJ4NA.js +3364 -0
  153. package/node_modules/pi-lens/dist/chunk-QYF5S6P6.js +45 -0
  154. package/node_modules/pi-lens/dist/chunk-RJFED73B.js +79 -0
  155. package/node_modules/pi-lens/dist/chunk-RTQNRM5X.js +27 -0
  156. package/node_modules/pi-lens/dist/chunk-S6AMWKPC.js +189 -0
  157. package/node_modules/pi-lens/dist/chunk-T4QZ6FEH.js +308 -0
  158. package/node_modules/pi-lens/dist/chunk-T54VJRAD.js +5456 -0
  159. package/node_modules/pi-lens/dist/chunk-TA5L5KWQ.js +167 -0
  160. package/node_modules/pi-lens/dist/chunk-TQFBZVCG.js +27 -0
  161. package/node_modules/pi-lens/dist/chunk-U52SAGRM.js +62 -0
  162. package/node_modules/pi-lens/dist/chunk-UEAHAMEI.js +5814 -0
  163. package/node_modules/pi-lens/dist/chunk-UGSMCQ4D.js +327 -0
  164. package/node_modules/pi-lens/dist/chunk-UOPVJQ4N.js +103 -0
  165. package/node_modules/pi-lens/dist/chunk-USHG4DLH.js +459 -0
  166. package/node_modules/pi-lens/dist/chunk-UXVNL3D7.js +23 -0
  167. package/node_modules/pi-lens/dist/chunk-V5MEBST3.js +4139 -0
  168. package/node_modules/pi-lens/dist/chunk-VGEVL5EQ.js +29 -0
  169. package/node_modules/pi-lens/dist/chunk-VPWKF3GN.js +87 -0
  170. package/node_modules/pi-lens/dist/chunk-VSMJK3ZJ.js +1250 -0
  171. package/node_modules/pi-lens/dist/chunk-VYKKMYVT.js +560 -0
  172. package/node_modules/pi-lens/dist/chunk-VZHJS6DR.js +442 -0
  173. package/node_modules/pi-lens/dist/chunk-WATC3IQR.js +213 -0
  174. package/node_modules/pi-lens/dist/chunk-WPE5FPGR.js +54 -0
  175. package/node_modules/pi-lens/dist/chunk-WSEWKCXU.js +188 -0
  176. package/node_modules/pi-lens/dist/chunk-WW5BLB74.js +659 -0
  177. package/node_modules/pi-lens/dist/chunk-XGUL4SLQ.js +406 -0
  178. package/node_modules/pi-lens/dist/chunk-XHSCVSOL.js +170 -0
  179. package/node_modules/pi-lens/dist/chunk-XIMYZ3JA.js +27 -0
  180. package/node_modules/pi-lens/dist/chunk-YLN4K6WD.js +385 -0
  181. package/node_modules/pi-lens/dist/chunk-Z3CCVDUB.js +76 -0
  182. package/node_modules/pi-lens/dist/chunk-Z54ZSOBZ.js +61 -0
  183. package/node_modules/pi-lens/dist/chunk-Z6BB4JLQ.js +478 -0
  184. package/node_modules/pi-lens/dist/chunk-Z7QQA2KT.js +27 -0
  185. package/node_modules/pi-lens/dist/chunk-ZETYB3XG.js +2626 -0
  186. package/node_modules/pi-lens/dist/chunk-ZMOMPX2Z.js +87 -0
  187. package/node_modules/pi-lens/dist/chunk-ZOEYVXSV.js +149 -0
  188. package/node_modules/pi-lens/dist/chunk-ZZUFZUQZ.js +12120 -0
  189. package/node_modules/pi-lens/dist/index.js +39712 -29876
  190. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +186 -232
  191. package/node_modules/pi-lens/dist/mcp/cli.js +137 -98
  192. package/node_modules/pi-lens/dist/mcp/server.js +22688 -1573
  193. package/node_modules/pi-lens/dist/mcp/worker.js +97 -38
  194. package/node_modules/pi-lens/dist/probes/installer.js +135 -0
  195. package/node_modules/pi-lens/dist/workers/project-snapshot-persist-worker.js +22 -0
  196. package/node_modules/pi-lens/dist/workers/review-graph-persist-worker.js +15 -0
  197. package/node_modules/pi-lens/docs/agent-guide.md +13 -4
  198. package/node_modules/pi-lens/docs/agent-tools.md +42 -0
  199. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -4
  200. package/node_modules/pi-lens/docs/configuration.md +28 -2
  201. package/node_modules/pi-lens/docs/custom-rules.md +25 -2
  202. package/node_modules/pi-lens/docs/environment-variables.md +86 -8
  203. package/node_modules/pi-lens/docs/features.md +45 -5
  204. package/node_modules/pi-lens/docs/globalconfig.md +2 -1
  205. package/node_modules/pi-lens/docs/io-bridge-v2-migration.md +94 -0
  206. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +37 -4
  207. package/node_modules/pi-lens/docs/lsp-idle-eviction.md +124 -0
  208. package/node_modules/pi-lens/docs/mcp.md +21 -5
  209. package/node_modules/pi-lens/docs/merge-queue-rollout.md +77 -0
  210. package/node_modules/pi-lens/docs/pi-lens-fixer.md +160 -88
  211. package/node_modules/pi-lens/docs/pi-lens-investigator.md +74 -26
  212. package/node_modules/pi-lens/docs/pi-lens-merge-policy.md +736 -0
  213. package/node_modules/pi-lens/docs/pi-lens-monitor.md +75 -7
  214. package/node_modules/pi-lens/docs/pi-lens-retro.md +6 -4
  215. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +189 -48
  216. package/node_modules/pi-lens/docs/pi-lens-subagent.md +246 -45
  217. package/node_modules/pi-lens/docs/pi-lens-warden.md +18 -7
  218. package/node_modules/pi-lens/docs/public-api-stability.md +55 -0
  219. package/node_modules/pi-lens/docs/release-qa-baseline.md +84 -17
  220. package/node_modules/pi-lens/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  221. package/node_modules/pi-lens/docs/schema/pi-lens-config-v1.json +530 -0
  222. package/node_modules/pi-lens/docs/servercapabilities.md +56 -49
  223. package/node_modules/pi-lens/docs/settings.md +1 -0
  224. package/node_modules/pi-lens/docs/usage.md +5 -1
  225. package/node_modules/pi-lens/docs/word-index.md +6 -0
  226. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm +0 -0
  227. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm.json +3 -3
  228. package/node_modules/pi-lens/package.json +18 -6
  229. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  230. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-identity-operator-on-literals-test.yml +12 -2
  231. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/throw-new-error-js-test.yml +2 -0
  232. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/throw-new-error-test.yml +2 -0
  233. package/node_modules/pi-lens/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  234. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-identity-operator-on-literals.yml +20 -12
  235. package/node_modules/pi-lens/rules/ast-grep-rules/rules/throw-new-error-js.yml +2 -2
  236. package/node_modules/pi-lens/rules/ast-grep-rules/rules/throw-new-error.yml +2 -2
  237. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +1275 -62
  238. package/node_modules/pi-lens/scripts/download-grammars.js +5 -0
  239. package/node_modules/pi-lens/scripts/grammars.lock.json +6 -1
  240. package/node_modules/pi-lens/scripts/install-selftest.mjs +33 -34
  241. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +13 -4
  242. package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +18 -0
  243. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  244. package/node_modules/pi-web-access/README.md +10 -6
  245. package/node_modules/pi-web-access/ceramic.ts +219 -0
  246. package/node_modules/pi-web-access/curator-page.ts +3 -1
  247. package/node_modules/pi-web-access/curator-server.ts +1 -0
  248. package/node_modules/pi-web-access/dist/index.js +846 -588
  249. package/node_modules/pi-web-access/dist/mcp-cli.js +725 -516
  250. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  251. package/node_modules/pi-web-access/github-extract.ts +34 -2
  252. package/node_modules/pi-web-access/index.ts +72 -30
  253. package/node_modules/pi-web-access/openai-search.ts +3 -3
  254. package/node_modules/pi-web-access/package.json +2 -2
  255. package/node_modules/pi-web-access/page-query.ts +6 -9
  256. package/node_modules/pi-web-access/parallel-mcp.ts +2 -0
  257. package/node_modules/pi-web-access/query-rewrite.ts +2 -2
  258. package/node_modules/pi-web-access/storage.ts +49 -0
  259. package/node_modules/pi-web-access/summary-review.ts +7 -6
  260. package/node_modules/pi-web-access/utils.ts +21 -6
  261. package/node_modules/pi-web-access/web-tool-core.ts +1 -0
  262. package/package.json +19 -19
  263. package/node_modules/@dietrichgebert/ponytail/README.es.md +0 -212
  264. package/node_modules/@dietrichgebert/ponytail/README.ja.md +0 -212
  265. package/node_modules/@dietrichgebert/ponytail/README.ko.md +0 -212
  266. package/node_modules/@dietrichgebert/ponytail/README.zh-CN.md +0 -212
  267. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -35
  268. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +0 -1610
  269. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +0 -593
  270. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +0 -147
  271. package/node_modules/pi-lens/dist/clients/agent-nudge.js +0 -325
  272. package/node_modules/pi-lens/dist/clients/analysed-root.js +0 -1
  273. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +0 -731
  274. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +0 -146
  275. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +0 -118
  276. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -10
  277. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +0 -154
  278. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +0 -75
  279. package/node_modules/pi-lens/dist/clients/atomic-write.js +0 -189
  280. package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +0 -12
  281. package/node_modules/pi-lens/dist/clients/bash-file-access.js +0 -1056
  282. package/node_modules/pi-lens/dist/clients/biome-client.js +0 -357
  283. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -837
  284. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +0 -129
  285. package/node_modules/pi-lens/dist/clients/bootstrap.js +0 -569
  286. package/node_modules/pi-lens/dist/clients/bounded-cache.js +0 -190
  287. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +0 -202
  288. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +0 -295
  289. package/node_modules/pi-lens/dist/clients/build-identity.js +0 -95
  290. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +0 -113
  291. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +0 -105
  292. package/node_modules/pi-lens/dist/clients/bus-publish.js +0 -171
  293. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +0 -190
  294. package/node_modules/pi-lens/dist/clients/cache-manager.js +0 -524
  295. package/node_modules/pi-lens/dist/clients/cache-observability.js +0 -1313
  296. package/node_modules/pi-lens/dist/clients/call-graph.js +0 -852
  297. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +0 -422
  298. package/node_modules/pi-lens/dist/clients/cascade-budget.js +0 -196
  299. package/node_modules/pi-lens/dist/clients/cascade-format.js +0 -315
  300. package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -31
  301. package/node_modules/pi-lens/dist/clients/cascade-types.js +0 -9
  302. package/node_modules/pi-lens/dist/clients/child-unref.js +0 -124
  303. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +0 -286
  304. package/node_modules/pi-lens/dist/clients/codebase-model.js +0 -173
  305. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +0 -40
  306. package/node_modules/pi-lens/dist/clients/complexity-client.js +0 -462
  307. package/node_modules/pi-lens/dist/clients/config-core/deny.js +0 -221
  308. package/node_modules/pi-lens/dist/clients/config-core/index.js +0 -50
  309. package/node_modules/pi-lens/dist/clients/config-core/merge.js +0 -357
  310. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +0 -340
  311. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +0 -248
  312. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +0 -164
  313. package/node_modules/pi-lens/dist/clients/config-core/records.js +0 -218
  314. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +0 -125
  315. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +0 -78
  316. package/node_modules/pi-lens/dist/clients/config-core/schema.js +0 -165
  317. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +0 -285
  318. package/node_modules/pi-lens/dist/clients/config-locations.js +0 -388
  319. package/node_modules/pi-lens/dist/clients/config-resolve.js +0 -798
  320. package/node_modules/pi-lens/dist/clients/config-schema.js +0 -251
  321. package/node_modules/pi-lens/dist/clients/config-warn.js +0 -407
  322. package/node_modules/pi-lens/dist/clients/console-guard-install.js +0 -26
  323. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +0 -42
  324. package/node_modules/pi-lens/dist/clients/dead-code-client.js +0 -510
  325. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -30
  326. package/node_modules/pi-lens/dist/clients/deadline-utils.js +0 -280
  327. package/node_modules/pi-lens/dist/clients/debug-handles.js +0 -211
  328. package/node_modules/pi-lens/dist/clients/debug-heap.js +0 -174
  329. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +0 -106
  330. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +0 -426
  331. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +0 -169
  332. package/node_modules/pi-lens/dist/clients/dependency-checker.js +0 -885
  333. package/node_modules/pi-lens/dist/clients/deps/ast-grep-napi.js +0 -22
  334. package/node_modules/pi-lens/dist/clients/deps/js-yaml.js +0 -9
  335. package/node_modules/pi-lens/dist/clients/deps/minimatch.js +0 -4
  336. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +0 -14
  337. package/node_modules/pi-lens/dist/clients/deps/typebox.js +0 -14
  338. package/node_modules/pi-lens/dist/clients/deps/vscode-jsonrpc.js +0 -1
  339. package/node_modules/pi-lens/dist/clients/deps/web-tree-sitter.js +0 -24
  340. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +0 -630
  341. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +0 -305
  342. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +0 -73
  343. package/node_modules/pi-lens/dist/clients/diagnostic-tracker.js +0 -105
  344. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +0 -230
  345. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  346. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  347. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -35
  348. package/node_modules/pi-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  349. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +0 -1269
  350. package/node_modules/pi-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
  351. package/node_modules/pi-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
  352. package/node_modules/pi-lens/dist/clients/dispatch/fact-runner.js +0 -30
  353. package/node_modules/pi-lens/dist/clients/dispatch/fact-scheduler.js +0 -68
  354. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +0 -377
  355. package/node_modules/pi-lens/dist/clients/dispatch/facts/comment-facts.js +0 -22
  356. package/node_modules/pi-lens/dist/clients/dispatch/facts/file-content.js +0 -19
  357. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +0 -348
  358. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +0 -204
  359. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  360. package/node_modules/pi-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  361. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +0 -339
  362. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +0 -417
  363. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +0 -89
  364. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +0 -2377
  365. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -11
  366. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +0 -87
  367. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -278
  368. package/node_modules/pi-lens/dist/clients/dispatch/priorities.js +0 -20
  369. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +0 -50
  370. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +0 -69
  371. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +0 -135
  372. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-noise.js +0 -40
  373. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  374. package/node_modules/pi-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  375. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  376. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  377. package/node_modules/pi-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  378. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +0 -72
  379. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  380. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  381. package/node_modules/pi-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  382. package/node_modules/pi-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  383. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  384. package/node_modules/pi-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  385. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  386. package/node_modules/pi-lens/dist/clients/dispatch/runner-context.js +0 -52
  387. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -111
  388. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  389. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -296
  390. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -219
  391. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -82
  392. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -416
  393. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -183
  394. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -176
  395. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -164
  396. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -195
  397. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -137
  398. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -29
  399. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -69
  400. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -167
  401. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +0 -104
  402. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -135
  403. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -91
  404. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -171
  405. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -940
  406. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -117
  407. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +0 -108
  408. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -99
  409. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -110
  410. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -379
  411. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -167
  412. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -102
  413. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +0 -414
  414. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -85
  415. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -120
  416. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  417. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  418. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +0 -169
  419. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -99
  420. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -88
  421. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -256
  422. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -173
  423. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -102
  424. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -128
  425. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -259
  426. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -183
  427. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -166
  428. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -163
  429. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -174
  430. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -168
  431. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -125
  432. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -643
  433. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -253
  434. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  435. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  436. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
  437. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  438. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  439. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  440. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  441. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  442. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -15
  443. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -128
  444. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  445. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -95
  446. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -79
  447. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +0 -79
  448. package/node_modules/pi-lens/dist/clients/dispatch/tool-profile.js +0 -30
  449. package/node_modules/pi-lens/dist/clients/dispatch/types.js +0 -21
  450. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
  451. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  452. package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -32
  453. package/node_modules/pi-lens/dist/clients/disposition-publish.js +0 -124
  454. package/node_modules/pi-lens/dist/clients/durable-store.js +0 -97
  455. package/node_modules/pi-lens/dist/clients/effective-config.js +0 -415
  456. package/node_modules/pi-lens/dist/clients/env-utils.js +0 -83
  457. package/node_modules/pi-lens/dist/clients/error-class.js +0 -23
  458. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +0 -17
  459. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +0 -274
  460. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +0 -250
  461. package/node_modules/pi-lens/dist/clients/extension-log.js +0 -504
  462. package/node_modules/pi-lens/dist/clients/extension-mode.js +0 -73
  463. package/node_modules/pi-lens/dist/clients/feature-hints.js +0 -103
  464. package/node_modules/pi-lens/dist/clients/file-kinds.js +0 -412
  465. package/node_modules/pi-lens/dist/clients/file-role.js +0 -134
  466. package/node_modules/pi-lens/dist/clients/file-time.js +0 -160
  467. package/node_modules/pi-lens/dist/clients/file-utils.js +0 -1032
  468. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +0 -494
  469. package/node_modules/pi-lens/dist/clients/finding-identity.js +0 -88
  470. package/node_modules/pi-lens/dist/clients/fix-worklog.js +0 -103
  471. package/node_modules/pi-lens/dist/clients/format-events-publish.js +0 -343
  472. package/node_modules/pi-lens/dist/clients/format-service.js +0 -222
  473. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +0 -9
  474. package/node_modules/pi-lens/dist/clients/formatters.js +0 -2032
  475. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +0 -17
  476. package/node_modules/pi-lens/dist/clients/freshness.js +0 -38
  477. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +0 -394
  478. package/node_modules/pi-lens/dist/clients/generation-guard.js +0 -215
  479. package/node_modules/pi-lens/dist/clients/git-guard.js +0 -1136
  480. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +0 -243
  481. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +0 -509
  482. package/node_modules/pi-lens/dist/clients/go-client.js +0 -104
  483. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +0 -605
  484. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +0 -348
  485. package/node_modules/pi-lens/dist/clients/grammar-source.js +0 -465
  486. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +0 -135
  487. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +0 -424
  488. package/node_modules/pi-lens/dist/clients/hook-budgets.js +0 -76
  489. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +0 -140
  490. package/node_modules/pi-lens/dist/clients/host-ports.js +0 -39
  491. package/node_modules/pi-lens/dist/clients/indent-retarget.js +0 -154
  492. package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +0 -186
  493. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +0 -156
  494. package/node_modules/pi-lens/dist/clients/installer/index.js +0 -5416
  495. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  496. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +0 -783
  497. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +0 -7
  498. package/node_modules/pi-lens/dist/clients/instance-reaper.js +0 -1137
  499. package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +0 -145
  500. package/node_modules/pi-lens/dist/clients/instance-registry.js +0 -773
  501. package/node_modules/pi-lens/dist/clients/jscpd-client.js +0 -378
  502. package/node_modules/pi-lens/dist/clients/json-cache-read.js +0 -65
  503. package/node_modules/pi-lens/dist/clients/knip-client.js +0 -788
  504. package/node_modules/pi-lens/dist/clients/language-policy.js +0 -252
  505. package/node_modules/pi-lens/dist/clients/language-profile.js +0 -361
  506. package/node_modules/pi-lens/dist/clients/language-registry.js +0 -603
  507. package/node_modules/pi-lens/dist/clients/latency-logger.js +0 -727
  508. package/node_modules/pi-lens/dist/clients/lazy-import.js +0 -21
  509. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +0 -54
  510. package/node_modules/pi-lens/dist/clients/lens-config.js +0 -404
  511. package/node_modules/pi-lens/dist/clients/lens-engine.js +0 -358
  512. package/node_modules/pi-lens/dist/clients/lens-events.js +0 -125
  513. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +0 -467
  514. package/node_modules/pi-lens/dist/clients/lens-map.js +0 -1156
  515. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +0 -74
  516. package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -222
  517. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +0 -178
  518. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +0 -421
  519. package/node_modules/pi-lens/dist/clients/lsp/client.js +0 -4593
  520. package/node_modules/pi-lens/dist/clients/lsp/config.js +0 -691
  521. package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +0 -41
  522. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +0 -225
  523. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +0 -467
  524. package/node_modules/pi-lens/dist/clients/lsp/edits.js +0 -1219
  525. package/node_modules/pi-lens/dist/clients/lsp/index.js +0 -8305
  526. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +0 -216
  527. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +0 -298
  528. package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -63
  529. package/node_modules/pi-lens/dist/clients/lsp/launch.js +0 -746
  530. package/node_modules/pi-lens/dist/clients/lsp/lombok.js +0 -158
  531. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +0 -5
  532. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -251
  533. package/node_modules/pi-lens/dist/clients/lsp/position-encoding.js +0 -61
  534. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  535. package/node_modules/pi-lens/dist/clients/lsp/server.js +0 -3290
  536. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +0 -192
  537. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +0 -17
  538. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -56
  539. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +0 -332
  540. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  541. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +0 -85
  542. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/index.js +0 -10
  543. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +0 -392
  544. package/node_modules/pi-lens/dist/clients/lsp/watch-queue.js +0 -61
  545. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  546. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  547. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  548. package/node_modules/pi-lens/dist/clients/lsp-budget.js +0 -186
  549. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +0 -110
  550. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +0 -9
  551. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +0 -396
  552. package/node_modules/pi-lens/dist/clients/lsp-status.js +0 -59
  553. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +0 -40
  554. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +0 -420
  555. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +0 -31
  556. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +0 -523
  557. package/node_modules/pi-lens/dist/clients/mcp/review.js +0 -197
  558. package/node_modules/pi-lens/dist/clients/mcp/session.js +0 -412
  559. package/node_modules/pi-lens/dist/clients/memory-sampler.js +0 -208
  560. package/node_modules/pi-lens/dist/clients/message-end-attribution.js +0 -30
  561. package/node_modules/pi-lens/dist/clients/metrics-client.js +0 -107
  562. package/node_modules/pi-lens/dist/clients/metrics-history.js +0 -327
  563. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +0 -263
  564. package/node_modules/pi-lens/dist/clients/model-provider.js +0 -53
  565. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +0 -189
  566. package/node_modules/pi-lens/dist/clients/module-report.js +0 -2150
  567. package/node_modules/pi-lens/dist/clients/mutating-tool.js +0 -651
  568. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +0 -368
  569. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +0 -240
  570. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -734
  571. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +0 -101
  572. package/node_modules/pi-lens/dist/clients/observed-mutation.js +0 -1253
  573. package/node_modules/pi-lens/dist/clients/oldtext-autopatch.js +0 -128
  574. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +0 -496
  575. package/node_modules/pi-lens/dist/clients/opengrep-client.js +0 -333
  576. package/node_modules/pi-lens/dist/clients/opengrep-config.js +0 -76
  577. package/node_modules/pi-lens/dist/clients/package-manager.js +0 -607
  578. package/node_modules/pi-lens/dist/clients/package-root.js +0 -38
  579. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +0 -439
  580. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +0 -43
  581. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +0 -108
  582. package/node_modules/pi-lens/dist/clients/path-utils.js +0 -1244
  583. package/node_modules/pi-lens/dist/clients/performance-report.js +0 -331
  584. package/node_modules/pi-lens/dist/clients/persist-debounce.js +0 -70
  585. package/node_modules/pi-lens/dist/clients/persistent-reverify.js +0 -271
  586. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +0 -119
  587. package/node_modules/pi-lens/dist/clients/pipeline.js +0 -1480
  588. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +0 -37
  589. package/node_modules/pi-lens/dist/clients/print-mode.js +0 -21
  590. package/node_modules/pi-lens/dist/clients/probe-home-state.js +0 -228
  591. package/node_modules/pi-lens/dist/clients/process-bridge.js +0 -66
  592. package/node_modules/pi-lens/dist/clients/process-singletons.js +0 -210
  593. package/node_modules/pi-lens/dist/clients/process-snapshot.js +0 -68
  594. package/node_modules/pi-lens/dist/clients/project-changes.js +0 -181
  595. package/node_modules/pi-lens/dist/clients/project-conventions.js +0 -171
  596. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +0 -137
  597. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +0 -109
  598. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
  599. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  600. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  601. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  602. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  603. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  604. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  605. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  606. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  607. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  608. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  609. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +0 -520
  610. package/node_modules/pi-lens/dist/clients/project-diagnostics/types.js +0 -1
  611. package/node_modules/pi-lens/dist/clients/project-lens-config.js +0 -807
  612. package/node_modules/pi-lens/dist/clients/project-report.js +0 -701
  613. package/node_modules/pi-lens/dist/clients/project-scale.js +0 -237
  614. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +0 -11
  615. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +0 -48
  616. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +0 -20
  617. package/node_modules/pi-lens/dist/clients/project-snapshot.js +0 -1653
  618. package/node_modules/pi-lens/dist/clients/project-trust.js +0 -181
  619. package/node_modules/pi-lens/dist/clients/python-environment.js +0 -217
  620. package/node_modules/pi-lens/dist/clients/python-provenance.js +0 -639
  621. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +0 -47
  622. package/node_modules/pi-lens/dist/clients/quiet-window.js +0 -236
  623. package/node_modules/pi-lens/dist/clients/read-bridge.js +0 -139
  624. package/node_modules/pi-lens/dist/clients/read-expansion.js +0 -266
  625. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +0 -251
  626. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +0 -1306
  627. package/node_modules/pi-lens/dist/clients/read-guard.js +0 -1561
  628. package/node_modules/pi-lens/dist/clients/recent-touches.js +0 -240
  629. package/node_modules/pi-lens/dist/clients/redact/secrets.js +0 -449
  630. package/node_modules/pi-lens/dist/clients/resource-sampler.js +0 -628
  631. package/node_modules/pi-lens/dist/clients/reverse-deps.js +0 -270
  632. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +0 -5126
  633. package/node_modules/pi-lens/dist/clients/review-graph/format.js +0 -33
  634. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +0 -163
  635. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +0 -481
  636. package/node_modules/pi-lens/dist/clients/review-graph/persist-worker.js +0 -10
  637. package/node_modules/pi-lens/dist/clients/review-graph/query.js +0 -244
  638. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +0 -21
  639. package/node_modules/pi-lens/dist/clients/review-graph/service.js +0 -96
  640. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  641. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +0 -103
  642. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +0 -299
  643. package/node_modules/pi-lens/dist/clients/review-graph/types.js +0 -1
  644. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +0 -449
  645. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +0 -81
  646. package/node_modules/pi-lens/dist/clients/ruff-client.js +0 -179
  647. package/node_modules/pi-lens/dist/clients/rules-scanner.js +0 -131
  648. package/node_modules/pi-lens/dist/clients/run-duration.js +0 -55
  649. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +0 -746
  650. package/node_modules/pi-lens/dist/clients/runtime-config.js +0 -77
  651. package/node_modules/pi-lens/dist/clients/runtime-context.js +0 -211
  652. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +0 -1324
  653. package/node_modules/pi-lens/dist/clients/runtime-session.js +0 -2485
  654. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +0 -1295
  655. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +0 -2049
  656. package/node_modules/pi-lens/dist/clients/runtime-turn.js +0 -3767
  657. package/node_modules/pi-lens/dist/clients/rust-client.js +0 -97
  658. package/node_modules/pi-lens/dist/clients/safe-spawn.js +0 -2357
  659. package/node_modules/pi-lens/dist/clients/sanitize.js +0 -286
  660. package/node_modules/pi-lens/dist/clients/scan-utils.js +0 -25
  661. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +0 -165
  662. package/node_modules/pi-lens/dist/clients/search-read-registration.js +0 -94
  663. package/node_modules/pi-lens/dist/clients/secret-findings.js +0 -114
  664. package/node_modules/pi-lens/dist/clients/security-scan-client.js +0 -352
  665. package/node_modules/pi-lens/dist/clients/session-event-guard.js +0 -297
  666. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +0 -484
  667. package/node_modules/pi-lens/dist/clients/session-start-observability.js +0 -94
  668. package/node_modules/pi-lens/dist/clients/session-state-store.js +0 -101
  669. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -15
  670. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +0 -27
  671. package/node_modules/pi-lens/dist/clients/sg-runner.js +0 -876
  672. package/node_modules/pi-lens/dist/clients/sgconfig.js +0 -347
  673. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +0 -338
  674. package/node_modules/pi-lens/dist/clients/single-flight.js +0 -158
  675. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +0 -108
  676. package/node_modules/pi-lens/dist/clients/skills-resolver.js +0 -141
  677. package/node_modules/pi-lens/dist/clients/slow-fs.js +0 -138
  678. package/node_modules/pi-lens/dist/clients/smells-rollup.js +0 -231
  679. package/node_modules/pi-lens/dist/clients/source-filter.js +0 -596
  680. package/node_modules/pi-lens/dist/clients/source-walker.js +0 -211
  681. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +0 -120
  682. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +0 -110
  683. package/node_modules/pi-lens/dist/clients/stale-marker.js +0 -17
  684. package/node_modules/pi-lens/dist/clients/startup-scan.js +0 -400
  685. package/node_modules/pi-lens/dist/clients/startup-timing.js +0 -130
  686. package/node_modules/pi-lens/dist/clients/string-utils.js +0 -33
  687. package/node_modules/pi-lens/dist/clients/subagent-mode.js +0 -111
  688. package/node_modules/pi-lens/dist/clients/symbol-containment.js +0 -24
  689. package/node_modules/pi-lens/dist/clients/symbol-types.js +0 -5
  690. package/node_modules/pi-lens/dist/clients/test-runner-client.js +0 -2507
  691. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +0 -287
  692. package/node_modules/pi-lens/dist/clients/todo-scanner.js +0 -229
  693. package/node_modules/pi-lens/dist/clients/tool-agreement.js +0 -423
  694. package/node_modules/pi-lens/dist/clients/tool-config.js +0 -249
  695. package/node_modules/pi-lens/dist/clients/tool-cwd.js +0 -270
  696. package/node_modules/pi-lens/dist/clients/tool-definition.js +0 -47
  697. package/node_modules/pi-lens/dist/clients/tool-event.js +0 -105
  698. package/node_modules/pi-lens/dist/clients/tool-policy.js +0 -2755
  699. package/node_modules/pi-lens/dist/clients/tool-probe.js +0 -53
  700. package/node_modules/pi-lens/dist/clients/tool-render.js +0 -156
  701. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +0 -118
  702. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +0 -364
  703. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +0 -4195
  704. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +0 -100
  705. package/node_modules/pi-lens/dist/clients/tree-sitter-navigator.js +0 -269
  706. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +0 -569
  707. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +0 -158
  708. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  709. package/node_modules/pi-lens/dist/clients/trivy-client.js +0 -467
  710. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -50
  711. package/node_modules/pi-lens/dist/clients/turn-context.js +0 -52
  712. package/node_modules/pi-lens/dist/clients/turn-end/lane.js +0 -51
  713. package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -112
  714. package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +0 -204
  715. package/node_modules/pi-lens/dist/clients/turn-summary-render.js +0 -72
  716. package/node_modules/pi-lens/dist/clients/turn-summary.js +0 -132
  717. package/node_modules/pi-lens/dist/clients/typos-config.js +0 -29
  718. package/node_modules/pi-lens/dist/clients/user-notify.js +0 -51
  719. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +0 -57
  720. package/node_modules/pi-lens/dist/clients/warm-attach.js +0 -305
  721. package/node_modules/pi-lens/dist/clients/widget-state.js +0 -1808
  722. package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -49
  723. package/node_modules/pi-lens/dist/clients/word-index-store.js +0 -459
  724. package/node_modules/pi-lens/dist/clients/word-index.js +0 -2080
  725. package/node_modules/pi-lens/dist/clients/workspace-topology.js +0 -443
  726. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +0 -65
  727. package/node_modules/pi-lens/dist/clients/zizmor-config.js +0 -340
  728. package/node_modules/pi-lens/dist/i18n.js +0 -69
  729. package/node_modules/pi-lens/dist/mcp/build-staleness.js +0 -124
  730. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +0 -583
  731. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +0 -129
  732. package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
  733. package/node_modules/pi-lens/dist/tools/activate-tools.js +0 -87
  734. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +0 -137
  735. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +0 -244
  736. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +0 -762
  737. package/node_modules/pi-lens/dist/tools/effective-config.js +0 -90
  738. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +0 -375
  739. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +0 -2571
  740. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +0 -1745
  741. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +0 -1367
  742. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +0 -294
  743. package/node_modules/pi-lens/dist/tools/module-report.js +0 -382
  744. package/node_modules/pi-lens/dist/tools/project-report.js +0 -86
  745. package/node_modules/pi-lens/dist/tools/render-compact.js +0 -374
  746. package/node_modules/pi-lens/dist/tools/scan-progress.js +0 -53
  747. package/node_modules/pi-lens/dist/tools/shared.js +0 -29
  748. package/node_modules/pi-lens/dist/tools/symbol-search.js +0 -155
  749. package/node_modules/pi-web-access/opencode-session-headers.ts +0 -24
  750. package/node_modules/remote-pi/README.md +0 -675
  751. package/node_modules/remote-pi/dist/actions/handlers.d.ts +0 -122
  752. package/node_modules/remote-pi/dist/actions/handlers.js +0 -160
  753. package/node_modules/remote-pi/dist/actions/handlers.js.map +0 -1
  754. package/node_modules/remote-pi/dist/actions/registry.d.ts +0 -39
  755. package/node_modules/remote-pi/dist/actions/registry.js +0 -58
  756. package/node_modules/remote-pi/dist/actions/registry.js.map +0 -1
  757. package/node_modules/remote-pi/dist/bin/supervisord.d.ts +0 -2
  758. package/node_modules/remote-pi/dist/bin/supervisord.js +0 -86
  759. package/node_modules/remote-pi/dist/bin/supervisord.js.map +0 -1
  760. package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +0 -58
  761. package/node_modules/remote-pi/dist/commands/builtin_mirror.js +0 -71
  762. package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +0 -1
  763. package/node_modules/remote-pi/dist/commands/list_commands.d.ts +0 -60
  764. package/node_modules/remote-pi/dist/commands/list_commands.js +0 -73
  765. package/node_modules/remote-pi/dist/commands/list_commands.js.map +0 -1
  766. package/node_modules/remote-pi/dist/config.d.ts +0 -62
  767. package/node_modules/remote-pi/dist/config.js +0 -115
  768. package/node_modules/remote-pi/dist/config.js.map +0 -1
  769. package/node_modules/remote-pi/dist/daemon/client.d.ts +0 -20
  770. package/node_modules/remote-pi/dist/daemon/client.js +0 -131
  771. package/node_modules/remote-pi/dist/daemon/client.js.map +0 -1
  772. package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +0 -176
  773. package/node_modules/remote-pi/dist/daemon/control_protocol.js +0 -63
  774. package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +0 -1
  775. package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +0 -45
  776. package/node_modules/remote-pi/dist/daemon/cron_log.js +0 -72
  777. package/node_modules/remote-pi/dist/daemon/cron_log.js.map +0 -1
  778. package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +0 -80
  779. package/node_modules/remote-pi/dist/daemon/cron_registry.js +0 -194
  780. package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +0 -1
  781. package/node_modules/remote-pi/dist/daemon/id.d.ts +0 -24
  782. package/node_modules/remote-pi/dist/daemon/id.js +0 -36
  783. package/node_modules/remote-pi/dist/daemon/id.js.map +0 -1
  784. package/node_modules/remote-pi/dist/daemon/install.d.ts +0 -170
  785. package/node_modules/remote-pi/dist/daemon/install.js +0 -547
  786. package/node_modules/remote-pi/dist/daemon/install.js.map +0 -1
  787. package/node_modules/remote-pi/dist/daemon/registry.d.ts +0 -63
  788. package/node_modules/remote-pi/dist/daemon/registry.js +0 -153
  789. package/node_modules/remote-pi/dist/daemon/registry.js.map +0 -1
  790. package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +0 -194
  791. package/node_modules/remote-pi/dist/daemon/rpc_child.js +0 -389
  792. package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +0 -1
  793. package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +0 -93
  794. package/node_modules/remote-pi/dist/daemon/supervisor.js +0 -596
  795. package/node_modules/remote-pi/dist/daemon/supervisor.js.map +0 -1
  796. package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +0 -26
  797. package/node_modules/remote-pi/dist/extension_ui_bridge.js +0 -341
  798. package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +0 -1
  799. package/node_modules/remote-pi/dist/index.d.ts +0 -213
  800. package/node_modules/remote-pi/dist/index.js +0 -4996
  801. package/node_modules/remote-pi/dist/index.js.map +0 -1
  802. package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +0 -10
  803. package/node_modules/remote-pi/dist/mcp/mesh_result.js +0 -42
  804. package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +0 -1
  805. package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +0 -16
  806. package/node_modules/remote-pi/dist/mcp/mesh_server.js +0 -327
  807. package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +0 -1
  808. package/node_modules/remote-pi/dist/mesh/canonical.d.ts +0 -30
  809. package/node_modules/remote-pi/dist/mesh/canonical.js +0 -61
  810. package/node_modules/remote-pi/dist/mesh/canonical.js.map +0 -1
  811. package/node_modules/remote-pi/dist/mesh/client.d.ts +0 -18
  812. package/node_modules/remote-pi/dist/mesh/client.js +0 -125
  813. package/node_modules/remote-pi/dist/mesh/client.js.map +0 -1
  814. package/node_modules/remote-pi/dist/mesh/encoding.d.ts +0 -38
  815. package/node_modules/remote-pi/dist/mesh/encoding.js +0 -216
  816. package/node_modules/remote-pi/dist/mesh/encoding.js.map +0 -1
  817. package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +0 -73
  818. package/node_modules/remote-pi/dist/mesh/self_revoke.js +0 -401
  819. package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +0 -1
  820. package/node_modules/remote-pi/dist/mesh/siblings.d.ts +0 -49
  821. package/node_modules/remote-pi/dist/mesh/siblings.js +0 -159
  822. package/node_modules/remote-pi/dist/mesh/siblings.js.map +0 -1
  823. package/node_modules/remote-pi/dist/mesh/types.d.ts +0 -34
  824. package/node_modules/remote-pi/dist/mesh/types.js +0 -11
  825. package/node_modules/remote-pi/dist/mesh/types.js.map +0 -1
  826. package/node_modules/remote-pi/dist/mesh/verify.d.ts +0 -17
  827. package/node_modules/remote-pi/dist/mesh/verify.js +0 -86
  828. package/node_modules/remote-pi/dist/mesh/verify.js.map +0 -1
  829. package/node_modules/remote-pi/dist/pairing/crypto.d.ts +0 -8
  830. package/node_modules/remote-pi/dist/pairing/crypto.js +0 -22
  831. package/node_modules/remote-pi/dist/pairing/crypto.js.map +0 -1
  832. package/node_modules/remote-pi/dist/pairing/handshake.d.ts +0 -28
  833. package/node_modules/remote-pi/dist/pairing/handshake.js +0 -113
  834. package/node_modules/remote-pi/dist/pairing/handshake.js.map +0 -1
  835. package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +0 -16
  836. package/node_modules/remote-pi/dist/pairing/noise-sha256.js +0 -103
  837. package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +0 -1
  838. package/node_modules/remote-pi/dist/pairing/qr.d.ts +0 -59
  839. package/node_modules/remote-pi/dist/pairing/qr.js +0 -125
  840. package/node_modules/remote-pi/dist/pairing/qr.js.map +0 -1
  841. package/node_modules/remote-pi/dist/pairing/storage.d.ts +0 -120
  842. package/node_modules/remote-pi/dist/pairing/storage.js +0 -604
  843. package/node_modules/remote-pi/dist/pairing/storage.js.map +0 -1
  844. package/node_modules/remote-pi/dist/protocol/codec.d.ts +0 -7
  845. package/node_modules/remote-pi/dist/protocol/codec.js +0 -49
  846. package/node_modules/remote-pi/dist/protocol/codec.js.map +0 -1
  847. package/node_modules/remote-pi/dist/protocol/types.d.ts +0 -393
  848. package/node_modules/remote-pi/dist/protocol/types.js +0 -2
  849. package/node_modules/remote-pi/dist/protocol/types.js.map +0 -1
  850. package/node_modules/remote-pi/dist/rooms.d.ts +0 -29
  851. package/node_modules/remote-pi/dist/rooms.js +0 -57
  852. package/node_modules/remote-pi/dist/rooms.js.map +0 -1
  853. package/node_modules/remote-pi/dist/session/address.d.ts +0 -49
  854. package/node_modules/remote-pi/dist/session/address.js +0 -58
  855. package/node_modules/remote-pi/dist/session/address.js.map +0 -1
  856. package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +0 -55
  857. package/node_modules/remote-pi/dist/session/agent_bridge.js +0 -146
  858. package/node_modules/remote-pi/dist/session/agent_bridge.js.map +0 -1
  859. package/node_modules/remote-pi/dist/session/bridge.d.ts +0 -37
  860. package/node_modules/remote-pi/dist/session/bridge.js +0 -130
  861. package/node_modules/remote-pi/dist/session/bridge.js.map +0 -1
  862. package/node_modules/remote-pi/dist/session/broker.d.ts +0 -189
  863. package/node_modules/remote-pi/dist/session/broker.js +0 -507
  864. package/node_modules/remote-pi/dist/session/broker.js.map +0 -1
  865. package/node_modules/remote-pi/dist/session/broker_remote.d.ts +0 -74
  866. package/node_modules/remote-pi/dist/session/broker_remote.js +0 -583
  867. package/node_modules/remote-pi/dist/session/broker_remote.js.map +0 -1
  868. package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +0 -33
  869. package/node_modules/remote-pi/dist/session/cwd_lock.js +0 -126
  870. package/node_modules/remote-pi/dist/session/cwd_lock.js.map +0 -1
  871. package/node_modules/remote-pi/dist/session/envelope.d.ts +0 -33
  872. package/node_modules/remote-pi/dist/session/envelope.js +0 -117
  873. package/node_modules/remote-pi/dist/session/envelope.js.map +0 -1
  874. package/node_modules/remote-pi/dist/session/global_config.d.ts +0 -33
  875. package/node_modules/remote-pi/dist/session/global_config.js +0 -73
  876. package/node_modules/remote-pi/dist/session/global_config.js.map +0 -1
  877. package/node_modules/remote-pi/dist/session/ipc.d.ts +0 -27
  878. package/node_modules/remote-pi/dist/session/ipc.js +0 -22
  879. package/node_modules/remote-pi/dist/session/ipc.js.map +0 -1
  880. package/node_modules/remote-pi/dist/session/leader_election.d.ts +0 -32
  881. package/node_modules/remote-pi/dist/session/leader_election.js +0 -106
  882. package/node_modules/remote-pi/dist/session/leader_election.js.map +0 -1
  883. package/node_modules/remote-pi/dist/session/local_config.d.ts +0 -55
  884. package/node_modules/remote-pi/dist/session/local_config.js +0 -157
  885. package/node_modules/remote-pi/dist/session/local_config.js.map +0 -1
  886. package/node_modules/remote-pi/dist/session/mesh_message.d.ts +0 -20
  887. package/node_modules/remote-pi/dist/session/mesh_message.js +0 -28
  888. package/node_modules/remote-pi/dist/session/mesh_message.js.map +0 -1
  889. package/node_modules/remote-pi/dist/session/mesh_node.d.ts +0 -116
  890. package/node_modules/remote-pi/dist/session/mesh_node.js +0 -573
  891. package/node_modules/remote-pi/dist/session/mesh_node.js.map +0 -1
  892. package/node_modules/remote-pi/dist/session/peer.d.ts +0 -139
  893. package/node_modules/remote-pi/dist/session/peer.js +0 -451
  894. package/node_modules/remote-pi/dist/session/peer.js.map +0 -1
  895. package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +0 -13
  896. package/node_modules/remote-pi/dist/session/peer_inventory.js +0 -48
  897. package/node_modules/remote-pi/dist/session/peer_inventory.js.map +0 -1
  898. package/node_modules/remote-pi/dist/session/peer_limits.d.ts +0 -9
  899. package/node_modules/remote-pi/dist/session/peer_limits.js +0 -21
  900. package/node_modules/remote-pi/dist/session/peer_limits.js.map +0 -1
  901. package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +0 -39
  902. package/node_modules/remote-pi/dist/session/setup_wizard.js +0 -63
  903. package/node_modules/remote-pi/dist/session/setup_wizard.js.map +0 -1
  904. package/node_modules/remote-pi/dist/session/tool_gate.d.ts +0 -5
  905. package/node_modules/remote-pi/dist/session/tool_gate.js +0 -11
  906. package/node_modules/remote-pi/dist/session/tool_gate.js.map +0 -1
  907. package/node_modules/remote-pi/dist/session/tools.d.ts +0 -24
  908. package/node_modules/remote-pi/dist/session/tools.js +0 -252
  909. package/node_modules/remote-pi/dist/session/tools.js.map +0 -1
  910. package/node_modules/remote-pi/dist/session/wizard.d.ts +0 -13
  911. package/node_modules/remote-pi/dist/session/wizard.js +0 -20
  912. package/node_modules/remote-pi/dist/session/wizard.js.map +0 -1
  913. package/node_modules/remote-pi/dist/settings.d.ts +0 -15
  914. package/node_modules/remote-pi/dist/settings.js +0 -52
  915. package/node_modules/remote-pi/dist/settings.js.map +0 -1
  916. package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +0 -37
  917. package/node_modules/remote-pi/dist/transport/peer_channel.js +0 -98
  918. package/node_modules/remote-pi/dist/transport/peer_channel.js.map +0 -1
  919. package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +0 -29
  920. package/node_modules/remote-pi/dist/transport/pi_forward_client.js +0 -62
  921. package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +0 -1
  922. package/node_modules/remote-pi/dist/transport/relay_client.d.ts +0 -91
  923. package/node_modules/remote-pi/dist/transport/relay_client.js +0 -206
  924. package/node_modules/remote-pi/dist/transport/relay_client.js.map +0 -1
  925. package/node_modules/remote-pi/dist/ui/footer.d.ts +0 -32
  926. package/node_modules/remote-pi/dist/ui/footer.js +0 -34
  927. package/node_modules/remote-pi/dist/ui/footer.js.map +0 -1
  928. package/node_modules/remote-pi/docs/daemon.md +0 -289
  929. package/node_modules/remote-pi/package.json +0 -92
  930. package/node_modules/remote-pi/service-templates/launchd.plist.template +0 -35
  931. package/node_modules/remote-pi/service-templates/systemd.service.template +0 -19
  932. package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +0 -10
  933. package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +0 -38
  934. package/node_modules/remote-pi/skills/agent-network/SKILL.md +0 -310
@@ -1,2049 +0,0 @@
1
- import * as nodeCrypto from "node:crypto";
2
- import * as nodeFs from "node:fs";
3
- import * as path from "node:path";
4
- import { noteAuthoritativeContentAttachment } from "./agent-nudge.js";
5
- import { captureFileStats, diffFileContent, getOpaqueBaselineStore, recoverOpaqueChangesViaGit, } from "./opaque-mutation-scan.js";
6
- import { normalizeMapKey } from "./path-utils.js";
7
- import { detectFileKind } from "./file-kinds.js";
8
- import { extractReadPathsFromCommand, extractDeletedPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, tokenizeShellCommand, } from "./bash-file-access.js";
9
- import { registerSearchReads, } from "./search-read-registration.js";
10
- import { createFileTime } from "./file-time.js";
11
- import { publishFormatQueued } from "./format-events-publish.js";
12
- import { invalidateProjectIgnoreMatcherForPath, isPathIgnoredByProject, } from "./file-utils.js";
13
- import { invalidateFormatterCacheForPath } from "./formatters.js";
14
- import { getFormatService } from "./format-service.js";
15
- import { isExternalOrVendorFile, normalizeEphemeralMapKey, pathsEqual, } from "./path-utils.js";
16
- import { PathKeyedMap } from "./path-keyed-map.js";
17
- import { resolveLanguageRootForFile } from "./language-profile.js";
18
- import { logLatency } from "./latency-logger.js";
19
- import { classifyMutatingTool, PI_LENS_SYNTHETIC_MUTATION_FIELD, } from "./mutating-tool.js";
20
- import { hasPendingObservation, noteMutationHandled, settleObservedMutation, } from "./observed-mutation.js";
21
- import { replayThroughMutationBridge, storedLineHashesFor, } from "./observed-mutation-sources.js";
22
- import { getAmbientAbortSignal } from "./safe-spawn.js";
23
- import { resolveToolCallCorrelationId } from "./tool-event.js";
24
- import { boundedIndexesForCount, createReadGuardEditBatchSummary, getReadGuardCorrelationId, logReadGuardEvent, } from "./read-guard-logger.js";
25
- import { countFileLines } from "./read-guard-tool-lines.js";
26
- import { notifyExternalFileChange, resyncGitChangedFiles, } from "./lsp/index.js";
27
- import { runPipeline } from "./pipeline.js";
28
- import { renderPostAutofixNotice, } from "./post-autofix-notice.js";
29
- import { syncGitGuardRecord } from "./git-guard.js";
30
- import { scheduleWordIndexPersist } from "./word-index.js";
31
- import { RUNTIME_CONFIG } from "./runtime-config.js";
32
- import { getActiveSessionId } from "./session-lifecycle.js";
33
- import { requestBootstrapClients } from "./bootstrap.js";
34
- import { bounded } from "./deadline-utils.js";
35
- import { HOOK_WALL_BUDGET_MS } from "./hook-budgets.js";
36
- import { incrementDegradationCount, recordDegradationOnce, } from "./degradation-ledger.js";
37
- const AUTHORITATIVE_CONTENT_MAX_BYTES = RUNTIME_CONFIG.pipeline.lspMaxFileBytes;
38
- // Keep same-turn analysis below the observed-directory capture bound so one
39
- // opaque codemod cannot monopolize the hook or analyzer fleet.
40
- const OBSERVED_DISPATCH_MAX_PATHS = 32;
41
- /**
42
- * Git subcommands that import ANOTHER commit's content into the index. The
43
- * whole family, with a verdict for each (#2060):
44
- * - merge, rebase, cherry-pick, pull, revert, am: IN. Each stages the other
45
- * side's clean files beside the unmerged ones. `pull` is fetch+merge and
46
- * `am --3way` reaches the same unmerged state, both probed on git 2.55.
47
- * - stash pop / stash apply: OUT. A conflicted pop leaves `M ` entries too,
48
- * but that content is the agent's OWN stashed work. Excluding it would
49
- * destroy exactly what opaque recovery exists to capture.
50
- * - checkout -m: OUT. Its "incoming" side is the agent's local modifications
51
- * carried across the switch, so the same reasoning applies.
52
- * - apply -3 / --3way: OUT. The patch is normally one the agent wrote, and
53
- * `apply` is far more often used without conflicts, so the narrower default
54
- * is to keep capturing.
55
- * Membership only ARMS the filter; it still needs a real unmerged entry to do
56
- * anything, so a non-integration use of a listed subcommand is inert.
57
- */
58
- const GIT_INTEGRATION_SUBCOMMANDS = new Set([
59
- "merge",
60
- "rebase",
61
- "cherry-pick",
62
- "pull",
63
- "revert",
64
- "am",
65
- ]);
66
- const GIT_GLOBAL_OPTIONS_WITH_VALUE = new Set([
67
- "-C",
68
- "-c",
69
- "--config-env",
70
- "--git-dir",
71
- "--namespace",
72
- "--work-tree",
73
- ]);
74
- /**
75
- * Failed integration commands are the one opaque-recovery case where Git's
76
- * index contains changes made by the other branch rather than the agent.
77
- * Keep this narrow: ordinary scripts and successful Git operations retain the
78
- * normal recovery contract.
79
- */
80
- export function isFailedGitIntegrationCommand(command, isError) {
81
- if (isError !== true)
82
- return false;
83
- return tokenizeShellCommand(command).some(({ tokens, unsupported }) => {
84
- if (unsupported)
85
- return false;
86
- const executable = path.win32
87
- .basename(tokens[0] ?? "")
88
- .toLowerCase()
89
- .replace(/\.(?:cmd|exe)$/, "");
90
- if (executable !== "git")
91
- return false;
92
- for (let index = 1; index < tokens.length; index += 1) {
93
- const token = tokens[index] ?? "";
94
- if (GIT_GLOBAL_OPTIONS_WITH_VALUE.has(token)) {
95
- index += 1;
96
- continue;
97
- }
98
- if (token.startsWith("-"))
99
- continue;
100
- return GIT_INTEGRATION_SUBCOMMANDS.has(token);
101
- }
102
- return false;
103
- });
104
- }
105
- function ensureToolResultClients(deps) {
106
- if (deps.biomeClient && deps.ruffClient && deps.metricsClient)
107
- return true;
108
- const request = {
109
- reason: "tool-result-analysis",
110
- hook: "tool_result_edit",
111
- timeoutMs: HOOK_WALL_BUDGET_MS.tool_result_edit,
112
- ...(deps.signal === undefined ? {} : { signal: deps.signal }),
113
- };
114
- return bounded(requestBootstrapClients(request), {
115
- ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
116
- signal: deps.signal,
117
- hook: "tool_result_edit",
118
- label: "tool-result-bootstrap-demand",
119
- }).then((clients) => {
120
- if (!clients)
121
- return false;
122
- deps.biomeClient = clients.biomeClient;
123
- deps.ruffClient = clients.ruffClient;
124
- deps.metricsClient = clients.metricsClient;
125
- return true;
126
- });
127
- }
128
- function parseDiffRanges(diff) {
129
- const changedLines = [];
130
- for (const line of diff.split("\n")) {
131
- const match = line.match(/^[+-]\s*(\d+)\s/);
132
- if (match) {
133
- changedLines.push(Number.parseInt(match[1], 10));
134
- }
135
- }
136
- if (changedLines.length === 0)
137
- return [];
138
- const sorted = [...new Set(changedLines)].sort((a, b) => a - b);
139
- const ranges = [];
140
- let rangeStart = sorted[0];
141
- let rangeEnd = sorted[0];
142
- for (const line of sorted.slice(1)) {
143
- if (line <= rangeEnd + 1) {
144
- rangeEnd = line;
145
- }
146
- else {
147
- ranges.push({ start: rangeStart, end: rangeEnd });
148
- rangeStart = line;
149
- rangeEnd = line;
150
- }
151
- }
152
- ranges.push({ start: rangeStart, end: rangeEnd });
153
- return ranges;
154
- }
155
- // Keyed by (normalized) filePath, then by the raw stateHash — the path portion
156
- // needs normalizing (divergent Windows spellings must collapse to one entry),
157
- // the stateHash suffix must NOT be folded into the path key (a real content
158
- // change for the same file has to stay a distinct entry). A flat
159
- // `PathKeyedMap<InFlightPipeline>` keyed by a composite `${filePath}:${hash}`
160
- // string can't express that split cleanly (the normalizer only sees the whole
161
- // composite string, so it can't fold the path half without also mangling the
162
- // hash half); nesting keeps each axis normalized/compared with its own rules.
163
- const inFlightPipelines = new PathKeyedMap(normalizeEphemeralMapKey);
164
- const lastAnalyzedStateByFile = new PathKeyedMap(normalizeEphemeralMapKey);
165
- // Called at turn_start — entries from the previous turn can never match the new
166
- // turnIndex so they're dead weight. Clearing here keeps the map bounded to the
167
- // files touched in the current turn only (typically < 20).
168
- export function clearLastAnalyzedStateCache() {
169
- lastAnalyzedStateByFile.clear();
170
- }
171
- /**
172
- * Register one in-flight pipeline and hand back the inner map it landed in.
173
- *
174
- * Paired with {@link releaseInFlightPipeline}; split out of
175
- * `dispatchPipelineAnalysis` so registration and deregistration are one seam
176
- * with one owner (#2464 review round 3, F1) rather than two open-coded blocks
177
- * ~80 lines apart whose invariants only line up if a reader checks both.
178
- *
179
- * Kept private because both dispatch call sites now use the shared claim before
180
- * registration; publishing this seam without the claim obligation would make
181
- * the identity guard's precondition easy to violate again.
182
- */
183
- function registerInFlightPipeline(filePath, stateHash, pipeline) {
184
- let filePipelines = inFlightPipelines.get(filePath);
185
- if (!filePipelines) {
186
- filePipelines = new Map();
187
- inFlightPipelines.set(filePath, filePipelines);
188
- }
189
- filePipelines.set(stateHash, pipeline);
190
- return filePipelines;
191
- }
192
- /**
193
- * Release one in-flight pipeline, pruning the per-file inner map once it is
194
- * empty so a file touched once this session doesn't leave a permanent empty
195
- * entry in the outer map.
196
- *
197
- * The IDENTITY check on the outer delete is load-bearing (#2464 review round 3,
198
- * F1). `registered` is a reference captured BEFORE the pipeline await. Deleting
199
- * by path alone assumes the outer entry still IS that map, and when it is not —
200
- * anything that replaced it while this pipeline ran — the delete evicts a LIVE,
201
- * unrelated pipeline's registration: its concurrent duplicates then stop
202
- * deduping and its `participantIds`/`participantTotal` under-count. Delete only
203
- * when the outer map still points at the very map this registration went into.
204
- */
205
- function releaseInFlightPipeline(filePath, stateHash, registered) {
206
- registered.delete(stateHash);
207
- if (registered.size === 0 && inFlightPipelines.get(filePath) === registered) {
208
- inFlightPipelines.delete(filePath);
209
- }
210
- }
211
- /**
212
- * The two pre-conditions EVERY pipeline dispatch shares (#2464 review round 3,
213
- * F1): the in-flight dedup for a concurrent call on the same post-write state,
214
- * and the already-analysed latch for a sequential duplicate in the same turn.
215
- *
216
- * Both call sites of {@link dispatchPipelineAnalysis} consult this, so the
217
- * PRE-conditions are as by-construction as the post-conditions that helper
218
- * already owns. The observed-mutation path shipped without either check in
219
- * round 2: two concurrent observed `tool_result`s for one file+hash both
220
- * registered, the second overwrote the first's entry in the per-file map, and
221
- * the first's release then evicted the whole outer entry — taking a live,
222
- * unrelated classified pipeline's registration with it.
223
- *
224
- * ## Why this is SYNCHRONOUS and hands the join promise back
225
- *
226
- * Check-then-act here has to be atomic against the microtask queue.
227
- * `dispatchPipelineAnalysis` registers synchronously before its own first
228
- * await, so a caller that claims and then dispatches with no `await` in between
229
- * cannot be interleaved. An `async` pre-check would reintroduce exactly that
230
- * interleave — both racers see an empty registry, both resume, both dispatch —
231
- * so the join's `await` is deliberately left to the caller.
232
- *
233
- * ## Why this is NOT folded into `dispatchPipelineAnalysis`
234
- *
235
- * On the classified chain the latch check sits ABOVE `addModifiedRange` and
236
- * `recordProjectChange`. Moving it down into the helper would write
237
- * `turn-state.json` ranges and an attributed change-log receipt for a state
238
- * already analysed this turn — the duplicate-recording inversion #2464 exists
239
- * to remove.
240
- */
241
- function claimPipelineDispatch(args) {
242
- const { filePath, stateHash, turnIndex, participantId, dbg } = args;
243
- // Deduplicate concurrent calls for the same final file state (pi can fire one
244
- // tool_result per edit hunk). Do not dedupe by file alone: a distinct later
245
- // same-turn edit to this file must still be analyzed.
246
- const inFlight = inFlightPipelines.get(filePath)?.get(stateHash);
247
- if (inFlight) {
248
- dbg(`tool_result: skipping duplicate concurrent state for ${filePath}`);
249
- if (inFlight.participantIds.length < 100) {
250
- inFlight.participantIds.push(participantId);
251
- }
252
- inFlight.participantTotal += 1;
253
- return { proceed: false, joined: inFlight.promise };
254
- }
255
- // Deduplicate sequential duplicate events for the same post-write state in
256
- // the same turn while allowing later same-file edits whose content changed.
257
- const lastAnalyzed = lastAnalyzedStateByFile.get(filePath);
258
- if (lastAnalyzed?.turnIndex === turnIndex &&
259
- lastAnalyzed.stateHash === stateHash) {
260
- dbg(`tool_result: skipping already-analyzed file state this turn for ${filePath}`);
261
- return { proceed: false, joined: undefined };
262
- }
263
- return { proceed: true };
264
- }
265
- const debouncedPipelines = new PathKeyedMap(normalizeEphemeralMapKey);
266
- const DEFAULT_DEBOUNCE_MS = 0;
267
- const MAX_DEBOUNCE_MS = 1000;
268
- function getDebounceMs() {
269
- const raw = Number(process.env.PI_LENS_TOOL_RESULT_DEBOUNCE_MS);
270
- if (!Number.isFinite(raw) || raw < 0)
271
- return DEFAULT_DEBOUNCE_MS;
272
- // Cap at 1s so turn_end and agent_end don't block on the timer for
273
- // pathologically long windows. flushDebouncedToolResults below also
274
- // short-circuits at boundary events.
275
- return Math.min(raw, MAX_DEBOUNCE_MS);
276
- }
277
- /**
278
- * Drain any pending debounced tool_result pipelines immediately, awaiting their
279
- * completion. Call from turn_end / agent_end before reading anything that depends
280
- * on the pipeline's bookkeeping (project change log, modified ranges, etc.).
281
- *
282
- * Passing a filePath flushes only that entry; omitting it flushes all.
283
- */
284
- export async function flushDebouncedToolResults(filePath) {
285
- const entries = filePath
286
- ? debouncedPipelines.has(filePath)
287
- ? [
288
- [
289
- filePath,
290
- debouncedPipelines.get(filePath),
291
- ],
292
- ]
293
- : []
294
- : [...debouncedPipelines.entries()];
295
- for (const [key, entry] of entries) {
296
- clearTimeout(entry.timer);
297
- debouncedPipelines.delete(key);
298
- // Re-enter the pipeline synchronously via the bypass flag so the
299
- // timer body's resolve/reject still fires through the shared promise.
300
- handleToolResult({ ...entry.latestDeps, _bypassDebounce: true }).then(entry.resolve, entry.reject);
301
- }
302
- if (entries.length > 0) {
303
- // Allow microtasks to settle so awaiting callers see the latest state.
304
- await Promise.all(entries.map(([, entry]) => entry.promise.catch(() => undefined)));
305
- }
306
- }
307
- function scheduleDebounced(filePath, debounceMs, deps) {
308
- const existing = debouncedPipelines.get(filePath);
309
- if (existing) {
310
- clearTimeout(existing.timer);
311
- const incomingId = deps._telemetryParticipantIds?.[0] ??
312
- getReadGuardCorrelationId(deps.event);
313
- const priorIds = existing.latestDeps._telemetryParticipantIds ?? [];
314
- existing.latestDeps = {
315
- ...deps,
316
- _telemetryParticipantIds: [...priorIds, incomingId].slice(0, 100),
317
- _telemetryParticipantTotal: (existing.latestDeps._telemetryParticipantTotal ?? priorIds.length) + 1,
318
- };
319
- existing.coalescedCount += 1;
320
- existing.timer = setTimeout(() => {
321
- debouncedPipelines.delete(filePath);
322
- deps.dbg(`tool_result: debounce fired after ${existing.coalescedCount} coalesced calls for ${filePath}`);
323
- handleToolResult({ ...existing.latestDeps, _bypassDebounce: true }).then(existing.resolve, existing.reject);
324
- }, debounceMs);
325
- deps.dbg(`tool_result: coalesced into pending debounce for ${filePath} (count=${existing.coalescedCount})`);
326
- return existing.promise;
327
- }
328
- let resolveFn;
329
- let rejectFn;
330
- const promise = new Promise((res, rej) => {
331
- resolveFn = res;
332
- rejectFn = rej;
333
- });
334
- const initialParticipantIds = deps._telemetryParticipantIds ?? [
335
- getReadGuardCorrelationId(deps.event),
336
- ];
337
- const entry = {
338
- timer: setTimeout(() => {
339
- debouncedPipelines.delete(filePath);
340
- handleToolResult({ ...entry.latestDeps, _bypassDebounce: true }).then(entry.resolve, entry.reject);
341
- }, debounceMs),
342
- promise,
343
- resolve: resolveFn,
344
- reject: rejectFn,
345
- latestDeps: {
346
- ...deps,
347
- _telemetryParticipantIds: initialParticipantIds.slice(0, 100),
348
- _telemetryParticipantTotal: deps._telemetryParticipantTotal ?? initialParticipantIds.length,
349
- },
350
- scheduledAt: Date.now(),
351
- coalescedCount: 1,
352
- };
353
- debouncedPipelines.set(filePath, entry);
354
- return promise;
355
- }
356
- function getFileStateHash(filePath) {
357
- try {
358
- const content = nodeFs.readFileSync(filePath);
359
- return nodeCrypto.createHash("sha256").update(content).digest("hex");
360
- }
361
- catch (err) {
362
- const code = err.code ?? "unknown";
363
- return `unreadable:${code}`;
364
- }
365
- }
366
- function getRequestedEditCount(event, kind) {
367
- if (kind === "write")
368
- return 1;
369
- const edits = event.input?.edits;
370
- return Array.isArray(edits) && edits.length > 0 ? edits.length : 1;
371
- }
372
- function getRequestedEditIndexes(event, kind) {
373
- return boundedIndexesForCount(getRequestedEditCount(event, kind));
374
- }
375
- /**
376
- * Change-log attribution for one classified mutation (#2423).
377
- *
378
- * A third-party tool gets its OWN source (`agent-tool:<name>`) rather than
379
- * being folded into `agent-edit`: a report that attributes a change to "the
380
- * model's edit tool" must not silently absorb an extension's rewrite.
381
- */
382
- function sourceForMutation(classification, details) {
383
- if (details
384
- ?.piLensPartialApply) {
385
- return "partial-apply";
386
- }
387
- if (classification.provenance === "builtin" ||
388
- classification.provenance === "bash-derived") {
389
- return classification.kind === "write" ? "agent-write" : "agent-edit";
390
- }
391
- return `agent-tool:${classification.toolName}`;
392
- }
393
- function singleRange(ranges) {
394
- return ranges?.length === 1 ? ranges[0] : undefined;
395
- }
396
- function recordProjectChange(args) {
397
- // One mutation seam (#2000 phase 1): bump + receipt + change-log live in
398
- // RuntimeCoordinator.recordProjectMutation; this wrapper only carries the
399
- // legacy dbg shape.
400
- args.runtime.recordProjectMutation?.({
401
- filePath: args.filePath,
402
- source: args.source,
403
- cwd: args.cwd,
404
- changedRange: args.changedRange,
405
- onAppendError: (err) => args.dbg(`project change log append failed for ${args.filePath}: ${err}`),
406
- });
407
- }
408
- /**
409
- * #2402 applied-edit records for a native edit tool, so an identical retry is
410
- * recognized as already-applied instead of escalating through the
411
- * oldText-not-found ladder. `input` carries the EXECUTED args (post-autopatch),
412
- * the same text the preflight resolves against.
413
- *
414
- * Extracted (#2449 review round 4, S4) because the observational-settle skip
415
- * path needs the IDENTICAL records: the mutation bridge does not write them, so
416
- * an early return that skipped this block left every retry of an observed
417
- * tool's edit looking unapplied. One body, two call sites — a second copy on the
418
- * skip path is the drift this repo keeps catching.
419
- */
420
- function recordNativeAppliedPairs(args) {
421
- const pairs = [];
422
- if (args.kind !== "edit")
423
- return pairs;
424
- const appliedInput = args.input;
425
- const record = (oldText, newText) => {
426
- if (typeof oldText === "string" && oldText.length > 0) {
427
- args.runtime.partialApplyRecords.record(args.filePath, oldText, newText, args.stateHash);
428
- pairs.push({ oldText, newText });
429
- }
430
- };
431
- if (Array.isArray(appliedInput.edits)) {
432
- for (const edit of appliedInput.edits)
433
- record(edit.oldText, edit.newText);
434
- }
435
- else {
436
- record(appliedInput.oldText, appliedInput.newText);
437
- }
438
- return pairs;
439
- }
440
- /**
441
- * Keep `cachedExports` in sync after each write/edit so the pre-write STOP check
442
- * does not fire on names that were removed from this file this session.
443
- *
444
- * Extracted for the same reason as {@link recordNativeAppliedPairs} (#2449
445
- * review round 4, S4): the mutation bridge does not touch this cache, so the
446
- * observational-settle skip path left it holding names an observed tool had
447
- * just deleted.
448
- */
449
- function refreshCachedExports(runtime, filePath) {
450
- if (runtime.cachedExports.size === 0 || !nodeFs.existsSync(filePath))
451
- return;
452
- const exportRe = new RegExp("export\\s+(?:async\\s+)?(?:function|class|const|let|type|interface)\\s+(\\w+)", "g");
453
- for (const [name, file] of runtime.cachedExports) {
454
- if (path.resolve(file) === path.resolve(filePath)) {
455
- runtime.cachedExports.delete(name);
456
- }
457
- }
458
- try {
459
- const freshContent = nodeFs.readFileSync(filePath, "utf-8");
460
- for (const match of freshContent.matchAll(exportRe)) {
461
- const name = match[1];
462
- if (!runtime.cachedExports.has(name)) {
463
- runtime.cachedExports.set(name, filePath);
464
- }
465
- }
466
- }
467
- catch {
468
- // Non-fatal — stale entry is worse than a missing one
469
- }
470
- }
471
- /**
472
- * #2464: the pipeline's own lint/diagnostics dispatch, factored out of the
473
- * block below that ALSO writes `turn-state.json` modified ranges and the
474
- * attributed change-log receipt (`cacheManager.addModifiedRange` /
475
- * `recordProjectChange`). The classified chain in `handleToolResult` still
476
- * does both, in the same order as before this split — see the call site
477
- * right after `recordProjectChange` below, which is byte-identical to what
478
- * used to be inlined there.
479
- *
480
- * The observed-mutation early return (#2430/#2449 round 4, S4) is the SECOND
481
- * caller: the mutation bridge already recorded the turn-state range and the
482
- * change-log receipt for that edit, so it calls this helper for analysis
483
- * WITHOUT asking for the recording a second time — which a shared "run the
484
- * pipeline AND record" block could not express.
485
- */
486
- async function dispatchPipelineAnalysis(args) {
487
- const { deps, runtime, filePath, dispatchCwd, turnStateCwd, autofixMode, modifiedRanges, writeIndex, initialStateHash, readGuardCorrelationId, requestedEditIndexes, requestedEditTotal, isPartialApplyResult, toolResultStart, nativeAppliedPairs, allowAutonomousWriters, } = args;
488
- const { event, getFlag, getFlagSource, dbg, biomeClient, ruffClient, metricsClient, resetLSPService, } = deps;
489
- const pipelinePromise = runPipeline({
490
- signal: deps.signal,
491
- filePath,
492
- cwd: dispatchCwd,
493
- projectRoot: turnStateCwd,
494
- toolName: event.toolName,
495
- autofixMode,
496
- allowAutonomousWriters,
497
- modifiedRanges,
498
- telemetry: {
499
- model: runtime.telemetryModel,
500
- sessionId: runtime.telemetrySessionId,
501
- turnIndex: runtime.turnIndex,
502
- writeIndex,
503
- modelId: runtime.telemetryModelId,
504
- provider: runtime.telemetryProviderId,
505
- },
506
- getFlag,
507
- getFlagSource,
508
- dbg,
509
- // #451: hand the deferred cascade live sequence accessors so the
510
- // review-graph builder can skip its per-build O(project) sweep when
511
- // only pi-observed edits happened. projectSeq is a function because the
512
- // cascade runs after this returns (#450) — read current, not captured.
513
- seqState: {
514
- projectSeq: () => runtime.projectSeq,
515
- getFilesChangedSince: (seq) => runtime.getFilesChangedSince(seq),
516
- },
517
- // The settle clock is live because the deferred cascade may reach its
518
- // budget derivation before or after turn_end starts waiting.
519
- turnEndCascadeSettleStart: () => runtime.getTurnEndCascadeSettleStart(),
520
- // #348 phase 2: live reference so the deferred cascade can update the
521
- // warm word index in place at the same seam as the graph rebuild.
522
- // `runtime.wordIndex` is read fresh (not captured) via this closure-free
523
- // property access being re-evaluated at object-literal construction
524
- // time here — that's fine because runPipeline reads `ctx.wordIndex`
525
- // synchronously into computeCascadeForFile's options before returning
526
- // (the deferred part is the cascade's OWN execution, not this handoff).
527
- wordIndex: runtime.wordIndex,
528
- onWordIndexUpdated: (index) => {
529
- scheduleWordIndexPersist(dispatchCwd, index, dbg);
530
- },
531
- }, {
532
- biomeClient: biomeClient,
533
- ruffClient: ruffClient,
534
- metricsClient: metricsClient,
535
- getFormatService,
536
- fixedThisTurn: runtime.fixedThisTurn,
537
- });
538
- const pipelineTelemetry = {
539
- promise: pipelinePromise,
540
- participantIds: [...new Set(args.participantIds)].slice(0, 100),
541
- participantTotal: args.participantTotal,
542
- };
543
- // Synchronous, and the FIRST thing after `runPipeline` handed back its
544
- // promise: `claimPipelineDispatch` at each call site is only atomic because
545
- // nothing awaits between the claim and this registration.
546
- const registeredPipelines = registerInFlightPipeline(filePath, initialStateHash, pipelineTelemetry);
547
- let result;
548
- try {
549
- result = await pipelinePromise;
550
- }
551
- catch (pipelineErr) {
552
- if (getFlag("lens-guard")) {
553
- runtime.markGitGuardCacheUnknown("pipeline_crash");
554
- }
555
- dbg(`runPipeline crashed: ${pipelineErr}`);
556
- logReadGuardEvent({
557
- event: "edit_post_edit_pipeline_failed",
558
- correlationId: readGuardCorrelationId,
559
- filePath,
560
- metadata: {
561
- tool: event.toolName,
562
- commitStatus: "committed",
563
- reasonCode: "pipeline_failed",
564
- },
565
- });
566
- logReadGuardEvent({
567
- event: "edit_batch_summary",
568
- correlationId: readGuardCorrelationId,
569
- filePath,
570
- metadata: {
571
- tool: event.toolName,
572
- editBatchSummary: createReadGuardEditBatchSummary({
573
- requestedIndexes: requestedEditIndexes,
574
- requestedTotal: requestedEditTotal,
575
- resolvedIndexes: requestedEditIndexes,
576
- resolvedTotal: requestedEditTotal,
577
- appliedIndexes: requestedEditIndexes,
578
- appliedTotal: requestedEditTotal,
579
- participantIds: pipelineTelemetry.participantIds,
580
- participantTotal: pipelineTelemetry.participantTotal,
581
- commitStatus: "committed",
582
- postEditStatus: "failed",
583
- terminalStatus: "failed",
584
- durationMs: Date.now() - toolResultStart,
585
- }),
586
- },
587
- });
588
- dbg(`runPipeline crash stack: ${pipelineErr.stack}`);
589
- // The LSP fleet is process-wide, but a pipeline crash belongs to one
590
- // evaluation. A registered primary owns the fleet; a known secondary
591
- // must not tear it down. Keep the historical reset when no registration
592
- // exists because synthetic callers and early startup have no role evidence.
593
- const activePrimarySessionId = getActiveSessionId();
594
- const crashBelongsToPrimary = activePrimarySessionId === undefined ||
595
- activePrimarySessionId === runtime.telemetrySessionId;
596
- if (!getFlag("no-lsp") && crashBelongsToPrimary) {
597
- resetLSPService({ fast: true, reason: "pipeline_crash" });
598
- }
599
- logLatency({
600
- type: "tool_result",
601
- toolName: event.toolName,
602
- filePath,
603
- durationMs: Date.now() - toolResultStart,
604
- result: "pipeline_crash",
605
- });
606
- const notice = runtime.formatPipelineCrashNotice(filePath, pipelineErr);
607
- return {
608
- crashed: true,
609
- response: {
610
- content: notice
611
- ? [...event.content, { type: "text", text: notice }]
612
- : event.content,
613
- isError: true,
614
- },
615
- };
616
- }
617
- finally {
618
- releaseInFlightPipeline(filePath, initialStateHash, registeredPipelines);
619
- }
620
- if (!isPartialApplyResult) {
621
- const postEditStatus = result.isError ? "failed" : "succeeded";
622
- if (result.isError) {
623
- logReadGuardEvent({
624
- event: "edit_post_edit_pipeline_failed",
625
- correlationId: readGuardCorrelationId,
626
- filePath,
627
- metadata: {
628
- tool: event.toolName,
629
- commitStatus: "committed",
630
- reasonCode: "pipeline_failed",
631
- },
632
- });
633
- }
634
- logReadGuardEvent({
635
- event: "edit_batch_summary",
636
- correlationId: readGuardCorrelationId,
637
- filePath,
638
- metadata: {
639
- tool: event.toolName,
640
- editBatchSummary: createReadGuardEditBatchSummary({
641
- requestedIndexes: requestedEditIndexes,
642
- requestedTotal: requestedEditTotal,
643
- resolvedIndexes: requestedEditIndexes,
644
- resolvedTotal: requestedEditTotal,
645
- appliedIndexes: requestedEditIndexes,
646
- appliedTotal: requestedEditTotal,
647
- participantIds: pipelineTelemetry.participantIds,
648
- participantTotal: pipelineTelemetry.participantTotal,
649
- commitStatus: "committed",
650
- postEditStatus,
651
- terminalStatus: postEditStatus === "failed" ? "failed" : "success",
652
- durationMs: Date.now() - toolResultStart,
653
- }),
654
- },
655
- });
656
- }
657
- // ── Post-pipeline post-conditions (#2464 review round 2, S1) ───────────────
658
- // These live INSIDE the helper rather than at its call sites so EVERY
659
- // provenance gets them by construction. The observed path used to discard
660
- // `result` entirely, so under `--immediate-format` the pipeline rewrote the
661
- // file and none of the three below ran: the next edit was then blocked with
662
- // a spurious `file_modified` (the read-guard staleness stamp was never
663
- // re-taken), an identical retry escalated through the oldText-not-found
664
- // ladder (the #2402 after-write hash was never stamped), and a duplicate
665
- // tool_result for the same bytes analysed the file a second time (the
666
- // already-analysed latch was never set).
667
- // The latch identifies the bytes this pipeline actually analysed. A pipeline
668
- // that reports no write analysed its input state, even if another writer
669
- // changed disk while the await was parked. A pipeline-reported write selects
670
- // only the identity captured by runPipeline before analysis awaits (#2499).
671
- const pipelineOwnedWriteHash = result.fileModified
672
- ? result.postWriteStateHash
673
- : undefined;
674
- const finalStateHash = pipelineOwnedWriteHash ?? initialStateHash;
675
- if (!result.fileModified || pipelineOwnedWriteHash !== undefined) {
676
- lastAnalyzedStateByFile.set(filePath, {
677
- turnIndex: runtime.turnIndex,
678
- stateHash: finalStateHash,
679
- });
680
- }
681
- // #2402: pi-lens' own immediate format/autofix may have rewritten the file
682
- // after the native edit was recorded by the caller. Stamp the post-pipeline
683
- // state so an identical retry against the formatted bytes is still
684
- // recognized as already-applied. Only the pairs recorded this invocation are
685
- // stamped, and only when the pipeline actually changed the bytes.
686
- // `initialStateHash` IS the post-write hash at both call sites — the
687
- // classified chain passes `postWriteStateHash` verbatim, the observed path
688
- // passes the same pre-settle digest.
689
- if (pipelineOwnedWriteHash !== undefined) {
690
- for (const pair of nativeAppliedPairs) {
691
- runtime.partialApplyRecords.noteAfterWriteHash(filePath, pair.oldText, pair.newText, finalStateHash);
692
- }
693
- }
694
- // The model's write/edit and pi-lens' own immediate format/autofix are now
695
- // reflected on disk. Refresh read-guard staleness stamps so a follow-up edit
696
- // is judged by read-range coverage, not by our own previous write.
697
- if (!getFlag("no-read-guard") && allowAutonomousWriters) {
698
- const changedForReadGuard = new Set([
699
- path.resolve(filePath),
700
- ...(result.changedFiles ?? []).map((changedFile) => path.resolve(changedFile)),
701
- ]);
702
- for (const changedFile of changedForReadGuard) {
703
- if (nodeFs.existsSync(changedFile)) {
704
- deps.readGuard?.recordWritten(changedFile);
705
- }
706
- }
707
- }
708
- return { crashed: false, result };
709
- }
710
- export async function handleToolResult(deps) {
711
- const { event, getFlag, dbg, runtime, cacheManager, agentBehaviorRecord, formatBehaviorWarnings, } = deps;
712
- const rawFilePath = event.input.path;
713
- const workspaceRoot = runtime.projectRoot || process.cwd();
714
- let bashAuthorshipConfirmed = deps._allowAutonomousWriters ??
715
- deps._readGuardAuthorship ??
716
- event.toolName !== "bash";
717
- // #1642: a gitignored worktree edit got re-attributed onto a
718
- // same-relative-path file in the parent checkout because this handler
719
- // used to always resolve a relative path against `workspaceRoot`
720
- // (`runtime.projectRoot`), with no idea the call actually ran under a
721
- // different cwd/worktree.
722
- //
723
- // Source-level correction (pi host audit, earendil-works/pi): tool_call's
724
- // own resolved path is NOT authoritative for what executed —
725
- // `agent-session.ts:914-919`'s extension-handler contract lets a LATER
726
- // `tool_call` handler mutate `event.input` in place with no
727
- // re-validation, and edit's `prepareArguments` rewrites args before the
728
- // event fires at all. `tool_result.input`, by contrast, is populated
729
- // from the EXECUTED args (`agent-session.ts:502-516`) — it is the
730
- // authoritative path source. So the correlation record's job is narrower
731
- // than "the path": it is the RESOLUTION BASIS (the cwd/worktree the call
732
- // actually ran under). Every tool_result resolves ITS OWN authoritative
733
- // `rawFilePath` against that basis, rather than trusting a call-time path
734
- // that a later handler may have superseded.
735
- const toolCallId = resolveToolCallCorrelationId(event);
736
- const attribution = toolCallId !== undefined
737
- ? runtime.takeToolCallAttribution(toolCallId)
738
- : undefined;
739
- let resolutionBasis;
740
- if (attribution) {
741
- resolutionBasis = attribution.originCwd;
742
- }
743
- else if (toolCallId !== undefined &&
744
- rawFilePath &&
745
- !path.isAbsolute(rawFilePath)) {
746
- // A real correlation id existed (the host DOES support one) but no
747
- // attribution was recorded under it — evicted, cleared because the
748
- // call was blocked before it could execute, or simply never seen by
749
- // `handleToolCall`. A RELATIVE path here is ambiguous: we have no
750
- // idea which cwd it is relative to, and guessing `workspaceRoot` is
751
- // exactly the #1642 collapse. Fail CLOSED instead of guessing — no
752
- // turn state, no deferred work — and log it so a real incident is
753
- // countable rather than silently mis-attributed.
754
- const guessedPath = path.resolve(workspaceRoot, rawFilePath);
755
- // Existence is not execution evidence: a same-named file can exist in
756
- // the workspace while the tool ran in another cwd. Without the recorded
757
- // call target and origin cwd there is no comparison to make, so retain the
758
- // full record and fail closed.
759
- dbg(`path_attribution_missing: no recorded resolution basis for toolCallId=${toolCallId}, refusing relative path ${rawFilePath} (would have guessed ${guessedPath})`);
760
- logLatency({
761
- type: "phase",
762
- toolName: event.toolName,
763
- filePath: guessedPath,
764
- phase: "path_attribution_missing",
765
- durationMs: 0,
766
- metadata: { toolCallId, rawFilePath, guessedPath },
767
- });
768
- return;
769
- }
770
- else {
771
- // Either an ABSOLUTE path (bash-synthetic writes always pass one —
772
- // unambiguous regardless of any basis, see the bash-write dispatch
773
- // below) or a host that supplies NO correlation id at all under any
774
- // known field name. The latter cannot be correlated by identity full
775
- // stop; this is the SAME exposure every host had before this fix,
776
- // not a regression introduced by it.
777
- resolutionBasis = workspaceRoot;
778
- }
779
- const filePath = rawFilePath
780
- ? path.isAbsolute(rawFilePath)
781
- ? rawFilePath
782
- : path.resolve(resolutionBasis, rawFilePath)
783
- : rawFilePath;
784
- if (filePath) {
785
- invalidateProjectIgnoreMatcherForPath(filePath);
786
- invalidateFormatterCacheForPath(filePath);
787
- }
788
- // Purely diagnostic: tool_call's call-time verdict (computed on ITS OWN
789
- // resolved path, which may since have been superseded) disagreed with
790
- // what actually executed. This does NOT gate anything by itself — the
791
- // ignore re-check below, running on the freshly & correctly resolved
792
- // `filePath`, is the real decision — but a divergence is exactly the
793
- // shape of the reported incident, so it is named legibly.
794
- if (attribution?.skipped &&
795
- filePath &&
796
- attribution.resolvedPath &&
797
- !pathsEqual(filePath, attribution.resolvedPath)) {
798
- const message = `path_attribution_refused: call target ${attribution.resolvedPath} (originCwd=${attribution.originCwd}) vs tool_result resolved ${filePath}`;
799
- dbg(message);
800
- logLatency({
801
- type: "phase",
802
- toolName: event.toolName,
803
- filePath,
804
- phase: "path_attribution_refused",
805
- durationMs: 0,
806
- metadata: {
807
- callTarget: attribution.resolvedPath,
808
- resolvedPath: filePath,
809
- originCwd: attribution.originCwd,
810
- },
811
- });
812
- }
813
- const behaviorWarnings = agentBehaviorRecord(event.toolName, filePath);
814
- const syntheticWriteContent = [];
815
- // #1590: one shared authoritative-content budget for every path this bash
816
- // command wrote. It is handed DOWN to each synthetic call so the single
817
- // attachment decision there sees both limits; nothing re-decides out here.
818
- const syntheticAttachmentBudget = {
819
- remaining: AUTHORITATIVE_CONTENT_MAX_BYTES,
820
- };
821
- // Bash writes (redirects, tee, sed -i, cp/mv, touch, git checkout/restore) —
822
- // these change file content but never go through the edit tool, so bash
823
- // early-returns before the dispatch pipeline below. For each in-project file
824
- // the command wrote/restored we therefore: (1) mark it authored-by-agent for
825
- // the read-guard (like the Write tool), and (2) re-run the pipeline via a
826
- // synthetic `write` event so its diagnostics, fileSeq, and change-log refresh.
827
- // Without (2) a `git checkout -- f` restore keeps serving the pre-restore
828
- // (e.g. broken-state) warnings on every later lens_diagnostics call.
829
- if (event.toolName === "bash" &&
830
- typeof event.input.command === "string") {
831
- const command = event.input.command;
832
- const recognized = extractWrittenPathsFromCommand(command, workspaceRoot);
833
- // The SURVIVING recognized set: what will actually dispatch. Failure
834
- // atomicity (#2000 invariant 5) means opaque recovery must subtract
835
- // THIS set, not raw recognized - otherwise a redirect target dropped
836
- // by the isError filter would be subtracted from recovery AND
837
- // excluded here, attributed nowhere.
838
- let recognizedWritten = event.isError !== true
839
- ? recognized.filter((wp) => !isExternalOrVendorFile(wp, workspaceRoot) &&
840
- !isPathIgnoredByProject(wp, workspaceRoot, false))
841
- : [];
842
- // Fence the mtime-based session-authored fallback before any async
843
- // observation. Only later content evidence may clear this fence.
844
- if (!getFlag("no-read-guard")) {
845
- for (const recognizedPath of recognizedWritten)
846
- deps.readGuard?.recordUnchanged?.(recognizedPath);
847
- }
848
- // #2000 phase 2: when the extractor recognizes NOTHING, the command is
849
- // opaque-candidate — recover its actual changed set by diffing the pre
850
- // snapshot taken at tool_call. Partial writes that landed before a
851
- // nonzero exit ARE attributed (the files changed and the agent authored
852
- // them) — a deliberate divergence from the isError filter above, which
853
- // exists for restore semantics where attribution would lie.
854
- let opaquePaths = [];
855
- let observedChangedKeys;
856
- let recognizedAuthored = [];
857
- // Recovery runs for EVERY bash command with a pending baseline - not
858
- // only recognized-empty ones. A mixed command (`python x.py > out.ts`
859
- // plus script-internal writes) previously skipped observation entirely
860
- // with zero telemetry; git-first recovery is cheap enough (~60ms) to
861
- // close that gap, subtracting already-recognized paths so nothing
862
- // double-dispatches.
863
- if (workspaceRoot && !getFlag("no-read-guard")) {
864
- const scanRoot = workspaceRoot;
865
- const started = Date.now();
866
- const pending = getOpaqueBaselineStore().take(`${normalizeMapKey(path.resolve(scanRoot))}:${runtime.sessionGeneration}`);
867
- let unknownReason;
868
- if (!pending && recognized.length > 0) {
869
- // Partial coverage without observation: the explicit verdict
870
- // invariant 1 demands (never silently imply no change).
871
- unknownReason = "partial-recognition-no-baseline";
872
- }
873
- else if (!pending) {
874
- unknownReason = "no-pending-snapshot";
875
- }
876
- else if (pending.strategy === "git") {
877
- // Git-first: no universe cap - works on any repo size.
878
- const recovery = await recoverOpaqueChangesViaGit(scanRoot, pending.startedAt, {
879
- excludeIndexOnlyWhenUnmerged: isFailedGitIntegrationCommand(command, event.isError),
880
- });
881
- if (recovery.verdict === "recovered") {
882
- opaquePaths = recovery.paths.filter((p) => !isExternalOrVendorFile(p, scanRoot) &&
883
- !isPathIgnoredByProject(p, scanRoot, false));
884
- observedChangedKeys = new Set(opaquePaths);
885
- }
886
- else if (recovery.verdict === "unknown") {
887
- // #2060: deliberately WIDER than the old `recognized.length > 0`
888
- // guard. A fully opaque command whose probe failed is the shape
889
- // whose coverage is least knowable, and it used to record
890
- // nothing at all.
891
- unknownReason = recovery.unknownReason;
892
- }
893
- else {
894
- // A clean git verdict is complete evidence that no path
895
- // changed; it is not missing evidence. Keep recognized writes
896
- // out of authorship because git found no changed bytes.
897
- observedChangedKeys = new Set();
898
- }
899
- // #2060: both counts are bounded (one record per tool_result, no
900
- // per-path logging) and exist because filtering is invisible in
901
- // production otherwise - the dropped paths simply never appear.
902
- if ((recovery.excludedIncomingCount ?? 0) > 0) {
903
- logLatency({
904
- type: "phase",
905
- phase: "opaque_mutation_incoming_excluded",
906
- filePath: command.slice(0, 80),
907
- durationMs: Date.now() - started,
908
- result: `excluded:${recovery.excludedIncomingCount}`,
909
- });
910
- }
911
- if ((recovery.unknownStatusCount ?? 0) > 0) {
912
- logLatency({
913
- type: "phase",
914
- phase: "opaque_mutation_status_pair_unknown",
915
- filePath: command.slice(0, 80),
916
- durationMs: Date.now() - started,
917
- result: `kept:${recovery.unknownStatusCount}`,
918
- });
919
- }
920
- }
921
- else if (pending.stats) {
922
- const outcome = await captureFileStats(scanRoot, {
923
- withHashes: true,
924
- ...deps._opaqueCaptureOptions,
925
- });
926
- if (outcome.snapshot && !outcome.unknownReason) {
927
- opaquePaths = diffFileContent(pending.stats, outcome.snapshot);
928
- observedChangedKeys = new Set(opaquePaths);
929
- }
930
- else {
931
- unknownReason =
932
- outcome.unknownReason ??
933
- pending.statsUnknownReason ??
934
- "walk-failed";
935
- }
936
- }
937
- else {
938
- unknownReason = pending.statsUnknownReason ?? "walk-failed";
939
- }
940
- if (opaquePaths.length > 0 && recognizedWritten.length > 0) {
941
- const survivingKeys = new Set(recognizedWritten.map((p) => normalizeMapKey(path.resolve(p))));
942
- opaquePaths = opaquePaths.filter((p) => !survivingKeys.has(p));
943
- }
944
- if (observedChangedKeys) {
945
- recognizedAuthored = recognizedWritten.filter((file) => observedChangedKeys.has(normalizeMapKey(path.resolve(file))));
946
- if (recognizedAuthored.length === 0)
947
- recognizedWritten = [];
948
- }
949
- else if (unknownReason) {
950
- recognizedAuthored = [];
951
- // The bounded opaque_mutation_coverage_unknown record below remains
952
- // the production proof that authorship evidence was unavailable.
953
- }
954
- if (unknownReason) {
955
- logLatency({
956
- type: "phase",
957
- phase: "opaque_mutation_coverage_unknown",
958
- filePath: command.slice(0, 80),
959
- durationMs: Date.now() - started,
960
- result: unknownReason,
961
- });
962
- }
963
- if (opaquePaths.length > 0) {
964
- logLatency({
965
- type: "phase",
966
- phase: "opaque_mutation_recovered",
967
- filePath: opaquePaths.slice(0, 5).join(","),
968
- durationMs: Date.now() - started,
969
- result: `changed:${opaquePaths.length}`,
970
- });
971
- void resyncGitChangedFiles(opaquePaths).catch((err) => {
972
- dbg(`git-change LSP resync failed: ${err}`);
973
- });
974
- }
975
- }
976
- // wp iterates opaquePaths VERBATIM (already normalizeMapKey keys), so the
977
- // set must hold those exact strings - no re-resolution.
978
- const opaqueSet = new Set(opaquePaths);
979
- const written = [...recognizedWritten, ...opaquePaths];
980
- const recognizedAuthoredSet = new Set(recognizedAuthored);
981
- bashAuthorshipConfirmed = recognizedAuthored.length > 0;
982
- for (const wp of written) {
983
- if (!getFlag("no-read-guard") && recognizedAuthoredSet.has(wp))
984
- deps.readGuard?.recordWritten(wp);
985
- else if (!getFlag("no-read-guard") && recognizedWritten.includes(wp))
986
- deps.readGuard?.recordUnchanged?.(wp);
987
- const receipt = runtime
988
- .recordMutationToolReceipt;
989
- const autofixMode = receipt
990
- ? receipt.call(runtime, wp, "write").autofixMode
991
- : "immediate";
992
- // Recovered opaque writes carry their own source so the change log
993
- // distinguishes them from parsed writes (auditable in production).
994
- const isOpaque = opaqueSet.has(wp);
995
- // Failure atomicity: an opaque-recovered file VERIFIABLY exists on
996
- // disk, so its synthetic event must not inherit isError - the main
997
- // path early-returns on failed host results before attribution,
998
- // which would silently drop exactly the partial writes invariant 5
999
- // says to attribute.
1000
- const syntheticEvent = {
1001
- ...event,
1002
- toolName: "write",
1003
- input: { path: wp },
1004
- isError: false,
1005
- // #2423: pi-lens SYNTHESIZED this write from a bash command, so the
1006
- // seam reports `provenance: "bash-derived"` and a consumer can tell
1007
- // it apart from the host's own write tool.
1008
- [PI_LENS_SYNTHETIC_MUTATION_FIELD]: "bash",
1009
- };
1010
- const syntheticResult = await handleToolResult({
1011
- ...deps,
1012
- event: syntheticEvent,
1013
- _bypassDebounce: true,
1014
- _autofixMode: autofixMode,
1015
- _attachmentBudget: syntheticAttachmentBudget,
1016
- _mutationSourceOverride: isOpaque ? "opaque-script" : undefined,
1017
- _readGuardAuthorship: recognizedAuthoredSet.has(wp),
1018
- // Opaque recovery is mutation evidence only. The synthetic call still
1019
- // records freshness and runs diagnostics, but it cannot format/autofix
1020
- // or issue an edit-directed blocker/actionable instruction.
1021
- _allowAutonomousWriters: recognizedAuthoredSet.has(wp),
1022
- });
1023
- if (syntheticResult) {
1024
- // #1590: forward verbatim. The synthetic call already charged the
1025
- // shared budget above and phrased its own notice from the decision
1026
- // it made, so a second verdict out here could only contradict it —
1027
- // which is exactly the defect this shape produced before.
1028
- syntheticWriteContent.push(...syntheticResult.content.slice(event.content.length));
1029
- }
1030
- }
1031
- if (event.isError !== true && !getFlag("no-read-guard")) {
1032
- const truncation = event.details?.truncation;
1033
- const parsedSpans = extractReadPathsFromCommand(command, workspaceRoot);
1034
- let spans = parsedSpans;
1035
- if (truncation?.truncated === true &&
1036
- typeof truncation.outputLines === "number") {
1037
- if (parsedSpans.length === 1) {
1038
- const span = parsedSpans[0];
1039
- if (span) {
1040
- // countFileLines intentionally preserves the split-based guard
1041
- // convention, where a trailing newline contributes an empty final
1042
- // element. The host's output line count does not include that
1043
- // element, so remove it from the span basis before taking the tail.
1044
- const hasTrailingNewline = nodeFs
1045
- .readFileSync(span.filePath, "utf8")
1046
- .endsWith("\n");
1047
- const spanLineCount = hasTrailingNewline
1048
- ? Math.max(1, span.limit - 1)
1049
- : span.limit;
1050
- const shown = Math.min(truncation.outputLines, spanLineCount);
1051
- spans =
1052
- shown > 0
1053
- ? [
1054
- {
1055
- ...span,
1056
- offset: span.offset + spanLineCount - shown,
1057
- limit: shown,
1058
- },
1059
- ]
1060
- : [];
1061
- }
1062
- }
1063
- else if (parsedSpans.length > 1) {
1064
- recordDegradationOnce({
1065
- kind: "bash-view-clipped",
1066
- subject: "multi-span",
1067
- reason: "truncated bash view contained multiple spans",
1068
- });
1069
- spans = [];
1070
- }
1071
- if (parsedSpans.length === 1 &&
1072
- spans.length === 1 &&
1073
- (spans[0]?.offset !== parsedSpans[0]?.offset ||
1074
- spans[0]?.limit !== parsedSpans[0]?.limit)) {
1075
- recordDegradationOnce({
1076
- kind: "bash-view-clipped",
1077
- subject: parsedSpans[0]?.filePath ?? "unknown",
1078
- reason: "truncated bash view narrowed a single span",
1079
- });
1080
- }
1081
- }
1082
- for (const span of spans) {
1083
- if (isExternalOrVendorFile(span.filePath, workspaceRoot))
1084
- continue;
1085
- if (isPathIgnoredByProject(span.filePath, workspaceRoot, false))
1086
- continue;
1087
- deps.readGuard?.recordRead({
1088
- filePath: span.filePath,
1089
- requestedOffset: span.offset,
1090
- requestedLimit: span.limit,
1091
- effectiveOffset: span.offset,
1092
- effectiveLimit: span.limit,
1093
- expandedByLsp: false,
1094
- turnIndex: runtime.turnIndex,
1095
- writeIndex: runtime.peekWriteIndex(),
1096
- timestamp: Date.now(),
1097
- });
1098
- }
1099
- }
1100
- // #1668: bash-deleted files never go through the edit tool, so nothing
1101
- // else tells an LSP server one of its watched files is gone — the ONLY
1102
- // existing enqueue site fires on first open and can only emit type 1/2.
1103
- // Extract the command's likely delete targets, confirm each by existence
1104
- // (never scan the workspace — only the paths the command named), and only
1105
- // act on paths pi-lens already knows about (a read or a write this
1106
- // session) so an `rm` on something pi-lens never touched is not treated
1107
- // as a signal. Each match is routed to already-active LSP clients as a
1108
- // type-3 watched-files event through the same #271 coalescing queue a
1109
- // burst of deletes still flushes as one notification per server.
1110
- if (event.isError !== true &&
1111
- !getFlag("no-lsp") &&
1112
- !getFlag("no-read-guard")) {
1113
- for (const dp of extractDeletedPathsFromCommand(command, workspaceRoot)) {
1114
- if (isExternalOrVendorFile(dp, workspaceRoot))
1115
- continue;
1116
- if (isPathIgnoredByProject(dp, workspaceRoot, false))
1117
- continue;
1118
- if (!deps.readGuard || !deps.readGuard.hasKnownPath(dp))
1119
- continue;
1120
- // #1668 review F4: this is the ONLY gate standing between a merely
1121
- // NAMED path and an actual confirmed delete — extractDeletedPathsFromCommand
1122
- // only proposes candidates from parsing the command text, so it can't
1123
- // tell `git rm --cached f` (index-only, file still on disk) from a
1124
- // real delete, can't see a short-circuited `rm f && false` that never
1125
- // ran, and can't resolve a relative path run from a `cd`-ed subdirectory
1126
- // against the wrong cwd. Every one of those is caught here, and only
1127
- // here — do not remove or reorder this check relative to the loop body.
1128
- if (nodeFs.existsSync(dp))
1129
- continue; // still there — not a real delete
1130
- deps.readGuard.forgetPath(dp);
1131
- void notifyExternalFileChange(dp, 3).catch((err) => {
1132
- dbg(`tool_result: external-delete notify failed for ${dp}: ${err}`);
1133
- });
1134
- }
1135
- }
1136
- }
1137
- // Search tools reveal specific lines (file:line) the agent then edits — register
1138
- // those shown lines (± context) as reads so the follow-up edit isn't blocked (#169).
1139
- // Our tools attach locations as `details.searchReads`; bash grep is parsed from
1140
- // `grep -n` output. Only shown lines are registered, never the whole file.
1141
- if (deps.readGuard && event.isError !== true && !getFlag("no-read-guard")) {
1142
- const searchReads = [];
1143
- const detailSearchReads = event.details?.searchReads;
1144
- if (Array.isArray(detailSearchReads))
1145
- searchReads.push(...detailSearchReads);
1146
- if (event.toolName === "bash" &&
1147
- typeof event.input.command === "string") {
1148
- const command = event.input.command;
1149
- const output = event.content
1150
- .map((part) => (typeof part.text === "string" ? part.text : ""))
1151
- .join("\n");
1152
- searchReads.push(...extractGrepSearchReadsFromOutput(command, workspaceRoot, output));
1153
- }
1154
- if (searchReads.length > 0) {
1155
- registerSearchReads(deps.readGuard, searchReads, {
1156
- projectRoot: workspaceRoot,
1157
- turnIndex: runtime.turnIndex,
1158
- writeIndex: runtime.peekWriteIndex(),
1159
- });
1160
- }
1161
- }
1162
- // Native read results are the authoritative read boundary. The tool_call
1163
- // input can request past EOF, and the host can cap bytes or lines before the
1164
- // result reaches the model. Register only the delivered range (#2802).
1165
- if (deps.readGuard &&
1166
- event.toolName === "read" &&
1167
- event.isError !== true &&
1168
- filePath &&
1169
- !getFlag("no-read-guard") &&
1170
- !isExternalOrVendorFile(filePath, workspaceRoot)) {
1171
- const deliveredFilePath = attribution?.resolvedPath && nodeFs.existsSync(attribution.resolvedPath)
1172
- ? attribution.resolvedPath
1173
- : filePath;
1174
- if (nodeFs.existsSync(deliveredFilePath)) {
1175
- const nativeReadToolCallId = resolveToolCallCorrelationId(event);
1176
- const input = event.input;
1177
- const requestedOffset = input.offset ?? 1;
1178
- const requestedLimit = input.limit;
1179
- const truncation = event.details?.truncation;
1180
- const available = Math.max(0, countFileLines(deliveredFilePath) - requestedOffset + 1);
1181
- const deliveredLimit = Math.min(available, truncation?.outputLines ?? requestedLimit ?? available);
1182
- if (deliveredLimit > 0) {
1183
- if (truncation?.truncated === true && deliveredLimit < available) {
1184
- recordDegradationOnce({
1185
- kind: "native-read-clipped",
1186
- subject: deliveredFilePath,
1187
- reason: "native read result was clipped before delivery",
1188
- });
1189
- }
1190
- logReadGuardEvent({
1191
- event: "read_pattern",
1192
- sessionId: runtime.telemetrySessionId,
1193
- filePath: deliveredFilePath,
1194
- requestedOffset,
1195
- requestedLimit: requestedLimit ?? deliveredLimit,
1196
- effectiveOffset: requestedOffset,
1197
- effectiveLimit: deliveredLimit,
1198
- metadata: {
1199
- totalLines: countFileLines(deliveredFilePath),
1200
- isPartial: deliveredLimit < available,
1201
- fileKind: detectFileKind(deliveredFilePath) ?? "unknown",
1202
- fractionRead: available > 0
1203
- ? Math.round((deliveredLimit / available) * 100) / 100
1204
- : 1,
1205
- expandedByTs: false,
1206
- },
1207
- });
1208
- const deliveredRecord = {
1209
- filePath: deliveredFilePath,
1210
- requestedOffset,
1211
- requestedLimit: requestedLimit ?? deliveredLimit,
1212
- effectiveOffset: requestedOffset,
1213
- effectiveLimit: deliveredLimit,
1214
- expandedByLsp: false,
1215
- turnIndex: runtime.turnIndex,
1216
- writeIndex: runtime.peekWriteIndex(),
1217
- timestamp: Date.now(),
1218
- };
1219
- if (nativeReadToolCallId) {
1220
- deps.readGuard.recordRead(deliveredRecord, {
1221
- supersedes: { toolCallId: nativeReadToolCallId },
1222
- });
1223
- }
1224
- else {
1225
- deps.readGuard.recordRead(deliveredRecord);
1226
- }
1227
- }
1228
- }
1229
- }
1230
- // #2423: THE inbound gate. Everything below this line is the mutation
1231
- // bookkeeping chain — read-guard staleness stamp, turn state, change-log
1232
- // receipt, deferred autofix and format. Before the seam this compared
1233
- // `event.toolName` to two literals, so a host or extension edit tool under
1234
- // any other name was dropped here with the path already resolved.
1235
- // `recognizeOnly` (#2423 review round 1, finding F5): the tool_call side
1236
- // already ran the adapters against the PRE-edit file and logged what they
1237
- // resolved. Re-running them here logged a second `touched_lines_detected`
1238
- // for every edit and an `edit_preflight_blocked` for edits that were never
1239
- // blocked, and any anchor it re-resolved would be resolved against content
1240
- // the edit has already rewritten. The seam carries the tool_call ranges
1241
- // forward by `toolCallId` instead.
1242
- const mutation = classifyMutatingTool(event, {
1243
- filePath: filePath || undefined,
1244
- sessionId: deps.sessionId,
1245
- recognizeOnly: true,
1246
- });
1247
- // #2430: settle the observational baseline BEFORE the classification gate
1248
- // returns. On the FIRST call of an unknown tool nothing below this line will
1249
- // run — that is the bug — so the disk diff is the only thing that can put
1250
- // the file in `turn-state.json`, and it replays through the mutation bridge
1251
- // to get the identical bookkeeping a `write` gets.
1252
- //
1253
- // The PROBE is synchronous and is the first thing asked, so the
1254
- // overwhelmingly common call — no baseline armed — pays one map lookup and
1255
- // nothing else (#2449 round 2, F1).
1256
- //
1257
- // The SETTLE is async (#2449 round 3, T4: no synchronous filesystem work on
1258
- // this path), so it yields. `handleToolResult` has no other `await` before
1259
- // it registers with `debouncedPipelines`/`inFlightPipelines`, and
1260
- // `tests/clients/runtime-tool-result-debounce.test.ts` asserts that a
1261
- // racing second tool_result for the same path cannot miss the first's
1262
- // entry — so everything the chain below derives from the file's POST-RESULT
1263
- // bytes is read HERE, before the yield. Otherwise the racing call rewrites
1264
- // the file while this one is awaiting and this one registers under the
1265
- // OTHER call's state hash, collapsing two distinct pipelines into one.
1266
- const observationPending = !getFlag("no-read-guard") &&
1267
- hasPendingObservation(resolveToolCallCorrelationId(event));
1268
- // #2464 review round 2 (S2): NOT gated on `mutation !== undefined` any more.
1269
- // The observed path now dispatches on call ONE of an unknown tool too, and
1270
- // that call is by definition unclassified — gating the pre-yield digest on a
1271
- // classification that does not exist yet would have left exactly the racing
1272
- // re-read this hoist exists to prevent.
1273
- const preSettleStateHash = observationPending && filePath ? getFileStateHash(filePath) : undefined;
1274
- let observedReplayed = 0;
1275
- let observedChangedPaths = [];
1276
- if (observationPending) {
1277
- const observed = await settleObservedMutation({
1278
- toolCallId: resolveToolCallCorrelationId(event),
1279
- toolName: event.toolName,
1280
- sessionGeneration: runtime.sessionGeneration,
1281
- turnIndex: runtime.turnIndex,
1282
- signal: getAmbientAbortSignal(),
1283
- record: replayThroughMutationBridge,
1284
- getStoredLineHashes: (candidate) => storedLineHashesFor(deps.readGuard, candidate),
1285
- isRecordable: (candidate) => !isExternalOrVendorFile(candidate, workspaceRoot) &&
1286
- !isPathIgnoredByProject(candidate, workspaceRoot, false),
1287
- dbg,
1288
- });
1289
- observedReplayed = observed.replayed;
1290
- observedChangedPaths = observed.changedPaths;
1291
- if (observed.replayed > 0) {
1292
- dbg(`tool_result: observed ${observed.replayed} mutation(s) from tool "${event.toolName}"`);
1293
- }
1294
- else if (observed.reason) {
1295
- dbg(`tool_result: observation for "${event.toolName}" did not settle: ${observed.reason}`);
1296
- }
1297
- }
1298
- // #2464 review round 2 (S5): ONE clock, started above BOTH exits, so
1299
- // `edit_batch_summary.durationMs` and the `tool_result` latency row measure
1300
- // the same span whichever provenance a tool takes. The observed path used to
1301
- // start its clock at the dispatch call itself, so its durations were
1302
- // pipeline-only and silently incomparable with the classified path's.
1303
- // Deliberately below the settle: neither path should be charged for the
1304
- // observational disk diff, which is arm-time work, not tool_result work.
1305
- const toolResultStart = Date.now();
1306
- // #2449 review round 3 (S2), narrowed in round 4 (S4). A tool learned from
1307
- // ONE observation is classified by NAME from here on AND is still armed —
1308
- // that second property is what makes a second observation, and therefore
1309
- // persistence, reachable at all (round 2, F2). Both halves then recorded the
1310
- // same physical edit: the settle above replayed it through the mutation
1311
- // bridge with measured ranges, and the chain below recorded it AGAIN as a
1312
- // whole-file change, so a three-edit session produced four change-log
1313
- // receipts.
1314
- //
1315
- // The settle wins, deliberately. It ran the disk diff, so it knows which
1316
- // LINES moved; the chain, reached through `recognizeOnly`, has no ranges for
1317
- // an unknown tool and over-approximates to the file. Skipping the arm
1318
- // instead would be the other way to fix this, and it is the wrong one — it
1319
- // makes PERSIST_AFTER_OBSERVATIONS unreachable again.
1320
- //
1321
- // ## What this return skips, stated in full (round 4, S4; #2464)
1322
- //
1323
- // The first cut called this "skipping turn tracking" and returned. It skipped
1324
- // considerably more than turn tracking, and THREE of those steps have no
1325
- // counterpart in `recordMutationThroughSeam`, so nothing else ran them. Those
1326
- // three run here, before the return:
1327
- //
1328
- // - the #2402 applied-edit records — without them an identical retry of
1329
- // the observed tool's edit escalates through the oldText-not-found ladder
1330
- // instead of being recognized as already applied;
1331
- // - `recordMutationToolReceipt`, the write→edit sticky turn transition,
1332
- // which is pure ordering state the bridge never touches;
1333
- // - the `cachedExports` refresh — without it the pre-write STOP check keeps
1334
- // firing on names this very edit removed.
1335
- //
1336
- // What stays skipped is skipped because the BRIDGE already did it: the
1337
- // read-guard staleness stamp, the `turn-state.json` modified ranges, the
1338
- // attributed change-log receipt, and the deferred autofix/format pair —
1339
- // `recordMutationThroughSeam` steps 1-4. #2464 pulled the pipeline's own
1340
- // lint/diagnostics dispatch (`dispatchPipelineAnalysis`, defined above) out
1341
- // of the block below that also writes those same turn-state ranges and the
1342
- // change-log receipt, so it can be called HERE too — analysis without asking
1343
- // for the recording a second time.
1344
- //
1345
- // ## Why this sits ABOVE the classification gates (#2464 review round 2, S2)
1346
- //
1347
- // It used to sit BELOW `mutation === undefined`, which meant CALL ONE of every
1348
- // unknown tool — the call the observational net exists for — was recorded by
1349
- // the bridge and then returned unanalysed: `runPipeline` was never reached, so
1350
- // the file was fixed and formatted by the `agent_settled` drain but never
1351
- // linted, and AC2 ("an observed mutation gets its pipeline analysis in the
1352
- // same turn") was met on the second call only. `observedReplayed > 0` is the
1353
- // whole condition now: the bridge recorded this edit, whoever the tool is.
1354
- if (observedReplayed > 0) {
1355
- // ## The `hostToolResultFailed` asymmetry, stated rather than hidden
1356
- //
1357
- // The classified chain returns below on `event.isError === true` with a
1358
- // `commitStatus: "failed"` receipt; this block does not consult it, so an
1359
- // unknown tool that reports failure and STILL moved bytes is recorded,
1360
- // analysed, and receipted as `committed`. That is deliberate: the
1361
- // observation is disk evidence, not a claim — the bytes changed whatever
1362
- // the tool says about itself — and the classified early return is safe
1363
- // only because a failed host edit did not write. Reading a third-party
1364
- // tool's self-reported status as authority over what is on disk is the
1365
- // exact gap the observational net exists to close.
1366
- //
1367
- // The gates below (`mutation === undefined` / `!filePath` /
1368
- // `isExternalOrVendorFile`) are deliberately NOT consulted for the SKIP:
1369
- // once the bridge has recorded the edit, re-running the classified chain
1370
- // double-records it regardless of how the tool classifies. They are
1371
- // consulted for what this block can still usefully DO.
1372
- if (filePath && !isExternalOrVendorFile(filePath, workspaceRoot)) {
1373
- // On call ONE the tool is not classified at all, so there is no
1374
- // `mutation.kind` to read. The observation itself is the authority and
1375
- // it only ever records "edit" (`settleObservedMutation` hard-codes
1376
- // `kind: "edit"`, and #2430 tier 4 only ever classifies a learned tool
1377
- // as "edit"), so the two agree wherever both exist.
1378
- const observedKind = mutation?.kind ?? "edit";
1379
- const observedStateHash = preSettleStateHash ?? getFileStateHash(filePath);
1380
- const observedAppliedPairs = recordNativeAppliedPairs({
1381
- runtime,
1382
- input: event.input,
1383
- kind: observedKind,
1384
- filePath,
1385
- stateHash: observedStateHash,
1386
- });
1387
- const receiptOutcome = runtime.recordMutationToolReceipt?.call(runtime, filePath, observedKind);
1388
- refreshCachedExports(runtime, filePath);
1389
- // Same fallback formula the classified chain uses below, minus its
1390
- // `_bypassDebounce` branch (#2464 review round 2, S3): that branch was
1391
- // unreachable here. Both callers that set `_bypassDebounce` arrive with
1392
- // no pending baseline — `scheduleDebounced`'s re-entry because THIS
1393
- // call already consumed it at the settle above, and the bash-derived
1394
- // synthetic write because `runtime-tool-call.ts` excludes `bash` from
1395
- // arming outright (`toolName !== "bash"`). `observedKind` is always
1396
- // "edit", so the un-receipted default is "deferred" either way.
1397
- const observedAutofixMode = receiptOutcome?.autofixMode ??
1398
- (observedKind === "edit" ? "deferred" : "immediate");
1399
- // Analyse the files the observation actually RECORDED, not merely the
1400
- // path the tool named. A directory is never a pipeline target.
1401
- const observedDispatchPaths = observedChangedPaths
1402
- .filter((candidate) => {
1403
- try {
1404
- return !nodeFs.statSync(candidate).isDirectory();
1405
- }
1406
- catch {
1407
- return false;
1408
- }
1409
- })
1410
- .slice(0, OBSERVED_DISPATCH_MAX_PATHS);
1411
- const observedDispatchDropped = observedChangedPaths.length - observedDispatchPaths.length;
1412
- if (observedDispatchDropped > 0) {
1413
- incrementDegradationCount({
1414
- kind: "observed-mutation-dispatch-cap",
1415
- subject: event.toolName,
1416
- reason: `observed mutation dispatch capped at ${OBSERVED_DISPATCH_MAX_PATHS}; ${observedDispatchDropped} path(s) not dispatched`,
1417
- });
1418
- }
1419
- if (observedDispatchPaths.length > 0) {
1420
- const observedClients = ensureToolResultClients(deps);
1421
- if (observedClients !== true &&
1422
- !(await bounded(Promise.resolve(observedClients), {
1423
- ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
1424
- signal: deps.signal ?? undefined,
1425
- hook: "tool_result_edit",
1426
- label: "observed-tool-result-analysis",
1427
- })))
1428
- return;
1429
- const observedReadGuardCorrelationId = getReadGuardCorrelationId(event);
1430
- // #2464 review round 3 (F1): the SAME two pre-conditions the
1431
- // classified site consults, through the same shared claim. Round 2
1432
- // dispatched here with neither, so two concurrent observed
1433
- // `tool_result`s for one file+hash both registered and both ran
1434
- // `runPipeline` — two autofix/format writers racing on one file — the
1435
- // second overwrote the first's registry entry, and the first's
1436
- // release then evicted the outer entry a live, unrelated classified
1437
- // pipeline had since re-created under it.
1438
- for (const observedPath of observedDispatchPaths) {
1439
- const observedDispatchSignal = deps.signal;
1440
- const observedJoinSignal = deps.signal;
1441
- const observedStateHashForPath = getFileStateHash(observedPath);
1442
- const observedClaim = claimPipelineDispatch({
1443
- filePath: observedPath,
1444
- stateHash: observedStateHashForPath,
1445
- turnIndex: runtime.turnIndex,
1446
- participantId: observedReadGuardCorrelationId,
1447
- dbg,
1448
- });
1449
- if (!observedClaim.proceed) {
1450
- if (observedClaim.joined) {
1451
- await bounded(observedClaim.joined, {
1452
- ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
1453
- signal: observedJoinSignal,
1454
- hook: "tool_result_edit",
1455
- label: "observed-tool-result-join",
1456
- });
1457
- }
1458
- continue;
1459
- }
1460
- const observedDispatchOutcome = await bounded(dispatchPipelineAnalysis({
1461
- deps,
1462
- runtime,
1463
- filePath: observedPath,
1464
- dispatchCwd: resolveLanguageRootForFile(observedPath, workspaceRoot),
1465
- turnStateCwd: path.resolve(workspaceRoot),
1466
- autofixMode: observedAutofixMode,
1467
- modifiedRanges: undefined,
1468
- writeIndex: runtime.nextWriteIndex(),
1469
- initialStateHash: observedStateHashForPath,
1470
- readGuardCorrelationId: observedReadGuardCorrelationId,
1471
- requestedEditIndexes: getRequestedEditIndexes(event, observedKind),
1472
- requestedEditTotal: getRequestedEditCount(event, observedKind),
1473
- isPartialApplyResult: (event.details ?? {})
1474
- .piLensPartialApply === true,
1475
- participantIds: [observedReadGuardCorrelationId],
1476
- participantTotal: 1,
1477
- toolResultStart,
1478
- nativeAppliedPairs: observedAppliedPairs,
1479
- // #2802 authorship rule (master): the observational
1480
- // settle already recorded this edit through the
1481
- // bridge, so the dispatch's read-guard write refresh
1482
- // carries evidence and stays enabled on every
1483
- // per-path dispatch.
1484
- allowAutonomousWriters: true,
1485
- }), {
1486
- ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
1487
- signal: observedDispatchSignal,
1488
- hook: "tool_result_edit",
1489
- label: "observed-tool-result-analysis",
1490
- });
1491
- if (observedDispatchOutcome?.crashed) {
1492
- // #2464 review round 2, S6: parity with the classified chain — a
1493
- // pipeline crash surfaces its notice to the agent instead of being
1494
- // swallowed into a dbg line the model never sees. The recorded
1495
- // edit stands either way; only the analysis was lost.
1496
- dbg(`tool_result: pipeline analysis crashed for the observed mutation on ${observedPath}; the recorded edit stands, analysis did not run this turn`);
1497
- return observedDispatchOutcome.response;
1498
- }
1499
- }
1500
- dbg(`tool_result: the observational settle already recorded ${observedReplayed} mutation(s) for "${event.toolName}"; kept the applied-edit records, mutation receipt, cachedExports refresh, and ran the pipeline dispatch (#2464); skipped the bridge-covered staleness stamp / turn-state ranges / change-log receipt / deferred autofix+format`);
1501
- }
1502
- else {
1503
- dbg(`tool_result: the observational settle recorded ${observedReplayed} mutation(s) for "${event.toolName}", but no dispatchable changed paths remained`);
1504
- }
1505
- }
1506
- return syntheticWriteContent.length > 0
1507
- ? { content: [...event.content, ...syntheticWriteContent] }
1508
- : undefined;
1509
- }
1510
- if (mutation === undefined) {
1511
- dbg(`tool_result: skipped turn tracking - toolName="${event.toolName}" is not a classified mutation`);
1512
- return syntheticWriteContent.length > 0
1513
- ? { content: [...event.content, ...syntheticWriteContent] }
1514
- : undefined;
1515
- }
1516
- if (!filePath) {
1517
- dbg(`tool_result: skipped turn tracking - no filePath for toolName="${event.toolName}"`);
1518
- return;
1519
- }
1520
- if (isExternalOrVendorFile(filePath, workspaceRoot)) {
1521
- dbg(`tool_result: skipped pipeline - file outside project root or in node_modules: ${filePath}`);
1522
- return;
1523
- }
1524
- // #2430: a classified mutation is accounted for by the chain below, so the
1525
- // `agent_settled` sweep must re-baseline this file rather than report the
1526
- // same bytes as unexplained drift.
1527
- noteMutationHandled(filePath);
1528
- const readGuardCorrelationId = getReadGuardCorrelationId(event);
1529
- const resultDetails = (event.details ?? {});
1530
- const isPartialApplyResult = resultDetails.piLensPartialApply === true;
1531
- const requestedEditIndexes = getRequestedEditIndexes(event, mutation.kind);
1532
- const requestedEditTotal = getRequestedEditCount(event, mutation.kind);
1533
- const participantIds = [
1534
- ...(deps._telemetryParticipantIds ?? []),
1535
- readGuardCorrelationId,
1536
- ].slice(0, 100);
1537
- const participantTotal = (deps._telemetryParticipantTotal ?? 0) +
1538
- (deps._telemetryParticipantIds?.includes(readGuardCorrelationId) ? 0 : 1);
1539
- const hostToolResultFailed = event.isError === true || resultDetails.isError === true;
1540
- if (hostToolResultFailed) {
1541
- logReadGuardEvent({
1542
- event: "edit_batch_summary",
1543
- correlationId: readGuardCorrelationId,
1544
- filePath,
1545
- metadata: {
1546
- tool: event.toolName,
1547
- source: "host_tool_result",
1548
- editBatchSummary: createReadGuardEditBatchSummary({
1549
- requestedIndexes: requestedEditIndexes,
1550
- requestedTotal: requestedEditTotal,
1551
- rejectedReasons: requestedEditIndexes.map((index) => ({
1552
- index,
1553
- code: "write_failed",
1554
- })),
1555
- rejectedTotal: requestedEditTotal,
1556
- participantIds: [readGuardCorrelationId],
1557
- participantTotal: 1,
1558
- commitStatus: "failed",
1559
- terminalStatus: "failed",
1560
- }),
1561
- },
1562
- });
1563
- return { content: event.content, isError: true };
1564
- }
1565
- // One post-result raw-byte hash, reused for the applied-edit records below and
1566
- // for the pipeline dedup key (`initialStateHash`) further down (finding 3):
1567
- // nothing between here and that point rewrites the file, so a second read
1568
- // would only re-derive the same digest.
1569
- //
1570
- // `preSettleStateHash` is that same digest taken BEFORE the observational
1571
- // settle's yield, on the only path that has one (#2449 round 3, T4). Reusing
1572
- // it is not an optimization: re-reading here would read whatever a racing
1573
- // tool_result wrote while this call was awaiting.
1574
- const postWriteStateHash = preSettleStateHash ?? getFileStateHash(filePath);
1575
- // #2402: a fully-applied native edit is also an applied record, so an
1576
- // identical retry is recognized as already-applied instead of escalating
1577
- // through the oldText-not-found ladder. `event.input` carries the EXECUTED
1578
- // args (post-autopatch), the same text the preflight resolves against.
1579
- const nativeAppliedPairs = recordNativeAppliedPairs({
1580
- runtime,
1581
- input: event.input,
1582
- kind: mutation.kind,
1583
- filePath,
1584
- stateHash: postWriteStateHash,
1585
- });
1586
- // Must happen before debounce admission: latestDeps intentionally retains only
1587
- // the latest event, but write -> edit is a sticky turn transition.
1588
- const receipt = runtime
1589
- .recordMutationToolReceipt;
1590
- const autofixMode = deps._bypassDebounce
1591
- ? (deps._autofixMode ??
1592
- (mutation.kind === "edit" ? "deferred" : "immediate"))
1593
- : receipt
1594
- ? receipt.call(runtime, filePath, mutation.kind).autofixMode
1595
- : mutation.kind === "edit"
1596
- ? "deferred"
1597
- : "immediate";
1598
- // Coalesce sequential edits to the same file into one pipeline run against
1599
- // the final state. Only the debounce-fired call (with _bypassDebounce=true)
1600
- // proceeds to the pipeline body; in-window callers share its promise.
1601
- if (!deps._bypassDebounce) {
1602
- const debounceMs = getDebounceMs();
1603
- if (debounceMs > 0) {
1604
- return scheduleDebounced(filePath, debounceMs, {
1605
- ...deps,
1606
- _autofixMode: autofixMode,
1607
- _telemetryParticipantIds: [readGuardCorrelationId],
1608
- _telemetryParticipantTotal: 1,
1609
- });
1610
- }
1611
- }
1612
- // Refresh the read-guard's FileTime stamp so that the model's own write
1613
- // doesn't trigger a spurious "file_modified" block on the next edit.
1614
- if (bashAuthorshipConfirmed)
1615
- deps.readGuard?.recordWritten(filePath);
1616
- // Keep cachedExports in sync after each write/edit so the pre-write STOP
1617
- // check doesn't fire on names that were removed from this file this session.
1618
- refreshCachedExports(runtime, filePath);
1619
- // Reuse the hash taken right after the write landed (finding 3): the file is
1620
- // unchanged between that read and here, so this is byte-identical.
1621
- const initialStateHash = postWriteStateHash;
1622
- // #2464 review round 3 (F1): the in-flight dedup and the already-analysed
1623
- // latch moved into `claimPipelineDispatch`, shared verbatim with the observed
1624
- // call site, which shipped round 2 with NEITHER check. The position is
1625
- // unchanged — still ABOVE `addModifiedRange`/`recordProjectChange`, so a
1626
- // duplicate state still writes no turn-state range and no change-log
1627
- // receipt. Nothing may await between this claim and the dispatch below: the
1628
- // claim is only atomic because `dispatchPipelineAnalysis` registers before
1629
- // its own first await.
1630
- const classifiedClaim = claimPipelineDispatch({
1631
- filePath,
1632
- stateHash: initialStateHash,
1633
- turnIndex: runtime.turnIndex,
1634
- participantId: readGuardCorrelationId,
1635
- dbg,
1636
- });
1637
- if (!classifiedClaim.proceed) {
1638
- if (classifiedClaim.joined) {
1639
- await classifiedClaim.joined;
1640
- }
1641
- return;
1642
- }
1643
- const sessionFileTime = createFileTime("default");
1644
- // tool_result is emitted after write/edit has already been applied.
1645
- // Asserting pre-write stamps here produces false positives on rapid edits.
1646
- sessionFileTime.read(filePath);
1647
- if (!getFlag("no-read-guard") && bashAuthorshipConfirmed) {
1648
- const readGuard = runtime.readGuard;
1649
- readGuard?.recordWritten?.(filePath);
1650
- }
1651
- // `toolResultStart` is hoisted above both provenance exits (#2464 review
1652
- // round 2, S5) so the two paths' durations are comparable — see its
1653
- // declaration right after the observational settle.
1654
- dbg(`tool_result: tracking turn state for ${event.toolName} on ${filePath}`);
1655
- if (isPathIgnoredByProject(filePath, workspaceRoot, false)) {
1656
- dbg(`tool_result: skipping gitignored file ${filePath}`);
1657
- return;
1658
- }
1659
- const dispatchCwd = resolveLanguageRootForFile(filePath, workspaceRoot);
1660
- const turnStateCwd = path.resolve(workspaceRoot);
1661
- dbg(`tool_result: resolved dispatch cwd ${dispatchCwd} for ${filePath} (turnState cwd ${turnStateCwd})`);
1662
- // #1655 item 2: a `setTelemetryIdentity` call used to sit here, gated on
1663
- // `event.model`/`provider`/`sessionId`/`session.id`. pi sets none of those on
1664
- // a `tool_result` — `afterToolCall` builds the event with exactly
1665
- // `type`/`toolName`/`toolCallId`/`input`/`content`/`details`/`isError`/`usage`
1666
- // (`@earendil-works/pi-coding-agent/dist/core/agent-session.js:243-256`,
1667
- // source `src/core/agent-session.ts:502-516`), so the gate was always false
1668
- // against a real host and the branch never ran. Identity for this dispatch
1669
- // comes from the runtime, which `message_start`/`session_start` populate —
1670
- // see the `telemetry:` block handed to `runPipeline` below.
1671
- const writeIndex = runtime.nextWriteIndex();
1672
- let modifiedRanges;
1673
- // #2423: ranges a shape adapter resolved from the tool's own input. Only a
1674
- // classified non-native edit shape sets these — a plain host `edit` carries
1675
- // its ranges in `details.diff` and is handled by the branch below.
1676
- const adapterRanges = mutation.editRanges && mutation.editRanges.length > 0
1677
- ? mutation.editRanges.map(([start, end]) => ({ start, end }))
1678
- : mutation.touchedLines
1679
- ? [{ start: mutation.touchedLines[0], end: mutation.touchedLines[1] }]
1680
- : undefined;
1681
- try {
1682
- // #1334 S6: the host DECLARES this payload (`EditToolDetails`, a
1683
- // type-only export), so use it instead of re-declaring `{ diff?: string }`
1684
- // here — the ad-hoc shape hid the sibling `patch`/`firstChangedLine`
1685
- // fields. `Partial<>` keeps the defensive posture: the host types mark
1686
- // `diff` required, but this runs against whatever a live host actually
1687
- // sent, and the `details?.diff` truthiness check below is what the code
1688
- // has always relied on.
1689
- const details = event.details;
1690
- dbg(`tool_result: details.diff=${details?.diff ? "present" : "missing"}, details keys: ${Object.keys(event.details || {}).join(", ")}`);
1691
- if (mutation.kind === "edit" && details?.diff) {
1692
- const diff = details.diff;
1693
- dbg(`tool_result: diff content (first 500 chars): ${diff.substring(0, 500)}`);
1694
- const ranges = parseDiffRanges(diff);
1695
- modifiedRanges = ranges;
1696
- const importsChanged = /import\s/.test(diff) || /from\s+['"]/.test(diff);
1697
- dbg(`tool_result: parsed ${ranges.length} ranges, importsChanged=${importsChanged}`);
1698
- for (const range of ranges) {
1699
- dbg(`tool_result: adding range ${range.start}-${range.end} for ${filePath}`);
1700
- cacheManager.addModifiedRange(filePath, range, importsChanged, turnStateCwd, runtime.telemetrySessionId);
1701
- }
1702
- dbg(`tool_result: turn state after add: ${JSON.stringify(cacheManager.readTurnState(turnStateCwd))}`);
1703
- }
1704
- else if (mutation.kind === "edit" &&
1705
- adapterRanges &&
1706
- nodeFs.existsSync(filePath)) {
1707
- // #2423: a third-party edit tool ships no host `details.diff`, so the
1708
- // diff branch above never fires and the file used to leave `files: {}`
1709
- // empty in turn-state.json. The shape adapter already resolved which
1710
- // lines the call touched — use those.
1711
- const content = nodeFs.readFileSync(filePath, "utf-8");
1712
- const importsChanged = /^import\s/m.test(content);
1713
- modifiedRanges = adapterRanges;
1714
- for (const range of adapterRanges) {
1715
- cacheManager.addModifiedRange(filePath, range, importsChanged, turnStateCwd, runtime.telemetrySessionId);
1716
- }
1717
- }
1718
- else if (mutation.kind === "edit" &&
1719
- mutation.provenance === "declared" &&
1720
- nodeFs.existsSync(filePath)) {
1721
- // #2423 review round 1 (F1): a third-party edit whose anchors did not
1722
- // resolve — a stale anchor, or the read-guard preflight never ran to
1723
- // resolve them — still CHANGED the file. Recording the whole file is a
1724
- // deliberate superset: turn state exists to say "this file changed,
1725
- // format and attribute it", and an empty `files` map is the exact
1726
- // symptom the issue reports. A host `edit` keeps its old behavior,
1727
- // because its ranges come from `details.diff` above.
1728
- const content = nodeFs.readFileSync(filePath, "utf-8");
1729
- const lineCount = content.split("\n").length;
1730
- const importsChanged = /^import\s/m.test(content);
1731
- modifiedRanges = [{ start: 1, end: lineCount }];
1732
- cacheManager.addModifiedRange(filePath, { start: 1, end: lineCount }, importsChanged, turnStateCwd, runtime.telemetrySessionId);
1733
- }
1734
- else if (mutation.kind === "write" && nodeFs.existsSync(filePath)) {
1735
- const content = nodeFs.readFileSync(filePath, "utf-8");
1736
- const lineCount = content.split("\n").length;
1737
- const hasImports = /^import\s/m.test(content);
1738
- modifiedRanges = [{ start: 1, end: lineCount }];
1739
- cacheManager.addModifiedRange(filePath, { start: 1, end: lineCount }, hasImports, turnStateCwd, runtime.telemetrySessionId);
1740
- }
1741
- }
1742
- catch (err) {
1743
- dbg(`turn state tracking error: ${err}`);
1744
- dbg(`turn state tracking error stack: ${err.stack}`);
1745
- }
1746
- recordProjectChange({
1747
- runtime,
1748
- cwd: turnStateCwd,
1749
- filePath,
1750
- source: deps._mutationSourceOverride ??
1751
- sourceForMutation(mutation, event.details),
1752
- changedRange: singleRange(modifiedRanges),
1753
- dbg,
1754
- });
1755
- const turnStateMs = Date.now() - toolResultStart;
1756
- logLatency({
1757
- type: "phase",
1758
- toolName: event.toolName,
1759
- filePath,
1760
- phase: "turn_state_tracking",
1761
- durationMs: turnStateMs,
1762
- });
1763
- dbg(`tool_result fired for: ${filePath} (turn_state: ${turnStateMs}ms)`);
1764
- // #2464: the pipeline dispatch itself now lives in `dispatchPipelineAnalysis`
1765
- // (defined above `handleToolResult`), shared with the observed-mutation
1766
- // early return. This call site is otherwise unchanged — same arguments, same
1767
- // crash-then-return / success-then-continue shape as before the split.
1768
- const classifiedClients = ensureToolResultClients(deps);
1769
- if (classifiedClients !== true &&
1770
- !(await bounded(Promise.resolve(classifiedClients), {
1771
- ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
1772
- signal: deps.signal,
1773
- hook: "tool_result_edit",
1774
- label: "classified-tool-result-analysis",
1775
- })))
1776
- return;
1777
- const dispatchOutcome = await bounded(dispatchPipelineAnalysis({
1778
- deps,
1779
- runtime,
1780
- filePath,
1781
- dispatchCwd,
1782
- turnStateCwd,
1783
- autofixMode,
1784
- modifiedRanges,
1785
- writeIndex,
1786
- initialStateHash,
1787
- readGuardCorrelationId,
1788
- requestedEditIndexes,
1789
- requestedEditTotal,
1790
- isPartialApplyResult,
1791
- participantIds,
1792
- participantTotal,
1793
- toolResultStart,
1794
- nativeAppliedPairs,
1795
- allowAutonomousWriters: bashAuthorshipConfirmed,
1796
- }), {
1797
- ms: HOOK_WALL_BUDGET_MS.tool_result_edit,
1798
- signal: deps.signal || undefined,
1799
- hook: "tool_result_edit",
1800
- label: "pipeline-analysis",
1801
- });
1802
- if (!dispatchOutcome)
1803
- return;
1804
- if (dispatchOutcome.crashed) {
1805
- return dispatchOutcome.response;
1806
- }
1807
- // #2464 review round 2 (S1): the three post-pipeline post-conditions that
1808
- // used to be written out here — the already-analysed latch, the #2402
1809
- // after-write hash stamp, and the read-guard staleness re-stamp over
1810
- // `result.changedFiles` — now live INSIDE `dispatchPipelineAnalysis`, so the
1811
- // observed path gets them by construction rather than by a second author
1812
- // remembering to copy them.
1813
- const result = dispatchOutcome.result;
1814
- let autofixNewlyQueued = false;
1815
- if (!result.isError &&
1816
- bashAuthorshipConfirmed &&
1817
- autofixMode === "deferred" &&
1818
- nodeFs.existsSync(filePath)) {
1819
- autofixNewlyQueued =
1820
- runtime.deferMutation?.call(runtime, filePath, dispatchCwd, event.toolName, turnStateCwd, "autofix", deps.sessionId, resolutionBasis) ?? false;
1821
- dbg(`tool_result: queued deferred autofix for ${filePath}`);
1822
- }
1823
- let formatQueued = false;
1824
- if (!result.isError &&
1825
- bashAuthorshipConfirmed &&
1826
- !getFlag("no-autoformat", filePath) &&
1827
- (autofixMode === "deferred" || !getFlag("immediate-format")) &&
1828
- nodeFs.existsSync(filePath)) {
1829
- const isNewlyQueued = runtime.deferFormat(filePath, dispatchCwd, event.toolName, turnStateCwd, deps.sessionId, resolutionBasis);
1830
- formatQueued = true;
1831
- dbg(`tool_result: queued deferred format for ${filePath}`);
1832
- logLatency({
1833
- type: "phase",
1834
- toolName: event.toolName,
1835
- filePath,
1836
- phase: "deferred_format_queued",
1837
- durationMs: 0,
1838
- metadata: { cwd: dispatchCwd },
1839
- });
1840
- // Publish a file's first queue entry and each newly added kind. A same-kind
1841
- // re-touch before agent_end carries no new information and stays silent.
1842
- if (isNewlyQueued || autofixNewlyQueued) {
1843
- publishFormatQueued({
1844
- filePath,
1845
- cwd: dispatchCwd,
1846
- // The v1 `pilens:format:queued` payload declares
1847
- // `tool: "write" | "edit"`, so a third-party tool publishes under
1848
- // its KIND rather than its name. Widening the published field is a
1849
- // public-API decision tracked in #2421; until then the kind is the
1850
- // honest projection.
1851
- tool: mutation.kind,
1852
- dbg,
1853
- kinds: autofixMode === "deferred" ? ["autofix", "format"] : ["format"],
1854
- });
1855
- }
1856
- }
1857
- if (autofixNewlyQueued && !formatQueued) {
1858
- publishFormatQueued({
1859
- filePath,
1860
- cwd: dispatchCwd,
1861
- // Same #2421 projection as the queued-with-format publish above.
1862
- tool: mutation.kind,
1863
- kinds: ["autofix"],
1864
- dbg,
1865
- });
1866
- }
1867
- for (const changedFile of result.changedFiles ?? []) {
1868
- const resolvedChanged = path.resolve(changedFile);
1869
- invalidateFormatterCacheForPath(resolvedChanged);
1870
- if (!nodeFs.existsSync(resolvedChanged))
1871
- continue;
1872
- recordProjectChange({
1873
- runtime,
1874
- cwd: turnStateCwd,
1875
- filePath: resolvedChanged,
1876
- source: "autofix",
1877
- dbg,
1878
- });
1879
- // Workspace-edit paths come from fileURLToPath and are normally absolute,
1880
- // so the turn-state cwd is inert for those values. Keep it in the resolve
1881
- // call because the producer's contract is cwd-relative URI resolution, and
1882
- // let pathsEqual ask the filesystem-aware path identity question (#3294).
1883
- if (pathsEqual(path.resolve(turnStateCwd, changedFile), path.resolve(filePath)))
1884
- continue;
1885
- try {
1886
- const content = nodeFs.readFileSync(resolvedChanged, "utf-8");
1887
- const lineCount = content.split("\n").length;
1888
- const hasImports = /^import\s/m.test(content);
1889
- cacheManager.addModifiedRange(resolvedChanged, { start: 1, end: lineCount }, hasImports, turnStateCwd);
1890
- dbg(`tool_result: tracking pi-lens side-effect change for ${resolvedChanged}`);
1891
- }
1892
- catch (err) {
1893
- dbg(`tool_result: side-effect tracking failed for ${resolvedChanged}: ${err}`);
1894
- }
1895
- }
1896
- if (result.cascadePromise) {
1897
- runtime.appendCascadePromise(result.cascadePromise);
1898
- }
1899
- if (result.actionableWarnings?.length) {
1900
- runtime.recordActionableWarnings(result.actionableWarnings);
1901
- }
1902
- if (result.codeQualityWarnings?.length) {
1903
- runtime.recordCodeQualityWarnings(result.codeQualityWarnings);
1904
- }
1905
- // #484: opt-in per-turn summary collection. Same signals the pipeline
1906
- // already computed above (diagnostics, autofix count/tools, formatters
1907
- // used) — no new collection plumbing, just fed into the collector when
1908
- // the feature is on.
1909
- if (getFlag("lens-turn-summary")) {
1910
- if (result.diagnostics?.length) {
1911
- for (const d of result.diagnostics) {
1912
- runtime.turnSummary.recordDiagnostic(d.filePath || filePath, {
1913
- tool: d.tool,
1914
- ruleId: d.rule ?? d.code,
1915
- severity: d.severity,
1916
- line: d.line,
1917
- description: d.message,
1918
- });
1919
- }
1920
- }
1921
- if (result.fixedCount && result.fixedCount > 0) {
1922
- for (const label of result.autofixTools ?? []) {
1923
- const [tool, countStr] = label.split(":");
1924
- const count = Number.parseInt(countStr ?? "", 10);
1925
- runtime.turnSummary.recordAutofix(filePath, {
1926
- tool: tool || label,
1927
- description: Number.isFinite(count) && count > 0
1928
- ? `${count} issue(s) fixed`
1929
- : undefined,
1930
- });
1931
- }
1932
- }
1933
- if (result.formattersUsed?.length) {
1934
- for (const tool of result.formattersUsed) {
1935
- runtime.turnSummary.recordFormat(filePath, { tool });
1936
- }
1937
- }
1938
- }
1939
- if (result.inlineBlockerSummary) {
1940
- // #1561: stamp the verdict with THIS dispatch's write token — the same
1941
- // counter `lsp_diagnostics`' reconciliation seam draws from — so a later
1942
- // confirmed-clean result can be ordered against it instead of racing it.
1943
- runtime.recordInlineBlockers(filePath, result.inlineBlockerSummary, writeIndex, result.inlineBlockerSources, result.inlineBlockerLines, result.inlineBlockerFileContent,
1944
- // #3246: the structured blockers the summary was rendered from, so a
1945
- // later `lens_diagnostic_mark` can be applied to this record at turn
1946
- // end instead of replaying pre-mark text.
1947
- result.inlineBlockerDiagnostics);
1948
- }
1949
- else {
1950
- runtime.clearInlineBlockers(filePath);
1951
- }
1952
- runtime.updateGitGuardStatus(result.hasBlockers, result.output);
1953
- if (getFlag("lens-guard")) {
1954
- syncGitGuardRecord(runtime, cacheManager, turnStateCwd, filePath);
1955
- if (result.isError && !result.hasBlockers) {
1956
- runtime.markGitGuardCacheUnknown("pipeline_error");
1957
- }
1958
- }
1959
- if (result.isError) {
1960
- return {
1961
- content: [...event.content, { type: "text", text: result.output }],
1962
- isError: true,
1963
- };
1964
- }
1965
- let output = result.output;
1966
- if (behaviorWarnings.length > 0 && !result.hasBlockers) {
1967
- output += `\n\n${formatBehaviorWarnings(behaviorWarnings)}`;
1968
- }
1969
- const totalMs = Date.now() - toolResultStart;
1970
- logLatency({
1971
- type: "tool_result",
1972
- toolName: event.toolName,
1973
- filePath,
1974
- durationMs: totalMs,
1975
- result: output ? "completed" : "no_output",
1976
- });
1977
- runtime.reportedThisTurn.add(filePath);
1978
- // --- The ONE authoritative-attachment decision (#1590) ---
1979
- // Everything downstream — the attached block, the telemetry row, the nudge
1980
- // suppression, and the notice sentence — reads this single verdict. It is
1981
- // the only place that sees both limits: the per-file cap and the shared
1982
- // per-command budget a multi-file bash write threads in.
1983
- const postMutation = result.postMutation;
1984
- const attachmentText = postMutation
1985
- ? `pi-lens applied autofix to ${postMutation.filePath}. The following full content is authoritative for subsequent edits:\n\n${postMutation.content}`
1986
- : "";
1987
- const contentBytes = postMutation
1988
- ? Buffer.byteLength(postMutation.content, "utf-8")
1989
- : 0;
1990
- const withinPerFileCap = contentBytes <= AUTHORITATIVE_CONTENT_MAX_BYTES;
1991
- const budget = deps._attachmentBudget;
1992
- const withinSharedBudget = !budget || Buffer.byteLength(attachmentText, "utf-8") <= budget.remaining;
1993
- const attachAuthoritativeContent = postMutation !== undefined && withinPerFileCap && withinSharedBudget;
1994
- const attachmentDecision = !postMutation
1995
- ? "none"
1996
- : attachAuthoritativeContent
1997
- ? "attached"
1998
- : withinPerFileCap
1999
- ? "aggregate-budget-degraded"
2000
- : "size-capped";
2001
- // #1590: the pipeline hands up the changed-file data and this layer renders
2002
- // the sentence, so a size-capped write can no longer carry both "attached
2003
- // content is authoritative" and "too large to attach". The fallback covers
2004
- // a post-mutation with no notice data, which must still say re-read.
2005
- const notice = result.postAutofixNotice ??
2006
- (postMutation
2007
- ? { targetPath: postMutation.filePath, changedFiles: [] }
2008
- : undefined);
2009
- if (postMutation && attachAuthoritativeContent && budget) {
2010
- budget.remaining -= Buffer.byteLength(attachmentText, "utf-8");
2011
- }
2012
- // #1590 review F1: every mutation that produced a notice logs a row,
2013
- // INCLUDING the `none` decision a format-only change makes. Gating the row
2014
- // on `postMutation` made a legitimate "nothing was attachable here" verdict
2015
- // indistinguishable from missing instrumentation, which is the same
2016
- // empty-vs-errored confusion the read paths already guard against.
2017
- if (postMutation || notice) {
2018
- logLatency({
2019
- type: "phase",
2020
- phase: "authoritative_content_attachment_decision",
2021
- filePath: postMutation?.filePath ?? filePath,
2022
- durationMs: 0,
2023
- metadata: {
2024
- path: postMutation?.filePath ?? filePath,
2025
- bytes: contentBytes,
2026
- decision: attachmentDecision,
2027
- },
2028
- });
2029
- }
2030
- if (postMutation) {
2031
- // #1464: the nudge suppresses exactly the paths this decision
2032
- // delivered. Same boolean the attachment below reads — the nudge layer
2033
- // never re-derives the cap or the budget for itself.
2034
- noteAuthoritativeContentAttachment(postMutation.filePath, attachAuthoritativeContent);
2035
- }
2036
- const returnedContent = attachAuthoritativeContent
2037
- ? [...event.content, { type: "text", text: attachmentText }]
2038
- : event.content;
2039
- if (notice) {
2040
- output = `${output ? `${output}\n\n` : ""}${renderPostAutofixNotice(notice, attachmentDecision)}`;
2041
- }
2042
- if (!output && !result.postMutation)
2043
- return;
2044
- return {
2045
- content: output
2046
- ? [...returnedContent, { type: "text", text: output }]
2047
- : returnedContent,
2048
- };
2049
- }