@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,1653 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { Worker } from "node:worker_threads";
5
- import { gunzipSync, gzipSync } from "node:zlib";
6
- import { writeFileAtomic } from "./atomic-write.js";
7
- import { BoundedFifoMap } from "./bounded-cache.js";
8
- import { getProjectDataDir } from "./file-utils.js";
9
- import { incrementDegradationCount } from "./degradation-ledger.js";
10
- import { readJsonCache } from "./json-cache-read.js";
11
- import { logLatency } from "./latency-logger.js";
12
- import { normalizeMapKey } from "./path-utils.js";
13
- import { fingerprintProjectSnapshotJson } from "./project-snapshot-fingerprint.js";
14
- import { detectProjectConventions, } from "./project-conventions.js";
15
- import { deserializeWordIndex, serializeWordIndex, } from "./word-index.js";
16
- // v2: added `wordIndex` (identifier inverted index + BM25, #162). Bumping the
17
- // version invalidates pre-v2 snapshots so they rebuild with the new field.
18
- export const PROJECT_SNAPSHOT_VERSION = 2;
19
- function parseSequenceIndex(value) {
20
- if (!value || typeof value !== "object")
21
- return undefined;
22
- const index = value;
23
- if (typeof index.projectSeq !== "number")
24
- return undefined;
25
- if (!Array.isArray(index.fileSeqByPath))
26
- return undefined;
27
- const fileSeqByPath = index.fileSeqByPath.filter((entry) => Array.isArray(entry) &&
28
- typeof entry[0] === "string" &&
29
- typeof entry[1] === "number");
30
- return { projectSeq: index.projectSeq, fileSeqByPath };
31
- }
32
- // #958 item 2: the canonical snapshot body is now streamed gzip
33
- // (`project-snapshot.json.gz`), written by a worker thread off the save path
34
- // (see the persist plumbing below). The previous uncompressed
35
- // `project-snapshot.json` remains readable for ONE compatibility release so an
36
- // upgrading user doesn't lose their snapshot — see loadSnapshotBody's legacy
37
- // fallback. gzip measured 5-10x on top of the #957 compaction win (the
38
- // review-graph's own measurement was 60MB → 1.4MB).
39
- export function getProjectSnapshotPath(cwd) {
40
- return path.join(getProjectDataDir(cwd), "cache", "project-snapshot.json.gz");
41
- }
42
- /**
43
- * Pre-#958 uncompressed body path. Read as a one-release fallback when no
44
- * `.json.gz` is present; deleted whenever a fresh gz body is promoted so the
45
- * two never coexist.
46
- */
47
- export function getProjectSnapshotLegacyPath(cwd) {
48
- return path.join(getProjectDataDir(cwd), "cache", "project-snapshot.json");
49
- }
50
- export function getProjectSnapshotMetaPath(cwd) {
51
- return path.join(getProjectDataDir(cwd), "cache", "project-snapshot.meta.json");
52
- }
53
- export function isProjectSnapshotFresh(snapshot, currentProjectSeq) {
54
- return (!!snapshot &&
55
- snapshot.version === PROJECT_SNAPSHOT_VERSION &&
56
- snapshot.seq === currentProjectSeq);
57
- }
58
- function parseSnapshot(value) {
59
- if (!value || typeof value !== "object")
60
- return null;
61
- const snapshot = value;
62
- if (snapshot.version !== PROJECT_SNAPSHOT_VERSION)
63
- return null;
64
- if (typeof snapshot.projectRoot !== "string")
65
- return null;
66
- if (typeof snapshot.generatedAt !== "string")
67
- return null;
68
- if (typeof snapshot.seq !== "number")
69
- return null;
70
- if (!Array.isArray(snapshot.cachedExports))
71
- return null;
72
- return {
73
- version: PROJECT_SNAPSHOT_VERSION,
74
- projectRoot: snapshot.projectRoot,
75
- generatedAt: snapshot.generatedAt,
76
- seq: snapshot.seq,
77
- files: snapshot.files ?? {},
78
- symbols: snapshot.symbols ?? {},
79
- reverseDeps: snapshot.reverseDeps ?? {},
80
- cachedExports: snapshot.cachedExports.filter((entry) => Array.isArray(entry) &&
81
- typeof entry[0] === "string" &&
82
- typeof entry[1] === "string"),
83
- sequenceIndex: parseSequenceIndex(snapshot.sequenceIndex),
84
- wordIndex: snapshot.wordIndex,
85
- projectRulesScan: snapshot.projectRulesScan,
86
- startupScan: snapshot.startupScan,
87
- languageProfile: snapshot.languageProfile,
88
- conventions: snapshot.conventions,
89
- };
90
- }
91
- function parseSnapshotMeta(value) {
92
- if (!value || typeof value !== "object")
93
- return null;
94
- const meta = value;
95
- if (typeof meta.version !== "number")
96
- return null;
97
- if (typeof meta.seq !== "number")
98
- return null;
99
- return {
100
- timestamp: typeof meta.timestamp === "string" ? meta.timestamp : "",
101
- version: meta.version,
102
- seq: meta.seq,
103
- fingerprint: typeof meta.fingerprint === "string" &&
104
- /^[a-f0-9]{64}$/.test(meta.fingerprint)
105
- ? meta.fingerprint
106
- : undefined,
107
- gzBytes: typeof meta.gzBytes === "number" &&
108
- Number.isInteger(meta.gzBytes) &&
109
- meta.gzBytes > 0
110
- ? meta.gzBytes
111
- : undefined,
112
- sequenceIndex: parseSequenceIndex(meta.sequenceIndex),
113
- };
114
- }
115
- /**
116
- * Read the tiny meta sidecar (`project-snapshot.meta.json`) WITHOUT parsing
117
- * the (potentially 40-112MB) snapshot body. Written on every save; absent on
118
- * legacy installs — callers must treat a `null` return as "no opinion" and
119
- * fall through to parsing the body. #947.
120
- */
121
- export function readProjectSnapshotMeta(cwd) {
122
- const meta = readJsonCache(getProjectSnapshotMetaPath(cwd), (parsed) => parseSnapshotMeta(parsed) ?? undefined);
123
- return meta ?? null;
124
- }
125
- /**
126
- * Cheap staleness verdict from the meta sidecar alone. When this returns
127
- * true, the snapshot body CANNOT be fresh (isProjectSnapshotFresh would
128
- * reject it on the same two fields), so the expensive body parse can be
129
- * skipped entirely. #947.
130
- */
131
- export function isProjectSnapshotMetaStale(meta, currentProjectSeq) {
132
- return (meta.version !== PROJECT_SNAPSHOT_VERSION || meta.seq !== currentProjectSeq);
133
- }
134
- export const SNAPSHOT_PARSE_CACHE_MAX = 4;
135
- // #957 review: the cache exists to avoid re-parsing NORMAL snapshots within a
136
- // session. A 112MB-class body parses to hundreds of MB of heap — pinning that
137
- // for process lifetime inverts the win, so oversized bodies are simply never
138
- // cached (they re-parse per read, exactly the pre-#947 behavior). Measured
139
- // against the UNCOMPRESSED body size, never the (much smaller) gz file size.
140
- const SNAPSHOT_PARSE_CACHE_MAX_BYTES = 24 * 1024 * 1024;
141
- const snapshotParseCache = new BoundedFifoMap(SNAPSHOT_PARSE_CACHE_MAX);
142
- function withoutWordIndex(snapshot) {
143
- if (!snapshot?.wordIndex)
144
- return snapshot;
145
- const { wordIndex: _releasedPostings, ...stripped } = snapshot;
146
- return stripped;
147
- }
148
- function cacheParsedSnapshot(snapshotPath, entry) {
149
- // Refresh recency (delete then set moves the key to the newest position;
150
- // BoundedFifoMap itself never reorders an already-present key on set()).
151
- snapshotParseCache.delete(snapshotPath);
152
- snapshotParseCache.set(snapshotPath, entry);
153
- }
154
- const authoritativeSnapshots = new Map();
155
- export const PROJECT_SNAPSHOT_MAX_WARM_ROOTS = 8;
156
- const PROJECT_SNAPSHOT_IDLE_EVICT_MS_DEFAULT = 20 * 60_000;
157
- function projectSnapshotIdleEvictMs() {
158
- const value = Number.parseInt(process.env.PI_LENS_PROJECT_SNAPSHOT_IDLE_EVICT_MS ?? "", 10);
159
- return Number.isSafeInteger(value) && value > 0
160
- ? value
161
- : PROJECT_SNAPSHOT_IDLE_EVICT_MS_DEFAULT;
162
- }
163
- function clearAuthoritativeSnapshotTimer(entry) {
164
- if (entry.idleTimer)
165
- clearTimeout(entry.idleTimer);
166
- entry.idleTimer = undefined;
167
- }
168
- function deleteAuthoritativeSnapshot(key) {
169
- const entry = authoritativeSnapshots.get(key);
170
- if (entry)
171
- clearAuthoritativeSnapshotTimer(entry);
172
- authoritativeSnapshots.delete(key);
173
- }
174
- function scheduleAuthoritativeSnapshotEviction(key, entry) {
175
- clearAuthoritativeSnapshotTimer(entry);
176
- const generation = entry.lastUsedAt;
177
- entry.idleTimer = setTimeout(() => {
178
- entry.idleTimer = undefined;
179
- if (authoritativeSnapshots.get(key) !== entry ||
180
- entry.lastUsedAt !== generation)
181
- return;
182
- deleteAuthoritativeSnapshot(key);
183
- }, projectSnapshotIdleEvictMs());
184
- entry.idleTimer.unref?.();
185
- }
186
- function touchAuthoritativeSnapshot(key, entry) {
187
- entry.lastUsedAt = Date.now();
188
- scheduleAuthoritativeSnapshotEviction(key, entry);
189
- }
190
- function enforceAuthoritativeSnapshotCap() {
191
- while (authoritativeSnapshots.size > PROJECT_SNAPSHOT_MAX_WARM_ROOTS) {
192
- const victim = [...authoritativeSnapshots.entries()].sort(([, a], [, b]) => a.lastUsedAt - b.lastUsedAt)[0];
193
- if (!victim)
194
- return;
195
- clearAuthoritativeSnapshotTimer(victim[1]);
196
- deleteAuthoritativeSnapshot(victim[0]);
197
- }
198
- }
199
- /** Test-only cache keys, in LRU order from oldest to newest. */
200
- export function _getAuthoritativeSnapshotCacheKeysForTests() {
201
- return [...authoritativeSnapshots.entries()]
202
- .sort(([, a], [, b]) => a.lastUsedAt - b.lastUsedAt)
203
- .map(([key]) => key);
204
- }
205
- /** Test hook: drop all cached parses + authoritative writes (per-worker isolation). */
206
- export function _resetProjectSnapshotParseCacheForTests() {
207
- snapshotParseCache.clear();
208
- for (const entry of authoritativeSnapshots.values())
209
- clearAuthoritativeSnapshotTimer(entry);
210
- authoritativeSnapshots.clear();
211
- }
212
- /** Test hook: prove the parse-cache tier never owns serialized postings. */
213
- export function _projectSnapshotParseCacheRetainsWordIndexForTests() {
214
- return [...snapshotParseCache.values()].some((entry) => entry.snapshot?.wordIndex !== undefined);
215
- }
216
- /** Resolve which body file is currently on disk: gz canonical, else legacy. */
217
- function resolveSnapshotBodyPath(cwd) {
218
- const gzPath = getProjectSnapshotPath(cwd);
219
- try {
220
- const stat = fs.statSync(gzPath);
221
- return { path: gzPath, gz: true, mtimeMs: stat.mtimeMs, size: stat.size };
222
- }
223
- catch {
224
- /* fall through to the legacy uncompressed body */
225
- }
226
- const legacyPath = getProjectSnapshotLegacyPath(cwd);
227
- try {
228
- const stat = fs.statSync(legacyPath);
229
- return {
230
- path: legacyPath,
231
- gz: false,
232
- mtimeMs: stat.mtimeMs,
233
- size: stat.size,
234
- };
235
- }
236
- catch {
237
- return null;
238
- }
239
- }
240
- /**
241
- * Read + parse the body off disk, transparently gunzipping the `.json.gz`
242
- * canonical form and falling back to the pre-#958 uncompressed `.json` body
243
- * for one compatibility release. Returns the parsed snapshot (or null on any
244
- * failure) plus the UNCOMPRESSED byte length, so the caller can apply the
245
- * heap-bounded cache gate against the real body size rather than the gz size.
246
- */
247
- // Test-observable count of ACTUAL disk body reads (both gz and legacy), so the
248
- // #947 meta-gate tests can assert "body parsed / not parsed" independently of
249
- // the compression format — the pre-#958 tests keyed this off a readJsonCache
250
- // spy, which the gz path (gunzip + JSON.parse) legitimately bypasses.
251
- let _snapshotBodyReadCountForTests = 0;
252
- export function getSnapshotBodyReadCountForTests() {
253
- return _snapshotBodyReadCountForTests;
254
- }
255
- export function resetSnapshotBodyReadCountForTests() {
256
- _snapshotBodyReadCountForTests = 0;
257
- }
258
- function readSnapshotBody(bodyPath, gz) {
259
- _snapshotBodyReadCountForTests++;
260
- if (!gz) {
261
- const snapshot = readJsonCache(bodyPath, (parsed) => parseSnapshot(parsed) ?? undefined) ?? null;
262
- let rawBytes = 0;
263
- try {
264
- rawBytes = fs.statSync(bodyPath).size;
265
- }
266
- catch {
267
- /* best-effort */
268
- }
269
- return { snapshot, rawBytes };
270
- }
271
- try {
272
- const json = gunzipSync(fs.readFileSync(bodyPath)).toString("utf-8");
273
- const snapshot = parseSnapshot(JSON.parse(json)) ?? null;
274
- return { snapshot, rawBytes: Buffer.byteLength(json) };
275
- }
276
- catch (err) {
277
- // Corrupt / truncated gz, or a parse failure: fail open exactly like
278
- // readJsonCache does — a null return rebuilds the snapshot. Log it so a
279
- // corrupt body is diagnosable rather than indistinguishable from "no
280
- // snapshot yet" (both return a null snapshot here).
281
- logLatency({
282
- type: "phase",
283
- phase: "project_snapshot_body_corrupt",
284
- filePath: bodyPath,
285
- durationMs: 0,
286
- metadata: { error: err instanceof Error ? err.message : String(err) },
287
- });
288
- return { snapshot: null, rawBytes: 0 };
289
- }
290
- }
291
- /**
292
- * Scan a JSON value starting at `start` (skipping any leading whitespace)
293
- * and return the index one past its end. Handles strings, objects, arrays,
294
- * and bare scalars (numbers/`true`/`false`/`null`) — correctly skipping
295
- * nested strings/braces/brackets (respecting `\"` escapes) WITHOUT ever
296
- * constructing a JS value for them. This is the primitive
297
- * `stripTopLevelJsonKeys` (#1785 F5) is built on: `JSON.parse` has no way to
298
- * skip a subtree's construction cost — a reviver only prunes the
299
- * already-built result — so avoiding a field's parse cost requires never
300
- * handing its text to `JSON.parse` in the first place.
301
- */
302
- function skipJsonValue(text, start) {
303
- let i = start;
304
- while (i < text.length && /\s/.test(text[i]))
305
- i++;
306
- const ch = text[i];
307
- if (ch === '"') {
308
- i++;
309
- while (i < text.length) {
310
- if (text[i] === "\\") {
311
- i += 2;
312
- continue;
313
- }
314
- if (text[i] === '"') {
315
- i++;
316
- break;
317
- }
318
- i++;
319
- }
320
- return i;
321
- }
322
- if (ch === "{" || ch === "[") {
323
- const open = ch;
324
- const close = open === "{" ? "}" : "]";
325
- let depth = 0;
326
- let inString = false;
327
- for (; i < text.length; i++) {
328
- const c = text[i];
329
- if (inString) {
330
- if (c === "\\") {
331
- i++;
332
- continue;
333
- }
334
- if (c === '"')
335
- inString = false;
336
- continue;
337
- }
338
- if (c === '"') {
339
- inString = true;
340
- continue;
341
- }
342
- if (c === open)
343
- depth++;
344
- else if (c === close) {
345
- depth--;
346
- if (depth === 0) {
347
- i++;
348
- break;
349
- }
350
- }
351
- }
352
- return i;
353
- }
354
- // A bare scalar (number/true/false/null): scan to the next structural
355
- // character. Every snapshot value is one of the five JSON kinds above, so
356
- // this branch only ever fires for those scalars.
357
- while (i < text.length && !",}]".includes(text[i]))
358
- i++;
359
- return i;
360
- }
361
- /**
362
- * Reconstruct a JSON object literal with the given top-level keys removed,
363
- * without ever materializing their values as JS objects (#1785 F5). Used to
364
- * excise the expensive fields — `wordIndex`'s postings graph above all,
365
- * `files`/`symbols`/`reverseDeps` too — before `JSON.parse` ever sees them,
366
- * so a caller that only needs a few small top-level fields (`seq`,
367
- * `cachedExports`, `projectRulesScan`, …) doesn't pay to construct the
368
- * fields it's about to discard. Correctness relies only on the writer
369
- * (`JSON.stringify(snapshot)`, `clients/gzip-stage-write.ts`) never emitting
370
- * pretty-printed/indented output — compact `JSON.stringify` output is what
371
- * every persist path in this file produces.
372
- */
373
- function stripTopLevelJsonKeys(text, keysToStrip) {
374
- const objStart = text.indexOf("{");
375
- if (objStart === -1)
376
- return text;
377
- let out = text.slice(0, objStart + 1);
378
- let i = objStart + 1;
379
- let wroteField = false;
380
- while (i < text.length) {
381
- while (i < text.length && /\s/.test(text[i]))
382
- i++;
383
- if (text[i] === "}" || i >= text.length) {
384
- out += text.slice(i);
385
- break;
386
- }
387
- if (text[i] === ",") {
388
- i++;
389
- continue;
390
- }
391
- const keyStart = i;
392
- const keyTextEnd = skipJsonValue(text, keyStart);
393
- let key;
394
- try {
395
- key = JSON.parse(text.slice(keyStart, keyTextEnd));
396
- }
397
- catch {
398
- // Malformed key text — bail out to the untouched original rather
399
- // than risk producing invalid JSON; the caller's own JSON.parse
400
- // on the result will then fail loudly instead of silently.
401
- return text;
402
- }
403
- let j = keyTextEnd;
404
- while (j < text.length && /\s/.test(text[j]))
405
- j++;
406
- // text[j] is ':' for a well-formed object.
407
- const valueStart = j + 1;
408
- const valueEnd = skipJsonValue(text, valueStart);
409
- if (!keysToStrip.has(key)) {
410
- out += (wroteField ? "," : "") + text.slice(keyStart, valueEnd);
411
- wroteField = true;
412
- }
413
- i = valueEnd;
414
- }
415
- return out;
416
- }
417
- /**
418
- * Test-only direct access to the raw-text stripper (#1785 F5). Unlike
419
- * asserting on `loadProjectSnapshotExportsAndRules`'s RETURN shape — which
420
- * only proves the output omits the heavy fields, not that their parse cost
421
- * was ever avoided (the function could strip nothing and still hand-pick 4
422
- * fields out of a fully-parsed object) — this lets a test inspect the
423
- * INTERMEDIATE text `JSON.parse` actually receives, which is the only way to
424
- * prove the expensive fields' text never reached `JSON.parse` at all.
425
- */
426
- export function _stripTopLevelJsonKeysForTests(text, keysToStrip) {
427
- return stripTopLevelJsonKeys(text, new Set(keysToStrip));
428
- }
429
- // A fixed, 4-entry, import-time constant — not per-session accumulating
430
- // state, so it needs no session_start reset (counted in
431
- // tests/support/session-state-registry.ts's SESSION_STATE_SYMBOL_COUNTS
432
- // pin for "project-snapshot.ts", alongside the bounded digest hook below).
433
- //
434
- // Adding a key here? Add it to `NARROW_DIGEST_HEAVY_KEY_LITERALS` too (~40
435
- // lines down) — it's a DELIBERATELY separate, independent list (#1785 F7: a
436
- // digest that reads its own containsHeavyKey answer off THIS set can't
437
- // detect this set failing/emptying, so it must not).
438
- const HEAVY_SNAPSHOT_KEYS = new Set([
439
- "wordIndex",
440
- "files",
441
- "symbols",
442
- "reverseDeps",
443
- ]);
444
- // #1785 F7 (review round 5): a FIXED LITERAL list, independent of
445
- // `HEAVY_SNAPSHOT_KEYS` — the digest below exists to detect a broken/emptied
446
- // `HEAVY_SNAPSHOT_KEYS`, so deriving `containsHeavyKey` from that same
447
- // constant makes the check vacuous by construction: empty the set and the
448
- // stripper strips nothing AND `[...HEAVY_SNAPSHOT_KEYS].some(...)` iterates
449
- // zero entries and reports `false` — the exact failure mode this hook exists
450
- // to catch, silently passing. Verified: with the shared-constant version,
451
- // emptying `HEAVY_SNAPSHOT_KEYS` left 38 tests green instead of red.
452
- const NARROW_DIGEST_HEAVY_KEY_LITERALS = [
453
- "wordIndex",
454
- "files",
455
- "symbols",
456
- "reverseDeps",
457
- ];
458
- let _lastNarrowParseDigestForTests;
459
- export function getLastNarrowParseDigestForTests() {
460
- return _lastNarrowParseDigestForTests;
461
- }
462
- export function resetLastNarrowParseDigestForTests() {
463
- _lastNarrowParseDigestForTests = undefined;
464
- }
465
- function parseExportsAndRulesOnly(json) {
466
- const narrowed = stripTopLevelJsonKeys(json, HEAVY_SNAPSHOT_KEYS);
467
- _lastNarrowParseDigestForTests = {
468
- length: narrowed.length,
469
- containsHeavyKey: NARROW_DIGEST_HEAVY_KEY_LITERALS.some((key) => narrowed.includes(`"${key}":`)),
470
- };
471
- const parsed = JSON.parse(narrowed);
472
- if (parsed.version !== PROJECT_SNAPSHOT_VERSION)
473
- return null;
474
- if (typeof parsed.seq !== "number")
475
- return null;
476
- if (!Array.isArray(parsed.cachedExports))
477
- return null;
478
- return {
479
- version: PROJECT_SNAPSHOT_VERSION,
480
- seq: parsed.seq,
481
- cachedExports: parsed.cachedExports.filter((entry) => Array.isArray(entry) &&
482
- typeof entry[0] === "string" &&
483
- typeof entry[1] === "string"),
484
- projectRulesScan: parsed.projectRulesScan,
485
- };
486
- }
487
- function readSnapshotExportsAndRulesBody(bodyPath, gz) {
488
- try {
489
- const json = gz
490
- ? gunzipSync(fs.readFileSync(bodyPath)).toString("utf-8")
491
- : fs.readFileSync(bodyPath, "utf-8");
492
- return parseExportsAndRulesOnly(json);
493
- }
494
- catch (err) {
495
- logLatency({
496
- type: "phase",
497
- phase: "project_snapshot_body_corrupt",
498
- filePath: bodyPath,
499
- durationMs: 0,
500
- metadata: {
501
- error: err instanceof Error ? err.message : String(err),
502
- narrow: true,
503
- },
504
- });
505
- return null;
506
- }
507
- }
508
- /**
509
- * #1785 F5: a narrow counterpart to `loadProjectSnapshot` for callers that
510
- * only need `seq`/`version`/`cachedExports`/`projectRulesScan` — critically,
511
- * NOT `wordIndex`, `files`, `symbols`, or `reverseDeps`. The full
512
- * `loadProjectSnapshot` (even `loadProjectSnapshotWithoutWordIndex`, which
513
- * only strips the RETAINED copy AFTER a full parse) pays `gunzip` +
514
- * `JSON.parse` for the ENTIRE body regardless — dominated by `wordIndex`'s
515
- * postings graph (measured: +200ms warm / +700ms cold on a 29MB body,
516
- * 209-278ms on this repo's own 16.7MB snapshot). This function excises the
517
- * heavy fields from the raw text BEFORE parsing (`stripTopLevelJsonKeys`),
518
- * so their construction cost is never paid at all; the remaining cost is
519
- * dominated by `cachedExports` (typically a small array), not the postings.
520
- *
521
- * Consults the same in-process authoritative-write cache
522
- * `loadProjectSnapshotInternal` does, for the same read-your-own-write
523
- * reason — a save's in-memory object is cheap to narrow (no parse needed at
524
- * all) and must win over a possibly-stale on-disk body exactly like the full
525
- * loader.
526
- */
527
- export function loadProjectSnapshotExportsAndRules(cwd) {
528
- const key = normalizeMapKey(cwd);
529
- const body = resolveSnapshotBodyPath(cwd);
530
- const authoritative = authoritativeSnapshots.get(key);
531
- if (authoritative) {
532
- // `body === null` means nothing is on disk — that is never "the body
533
- // changed size", so it must not be read as superseding our own write.
534
- // See the matching comment in loadProjectSnapshotInternal.
535
- const notSuperseded = body === null ||
536
- (body.mtimeMs <= authoritative.knownMtime &&
537
- body.size === authoritative.knownSize);
538
- if (notSuperseded) {
539
- const { version, seq, cachedExports, projectRulesScan } = authoritative.snapshot;
540
- return { version, seq, cachedExports, projectRulesScan };
541
- }
542
- // On mismatch, unlike the full loader, this narrow loader neither
543
- // deletes the entry nor touches its idle timer (it never calls
544
- // touchAuthoritativeSnapshot even on a hit). The stale entry is safe to
545
- // leave in place: nothing here re-arms its eviction, so it is still
546
- // bounded by whatever idle window the full loader (or the original
547
- // write) last set, not left to live indefinitely.
548
- }
549
- if (!body)
550
- return null;
551
- return readSnapshotExportsAndRulesBody(body.path, body.gz);
552
- }
553
- function loadProjectSnapshotInternal(cwd, requireWordIndex) {
554
- const key = normalizeMapKey(cwd);
555
- const body = resolveSnapshotBodyPath(cwd);
556
- // Authoritative in-process write wins while our own (possibly still
557
- // in-flight) write has not been superseded on disk by a newer external mtime
558
- // or a different-size body in the same/coarser bucket. `body === null` means
559
- // nothing is on disk — either our just-scheduled write hasn't landed yet, or
560
- // something removed the body after we wrote it (e.g. a cleared cache dir).
561
- // Neither case is "the body changed size", so serve the in-process object.
562
- const authoritative = authoritativeSnapshots.get(key);
563
- if (authoritative) {
564
- const notSuperseded = body === null ||
565
- (body.mtimeMs <= authoritative.knownMtime &&
566
- body.size === authoritative.knownSize);
567
- if (notSuperseded) {
568
- touchAuthoritativeSnapshot(key, authoritative);
569
- return authoritative.snapshot;
570
- }
571
- // An external writer changed the body beyond our metadata stamp — honor
572
- // disk and stop serving the now-stale in-memory object.
573
- deleteAuthoritativeSnapshot(key);
574
- }
575
- if (!body) {
576
- snapshotParseCache.delete(getProjectSnapshotPath(cwd));
577
- return null;
578
- }
579
- const cacheKey = body.path;
580
- const cached = snapshotParseCache.get(cacheKey);
581
- // Both mtime AND size must match (see the `size` field doc on
582
- // SnapshotParseCacheEntry for why: coarse FAT/exFAT mtime resolution can
583
- // otherwise alias a just-rewritten file onto a stale cache entry).
584
- if (cached && cached.mtimeMs === body.mtimeMs && cached.size === body.size) {
585
- if (!requireWordIndex || !cached.snapshot || cached.snapshot.wordIndex) {
586
- return cached.snapshot;
587
- }
588
- }
589
- const { snapshot, rawBytes } = readSnapshotBody(body.path, body.gz);
590
- // Serialized postings expand into a much larger object graph. Cache only a
591
- // shallow postings-stripped body: metadata/report consumers stay warm while
592
- // the live warm WordIndex remains the sole retained postings graph (#1370).
593
- const cacheSnapshot = withoutWordIndex(snapshot);
594
- if (rawBytes > 0 &&
595
- (rawBytes <= SNAPSHOT_PARSE_CACHE_MAX_BYTES || snapshot?.wordIndex)) {
596
- cacheParsedSnapshot(cacheKey, {
597
- mtimeMs: body.mtimeMs,
598
- size: body.size,
599
- snapshot: cacheSnapshot,
600
- });
601
- }
602
- else {
603
- snapshotParseCache.delete(cacheKey);
604
- }
605
- return snapshot;
606
- }
607
- /** Load the canonical body, including serialized postings when present. */
608
- export function loadProjectSnapshot(cwd) {
609
- return loadProjectSnapshotInternal(cwd, true);
610
- }
611
- /**
612
- * Load snapshot metadata without retaining or re-reading serialized postings.
613
- * After publication this is served by the postings-stripped parse cache.
614
- */
615
- export function loadProjectSnapshotWithoutWordIndex(cwd) {
616
- return loadProjectSnapshotInternal(cwd, false);
617
- }
618
- const _snapshotGenerationStates = new Map();
619
- const _successfulSnapshotPersists = new BoundedFifoMap(PROJECT_SNAPSHOT_MAX_WARM_ROOTS);
620
- const _failedSnapshotPersists = new BoundedFifoMap(PROJECT_SNAPSHOT_MAX_WARM_ROOTS);
621
- const _activeSnapshotPersists = new Map();
622
- const _queuedSnapshotPersists = new Map();
623
- const _snapshotWorkerRequests = new Map();
624
- let _snapshotPersistWorker;
625
- let _snapshotWorkerRequestId = 0;
626
- let _snapshotWorkerDisabled = false;
627
- let _snapshotGenerationGateEnabledForTests = true;
628
- let _snapshotPromotionSeamForTests;
629
- let _lastSnapshotPersistErrorForTests;
630
- let _snapshotExiting = false;
631
- let _snapshotWorkerBodyWritesForTests = 0;
632
- function snapshotWorkerEnabled() {
633
- // The synchronous fallback writer is a legitimate degraded mode (hosts that
634
- // can't spawn a worker); tests also force it so a save→load is fully
635
- // synchronous. Production defaults to the worker.
636
- const raw = process.env.PI_LENS_SNAPSHOT_PERSIST_SYNC;
637
- return !(raw === "1" || raw === "true");
638
- }
639
- function pendingSnapshotIsCurrent(pending) {
640
- return (!_snapshotGenerationGateEnabledForTests ||
641
- _snapshotGenerationStates.get(pending.key)?.generation ===
642
- pending.generation);
643
- }
644
- function rememberSuccessfulSnapshotPersist(key, record) {
645
- _successfulSnapshotPersists.delete(key);
646
- _successfulSnapshotPersists.set(key, record);
647
- }
648
- function assessSnapshotBodyIntegrity(meta, body) {
649
- if (meta.gzBytes === undefined) {
650
- // Legacy meta (pre-#2008): nothing to compare against, so the evidence is
651
- // untrusted until the next successful persist populates gzBytes.
652
- return { outcome: "legacy-meta", actualBytes: body.size };
653
- }
654
- if (!body.gz || body.size !== meta.gzBytes) {
655
- return {
656
- outcome: "size-mismatch",
657
- expectedGzBytes: meta.gzBytes,
658
- actualBytes: body.size,
659
- };
660
- }
661
- return {
662
- outcome: "ok",
663
- expectedGzBytes: meta.gzBytes,
664
- actualBytes: body.size,
665
- };
666
- }
667
- /**
668
- * Bounded observability for #2008: the degradation ledger keeps one entry per
669
- * corrupted subject with the exact detection count for the session; every
670
- * detection also emits one `project_snapshot_body_integrity` latency row
671
- * naming expected vs actual bytes, so an operator can confirm both the
672
- * detection and the forced republish from logs alone.
673
- */
674
- function noteSnapshotBodyIntegrityWithheld(args) {
675
- incrementDegradationCount({
676
- kind: "snapshot-integrity",
677
- subject: args.gzPath,
678
- reason: args.verdict,
679
- });
680
- logLatency({
681
- type: "phase",
682
- phase: "project_snapshot_body_integrity",
683
- filePath: args.gzPath,
684
- durationMs: 0,
685
- metadata: {
686
- outcome: "dedupe_withheld",
687
- reason: args.verdict,
688
- ...(args.seq !== undefined ? { seq: args.seq } : {}),
689
- ...(args.expectedGzBytes === undefined
690
- ? {}
691
- : { expectedGzBytes: args.expectedGzBytes }),
692
- actualBytes: args.actualBytes,
693
- },
694
- });
695
- }
696
- /** Log one row naming a skip that was refused because integrity regressed. */
697
- function noteSnapshotSkipRefused(args) {
698
- logLatency({
699
- type: "phase",
700
- phase: "project_snapshot_body_integrity",
701
- filePath: args.gzPath,
702
- durationMs: 0,
703
- metadata: {
704
- outcome: "skip_refused_rewrite",
705
- reason: args.verdict,
706
- seq: args.seq,
707
- },
708
- });
709
- }
710
- /**
711
- * PURE READ of the durable meta+body evidence for a snapshot key (#2008
712
- * refactor): it must never mutate {@link _successfulSnapshotPersists}. This
713
- * runs up to three times per persist — admission in saveProjectSnapshot, the
714
- * dispatch-time refresh, and the skip-honor re-read — including on results
715
- * whose fingerprints are only partially used, so the seeding write lives in
716
- * {@link seedSnapshotPersistBaselineFromDurable} and is called only by the
717
- * seam that owns the persist lifecycle (dispatchSnapshotPersist).
718
- */
719
- function snapshotPersistBaselinesFor(cwd, key) {
720
- const local = _successfulSnapshotPersists.get(key);
721
- const meta = readProjectSnapshotMeta(cwd);
722
- const body = resolveSnapshotBodyPath(cwd);
723
- // No body means no dedupe evidence. This keeps same-seq deletion repair live.
724
- if (!meta?.fingerprint || !body) {
725
- if (!body)
726
- _successfulSnapshotPersists.delete(key);
727
- return { fingerprints: [] };
728
- }
729
- // #2008: a meta whose recorded gz size no longer matches the on-disk body
730
- // describes evidence we cannot trust — a truncated/torn gzip under an
731
- // intact meta used to win same-fingerprint dedupe forever, keeping the
732
- // corrupt body canonical until seq advanced. Withhold the fingerprints so
733
- // the pending save republishes (and rewrites) the body.
734
- const integrity = assessSnapshotBodyIntegrity(meta, body);
735
- if (integrity.outcome !== "ok") {
736
- noteSnapshotBodyIntegrityWithheld({
737
- gzPath: getProjectSnapshotPath(cwd),
738
- verdict: integrity.outcome,
739
- seq: meta.seq,
740
- expectedGzBytes: integrity.expectedGzBytes,
741
- actualBytes: integrity.actualBytes,
742
- });
743
- return { fingerprints: [] };
744
- }
745
- const durable = {
746
- seq: meta.seq,
747
- fingerprint: meta.fingerprint,
748
- generatedAt: meta.timestamp,
749
- generation: _snapshotGenerationStates.get(key)?.generation ?? 0,
750
- gzBytes: meta.gzBytes,
751
- };
752
- const fingerprints = [durable.fingerprint];
753
- // A sibling process may have advanced durable state from local A to B. An
754
- // unchanged replay of A is stale work and must not overwrite B. A third
755
- // semantic state C matches neither fingerprint and still publishes.
756
- if (local && local.fingerprint !== durable.fingerprint) {
757
- fingerprints.push(local.fingerprint);
758
- }
759
- return { durable, fingerprints, integrity: "ok" };
760
- }
761
- /**
762
- * Seed the in-process baseline for `key` from freshly-read durable state.
763
- * Deliberately separate from {@link snapshotPersistBaselinesFor} so the read
764
- * stays pure; called only at the dispatch seam where the persist lifecycle
765
- * begins.
766
- */
767
- function seedSnapshotPersistBaselineFromDurable(key, durable) {
768
- if (!durable || _successfulSnapshotPersists.has(key))
769
- return;
770
- rememberSuccessfulSnapshotPersist(key, durable);
771
- }
772
- function writeProjectSnapshotMeta(metaPath, snapshot, bodyRecord) {
773
- writeFileAtomic(metaPath, JSON.stringify({
774
- timestamp: bodyRecord?.generatedAt ?? snapshot.generatedAt,
775
- version: snapshot.version,
776
- seq: snapshot.seq,
777
- ...(bodyRecord
778
- ? {
779
- fingerprint: bodyRecord.fingerprint,
780
- ...(bodyRecord.gzBytes === undefined
781
- ? {}
782
- : { gzBytes: bodyRecord.gzBytes }),
783
- }
784
- : {}),
785
- ...(snapshot.sequenceIndex
786
- ? { sequenceIndex: snapshot.sequenceIndex }
787
- : {}),
788
- }), { bestEffort: false });
789
- }
790
- function recordSnapshotPersistFailure(pending, error, bodyPersisted = false) {
791
- // Honesty (#533): a failed async body write must be surfaced, never left to
792
- // masquerade as a saved snapshot. The meta gate is already self-healing (an
793
- // old body under a newer-seq meta is rejected on the body's own embedded
794
- // seq), and dropping the authoritative entry means the next load reflects
795
- // what is ACTUALLY on disk rather than the object we failed to persist.
796
- _lastSnapshotPersistErrorForTests = error;
797
- _failedSnapshotPersists.set(pending.key, {
798
- seq: pending.snapshot.seq,
799
- generation: pending.generation,
800
- });
801
- deleteAuthoritativeSnapshot(pending.key);
802
- logLatency({
803
- type: "phase",
804
- phase: "project_snapshot_persist_failed",
805
- filePath: pending.gzPath,
806
- durationMs: 0,
807
- metadata: {
808
- error,
809
- seq: pending.snapshot.seq,
810
- outcome: bodyPersisted ? "metadata_repair_required" : "failed",
811
- ...(bodyPersisted ? { bodyPersisted: true } : {}),
812
- },
813
- });
814
- // #1333: the logLatency call above already carries this failure to
815
- // latency.log — the console.error was a duplicate RAW write into pi's frame.
816
- }
817
- function logSnapshotPersistSuccess(pending, fingerprint, stats) {
818
- rememberSuccessfulSnapshotPersist(pending.key, {
819
- seq: pending.snapshot.seq,
820
- fingerprint,
821
- generatedAt: pending.snapshot.generatedAt,
822
- generation: pending.generation,
823
- rawBytes: stats.rawBytes,
824
- gzBytes: stats.gzBytes,
825
- });
826
- _failedSnapshotPersists.delete(pending.key);
827
- logLatency({
828
- type: "phase",
829
- phase: "project_snapshot_persist",
830
- filePath: pending.gzPath,
831
- durationMs: stats.serializeMs + stats.writeMs,
832
- metadata: { seq: pending.snapshot.seq, outcome: "executed", ...stats },
833
- });
834
- }
835
- function logSnapshotPersistDecision(args) {
836
- logLatency({
837
- type: "phase",
838
- phase: "project_snapshot_persist_decision",
839
- filePath: getProjectSnapshotPath(args.cwd),
840
- durationMs: 0,
841
- metadata: {
842
- seq: args.seq,
843
- decision: args.decision,
844
- ...(args.fingerprint
845
- ? { fingerprint: args.fingerprint.slice(0, 12) }
846
- : {}),
847
- ...(args.avoidedRawBytes === undefined
848
- ? {}
849
- : { avoidedRawBytes: args.avoidedRawBytes }),
850
- ...(args.avoidedGzipBytes === undefined
851
- ? {}
852
- : { avoidedGzipBytes: args.avoidedGzipBytes }),
853
- },
854
- });
855
- }
856
- /**
857
- * Reconcile the authoritative in-process entry with a body that just landed on
858
- * disk: update its `knownMtime` so a subsequent load keeps serving our own
859
- * object without re-parsing, and DROP oversized bodies (their post-promotion
860
- * disk read is the pre-#947 behavior — we won't pin hundreds of MB of heap).
861
- */
862
- function reconcileAuthoritativeAfterWrite(pending, rawBytes) {
863
- const entry = authoritativeSnapshots.get(pending.key);
864
- // Only reconcile the entry that still belongs to THIS (latest) generation —
865
- // a superseding save already replaced it with a newer object.
866
- if (!entry || entry.snapshot !== pending.snapshot)
867
- return;
868
- // The worker needs the serialized snapshot until promotion completes, but
869
- // retaining it afterward duplicates the mutable warm index's postings. A
870
- // shared reference is unsafe: ProjectSnapshot stores serialized arrays while
871
- // WordIndex owns mutable Map/PathKeyedMap state. Drop the authoritative copy
872
- // after publication; later merge-writers rehydrate the canonical disk body.
873
- if (pending.snapshot.wordIndex) {
874
- try {
875
- const stat = fs.statSync(pending.gzPath);
876
- cacheParsedSnapshot(pending.gzPath, {
877
- mtimeMs: stat.mtimeMs,
878
- size: stat.size,
879
- snapshot: withoutWordIndex(pending.snapshot),
880
- });
881
- }
882
- catch {
883
- // A cache miss is safe: the first metadata consumer reconstructs it.
884
- }
885
- deleteAuthoritativeSnapshot(pending.key);
886
- logLatency({
887
- type: "phase",
888
- phase: "project_snapshot_word_index_released",
889
- filePath: pending.gzPath,
890
- durationMs: 0,
891
- metadata: { rawBytes },
892
- });
893
- return;
894
- }
895
- if (rawBytes > SNAPSHOT_PARSE_CACHE_MAX_BYTES) {
896
- // Benign but invisible otherwise: the next load will re-parse this body
897
- // from disk instead of serving the in-process object.
898
- logLatency({
899
- type: "phase",
900
- phase: "project_snapshot_authoritative_dropped_oversized",
901
- filePath: pending.gzPath,
902
- durationMs: 0,
903
- metadata: { rawBytes, maxBytes: SNAPSHOT_PARSE_CACHE_MAX_BYTES },
904
- });
905
- deleteAuthoritativeSnapshot(pending.key);
906
- return;
907
- }
908
- try {
909
- const stat = fs.statSync(pending.gzPath);
910
- entry.knownMtime = stat.mtimeMs;
911
- entry.knownSize = stat.size;
912
- }
913
- catch {
914
- // If we can't stat our own write, leave the metadata as-is; the worst case
915
- // is one extra disk re-parse on the next load.
916
- }
917
- }
918
- function finalizeProjectSnapshotMeta(pending, record) {
919
- try {
920
- writeProjectSnapshotMeta(getProjectSnapshotMetaPath(pending.cwd), pending.snapshot, record);
921
- return true;
922
- }
923
- catch (err) {
924
- recordSnapshotPersistFailure(pending, err instanceof Error ? err.message : String(err), true);
925
- return false;
926
- }
927
- }
928
- function completeSnapshotPersist(pending) {
929
- if (_activeSnapshotPersists.get(pending.key) !== pending)
930
- return;
931
- _activeSnapshotPersists.delete(pending.key);
932
- if (_snapshotExiting)
933
- return;
934
- const queued = _queuedSnapshotPersists.get(pending.key);
935
- if (!queued)
936
- return;
937
- _queuedSnapshotPersists.delete(pending.key);
938
- dispatchSnapshotPersist(queued);
939
- }
940
- function writeSnapshotBodyOnMainThread(pending, reason) {
941
- if (!pendingSnapshotIsCurrent(pending)) {
942
- completeSnapshotPersist(pending);
943
- return;
944
- }
945
- if (reason) {
946
- // We took the synchronous main-thread gzip path (the +656MB-risk path,
947
- // #950) instead of the worker. Surface it rather than burying it in an
948
- // `offloaded:false` success line below. `degraded` distinguishes a REAL
949
- // degradation (worker died/unavailable/promote-failed) from the benign
950
- // `exit_hook` teardown flush, so an operator triaging worker health isn't
951
- // misled by normal process-exit flushes.
952
- logLatency({
953
- type: "phase",
954
- phase: "project_snapshot_worker_fallback",
955
- filePath: pending.gzPath,
956
- durationMs: 0,
957
- metadata: {
958
- reason,
959
- seq: pending.snapshot.seq,
960
- degraded: reason !== "exit_hook",
961
- },
962
- });
963
- }
964
- try {
965
- const serializeStarted = performance.now();
966
- const json = JSON.stringify(pending.snapshot);
967
- const serializeMs = performance.now() - serializeStarted;
968
- const rawBytes = Buffer.byteLength(json);
969
- const fingerprint = fingerprintProjectSnapshotJson(json, pending.snapshot.generatedAt);
970
- if (pending.dedupeFingerprints.includes(fingerprint)) {
971
- // Re-read the tiny durable sidecar before honoring a fingerprint
972
- // captured at dispatch time (#2008): a body torn between dispatch and
973
- // execution must fall through to the full write, not skip.
974
- const current = snapshotPersistBaselinesFor(pending.cwd, pending.key);
975
- if (current.integrity === "ok") {
976
- const prior = current.durable ?? pending.durablePersist;
977
- if (authoritativeSnapshots.get(pending.key)?.snapshot === pending.snapshot) {
978
- deleteAuthoritativeSnapshot(pending.key);
979
- }
980
- logSnapshotPersistDecision({
981
- cwd: pending.cwd,
982
- seq: pending.snapshot.seq,
983
- fingerprint,
984
- decision: "skipped_unchanged",
985
- avoidedRawBytes: rawBytes,
986
- avoidedGzipBytes: prior?.gzBytes,
987
- });
988
- return;
989
- }
990
- if (current.integrity !== undefined) {
991
- noteSnapshotSkipRefused({
992
- gzPath: pending.gzPath,
993
- verdict: current.integrity,
994
- seq: pending.snapshot.seq,
995
- });
996
- }
997
- // integrity === undefined: the meta/body evidence vanished entirely
998
- // since dispatch — falling through to the full write repairs it, the
999
- // same contract as deletion-before-dispatch.
1000
- }
1001
- const writeStarted = performance.now();
1002
- const gzip = gzipSync(json);
1003
- fs.mkdirSync(path.dirname(pending.gzPath), { recursive: true });
1004
- writeFileAtomic(pending.gzPath, gzip, { bestEffort: false });
1005
- fs.rmSync(pending.legacyPath, { force: true });
1006
- const metadataFinalized = finalizeProjectSnapshotMeta(pending, {
1007
- fingerprint,
1008
- generatedAt: pending.snapshot.generatedAt,
1009
- gzBytes: gzip.byteLength,
1010
- });
1011
- if (!metadataFinalized)
1012
- return;
1013
- reconcileAuthoritativeAfterWrite(pending, rawBytes);
1014
- logSnapshotPersistSuccess(pending, fingerprint, {
1015
- rawBytes,
1016
- gzBytes: gzip.byteLength,
1017
- serializeMs,
1018
- writeMs: performance.now() - writeStarted,
1019
- offloaded: false,
1020
- });
1021
- if (reason)
1022
- _lastSnapshotPersistErrorForTests = reason;
1023
- }
1024
- catch (err) {
1025
- recordSnapshotPersistFailure(pending, err instanceof Error ? err.message : String(err));
1026
- }
1027
- finally {
1028
- completeSnapshotPersist(pending);
1029
- }
1030
- }
1031
- /**
1032
- * The ForTests promotion seam covers worker-message and every main-thread
1033
- * fallback promotion. It stays sync and seam-free in production, identical to
1034
- * calling the writer directly. The process-exit hook is deliberately the sole
1035
- * direct write because an exit handler cannot await this asynchronous seam.
1036
- */
1037
- function dispatchMainThreadWriteThroughSeam(pending, reason) {
1038
- if (_snapshotPromotionSeamForTests) {
1039
- void _snapshotPromotionSeamForTests().then(() => writeSnapshotBodyOnMainThread(pending, reason));
1040
- return;
1041
- }
1042
- writeSnapshotBodyOnMainThread(pending, reason);
1043
- }
1044
- function handleSnapshotWorkerResult(result) {
1045
- const pending = _snapshotWorkerRequests.get(result.id);
1046
- if (!pending) {
1047
- fs.rmSync(result.stagePath, { force: true });
1048
- return;
1049
- }
1050
- _snapshotWorkerRequests.delete(result.id);
1051
- if (result.error ||
1052
- result.rawBytes === undefined ||
1053
- result.gzBytes === undefined ||
1054
- result.serializeMs === undefined ||
1055
- result.writeMs === undefined ||
1056
- result.semanticFingerprint === undefined) {
1057
- fs.rmSync(result.stagePath, { force: true });
1058
- dispatchMainThreadWriteThroughSeam(pending, result.error ?? "invalid worker result");
1059
- return;
1060
- }
1061
- // Generation gate: a newer save already superseded this one — discard the
1062
- // stale stage file rather than promote it over the fresher body.
1063
- if (!result.skippedUnchanged)
1064
- _snapshotWorkerBodyWritesForTests++;
1065
- if (_snapshotGenerationGateEnabledForTests &&
1066
- _snapshotGenerationStates.get(pending.key)?.generation !== result.generation) {
1067
- // The stale stage is part of the promotion transaction: remove it before
1068
- // returning so a superseded save cannot leave an orphan behind.
1069
- fs.rmSync(result.stagePath, { force: true });
1070
- completeSnapshotPersist(pending);
1071
- return;
1072
- }
1073
- if (result.skippedUnchanged) {
1074
- // Re-read the tiny durable sidecar at the decision seam. A sibling process
1075
- // may have advanced B after this request captured A. A stale replay of A
1076
- // must preserve B's body metadata, not restore the captured A sidecar.
1077
- const baselines = snapshotPersistBaselinesFor(pending.cwd, pending.key);
1078
- if (baselines.integrity !== "ok") {
1079
- // The worker skipped WITHOUT staging a body, trusting the durable
1080
- // fingerprint captured at dispatch. The re-read says that evidence no
1081
- // longer passes the #2008 integrity gate — refuse the skip and rewrite
1082
- // synchronously so a torn/missing body cannot outlive this save. The
1083
- // sync writer recomputes the same baselines, finds them untrusted, and
1084
- // performs the full gzip+stage+promote (its finally completes this
1085
- // pending, so do not complete it twice here).
1086
- if (baselines.integrity !== undefined) {
1087
- noteSnapshotSkipRefused({
1088
- gzPath: pending.gzPath,
1089
- verdict: baselines.integrity,
1090
- seq: pending.snapshot.seq,
1091
- });
1092
- }
1093
- dispatchMainThreadWriteThroughSeam(pending, "snapshot body integrity regressed");
1094
- return;
1095
- }
1096
- const prior = baselines.durable ?? pending.durablePersist;
1097
- if (authoritativeSnapshots.get(pending.key)?.snapshot === pending.snapshot) {
1098
- deleteAuthoritativeSnapshot(pending.key);
1099
- }
1100
- logSnapshotPersistDecision({
1101
- cwd: pending.cwd,
1102
- seq: pending.snapshot.seq,
1103
- fingerprint: result.semanticFingerprint,
1104
- decision: "skipped_unchanged",
1105
- avoidedRawBytes: result.rawBytes,
1106
- avoidedGzipBytes: prior?.gzBytes,
1107
- });
1108
- completeSnapshotPersist(pending);
1109
- return;
1110
- }
1111
- try {
1112
- fs.renameSync(result.stagePath, pending.gzPath);
1113
- fs.rmSync(pending.legacyPath, { force: true });
1114
- const metadataFinalized = finalizeProjectSnapshotMeta(pending, {
1115
- fingerprint: result.semanticFingerprint,
1116
- generatedAt: pending.snapshot.generatedAt,
1117
- gzBytes: result.gzBytes,
1118
- });
1119
- if (!metadataFinalized) {
1120
- completeSnapshotPersist(pending);
1121
- return;
1122
- }
1123
- reconcileAuthoritativeAfterWrite(pending, result.rawBytes);
1124
- logSnapshotPersistSuccess(pending, result.semanticFingerprint, {
1125
- rawBytes: result.rawBytes,
1126
- gzBytes: result.gzBytes,
1127
- serializeMs: result.serializeMs,
1128
- writeMs: result.writeMs,
1129
- offloaded: true,
1130
- });
1131
- completeSnapshotPersist(pending);
1132
- }
1133
- catch (err) {
1134
- fs.rm(result.stagePath, { force: true }, () => { });
1135
- dispatchMainThreadWriteThroughSeam(pending, err instanceof Error ? err.message : String(err));
1136
- }
1137
- }
1138
- function dispatchSnapshotPersist(pending) {
1139
- // A queued request may have waited behind the publication that created its
1140
- // best dedupe evidence. Refresh only the tiny sidecar/body stat here; never
1141
- // retain the stale admission-time baseline through dispatch.
1142
- const baselines = snapshotPersistBaselinesFor(pending.cwd, pending.key);
1143
- pending.durablePersist = baselines.durable;
1144
- pending.dedupeFingerprints = baselines.fingerprints;
1145
- seedSnapshotPersistBaselineFromDurable(pending.key, baselines.durable);
1146
- _activeSnapshotPersists.set(pending.key, pending);
1147
- if (!snapshotWorkerEnabled()) {
1148
- dispatchMainThreadWriteThroughSeam(pending, undefined);
1149
- return;
1150
- }
1151
- const worker = getSnapshotPersistWorker();
1152
- if (!worker) {
1153
- dispatchMainThreadWriteThroughSeam(pending, "persist worker unavailable");
1154
- return;
1155
- }
1156
- const id = ++_snapshotWorkerRequestId;
1157
- _snapshotWorkerRequests.set(id, pending);
1158
- const request = {
1159
- id,
1160
- generation: pending.generation,
1161
- stagePath: pending.stagePath,
1162
- data: pending.snapshot,
1163
- priorFingerprints: pending.dedupeFingerprints,
1164
- testDelayMs: process.env.NODE_ENV === "test"
1165
- ? Number(process.env.PI_LENS_TEST_SNAPSHOT_PERSIST_WORKER_DELAY_MS) ||
1166
- undefined
1167
- : undefined,
1168
- };
1169
- try {
1170
- worker.postMessage(request);
1171
- }
1172
- catch (err) {
1173
- _snapshotWorkerRequests.delete(id);
1174
- dispatchMainThreadWriteThroughSeam(pending, err instanceof Error ? err.message : String(err));
1175
- }
1176
- }
1177
- function handleSnapshotWorkerDeath(reason) {
1178
- _snapshotPersistWorker = undefined;
1179
- _snapshotWorkerDisabled = true;
1180
- const requests = [..._snapshotWorkerRequests.values()];
1181
- _snapshotWorkerRequests.clear();
1182
- for (const pending of requests)
1183
- dispatchMainThreadWriteThroughSeam(pending, reason);
1184
- }
1185
- function resolveSnapshotPersistWorkerPath() {
1186
- // esbuild does NOT rewrite new URL(...) asset refs, so from the bundled
1187
- // dist/index.js a sibling ./project-snapshot-persist-worker.js resolves
1188
- // beside the BUNDLE where nothing exists. Try the compiled-sibling layout
1189
- // first (source checkout / unbundled dist/clients tree), then the dist-tree
1190
- // path relative to the bundle entry — same shape as the review graph's
1191
- // resolvePersistWorkerPath (#950 review F1).
1192
- const candidates = [
1193
- new URL("./project-snapshot-persist-worker.js", import.meta.url),
1194
- new URL("./clients/project-snapshot-persist-worker.js", import.meta.url),
1195
- ];
1196
- for (const url of candidates) {
1197
- try {
1198
- const resolved = fileURLToPath(url);
1199
- if (fs.existsSync(resolved))
1200
- return resolved;
1201
- }
1202
- catch {
1203
- /* try next layout */
1204
- }
1205
- }
1206
- return undefined;
1207
- }
1208
- function getSnapshotPersistWorker() {
1209
- if (_snapshotWorkerDisabled)
1210
- return undefined;
1211
- if (_snapshotPersistWorker)
1212
- return _snapshotPersistWorker;
1213
- try {
1214
- const workerPath = resolveSnapshotPersistWorkerPath();
1215
- if (workerPath === undefined) {
1216
- handleSnapshotWorkerDeath("persist worker script not found in any layout");
1217
- return undefined;
1218
- }
1219
- const worker = new Worker(workerPath);
1220
- // The ForTests promotion seam wraps ONLY when set — the production path
1221
- // binds the sync handler directly, so scheduling is byte-identical when
1222
- // no test seam is installed (the async-handler variant of this shifted
1223
- // promotion timing under full-suite load and flaked the round-trip test).
1224
- worker.on("message", (result) => {
1225
- if (_snapshotPromotionSeamForTests) {
1226
- void _snapshotPromotionSeamForTests().then(() => handleSnapshotWorkerResult(result));
1227
- return;
1228
- }
1229
- handleSnapshotWorkerResult(result);
1230
- });
1231
- worker.on("error", (err) => handleSnapshotWorkerDeath(err.message));
1232
- worker.on("exit", (code) => {
1233
- if (_snapshotPersistWorker === worker)
1234
- _snapshotPersistWorker = undefined;
1235
- // Any body still queued when the worker exits was abandoned mid-flight
1236
- // (a crash, a `terminate()`, or host recycling) — it will never be
1237
- // promoted by this worker, so fall it back to the sync writer rather
1238
- // than let it vanish (honesty, #533). `terminate()` can report a 0
1239
- // exit code on some platforms, so this cannot key off `code !== 0`.
1240
- const stranded = [..._snapshotWorkerRequests.values()];
1241
- if (stranded.length > 0) {
1242
- _snapshotWorkerRequests.clear();
1243
- for (const pending of stranded) {
1244
- dispatchMainThreadWriteThroughSeam(pending, `persist worker exited with code ${code}`);
1245
- }
1246
- }
1247
- // Only an ABNORMAL exit disables respawning; a clean idle exit (nothing
1248
- // stranded) just drops the reference so the next persist respawns.
1249
- if (code !== 0)
1250
- _snapshotWorkerDisabled = true;
1251
- });
1252
- // #1148: adding a message listener refs the Worker's public MessagePort.
1253
- // Unref only after every listener is installed so it stays background-only.
1254
- worker.unref();
1255
- _snapshotPersistWorker = worker;
1256
- return worker;
1257
- }
1258
- catch (err) {
1259
- handleSnapshotWorkerDeath(err instanceof Error ? err.message : String(err));
1260
- return undefined;
1261
- }
1262
- }
1263
- // #950 review F3: a process that dies between a worker's staged write and its
1264
- // promotion leaves project-snapshot.json.gz.stage-<pid>-<gen> (and the worker's
1265
- // .tmp-<pid>) behind forever. Sweep leftovers from PRIOR processes once per
1266
- // cache dir; our own live stage files carry this pid and are skipped.
1267
- const _sweptSnapshotStageDirs = new Set();
1268
- function sweepStaleSnapshotStageFiles(cacheDir) {
1269
- if (_sweptSnapshotStageDirs.has(cacheDir))
1270
- return;
1271
- _sweptSnapshotStageDirs.add(cacheDir);
1272
- fs.readdir(cacheDir, (err, entries) => {
1273
- if (err)
1274
- return;
1275
- const ownMarker = `.stage-${process.pid}-`;
1276
- for (const entry of entries) {
1277
- if (!entry.startsWith("project-snapshot.json.gz.stage-"))
1278
- continue;
1279
- if (entry.includes(ownMarker))
1280
- continue;
1281
- fs.rm(path.join(cacheDir, entry), { force: true }, () => { });
1282
- }
1283
- });
1284
- }
1285
- // Flush any in-flight worker writes synchronously at process teardown so a body
1286
- // whose worker hasn't promoted yet isn't lost. Sync writes only (no child
1287
- // spawn — the teardown libuv hazard); best-effort.
1288
- let _snapshotExitHookInstalled = false;
1289
- function ensureSnapshotPersistExitHook() {
1290
- if (_snapshotExitHookInstalled)
1291
- return;
1292
- _snapshotExitHookInstalled = true;
1293
- process.once("exit", () => {
1294
- _snapshotExiting = true;
1295
- const latestByKey = new Map();
1296
- for (const pending of _snapshotWorkerRequests.values()) {
1297
- latestByKey.set(pending.key, pending);
1298
- }
1299
- for (const pending of _queuedSnapshotPersists.values()) {
1300
- const prior = latestByKey.get(pending.key);
1301
- // Queued work is later admission order. Equal-seq requests deliberately
1302
- // share a gate generation, so a tie must still select the queued payload.
1303
- if (!prior || prior.generation <= pending.generation) {
1304
- latestByKey.set(pending.key, pending);
1305
- }
1306
- }
1307
- _snapshotWorkerRequests.clear();
1308
- _queuedSnapshotPersists.clear();
1309
- _activeSnapshotPersists.clear();
1310
- for (const pending of latestByKey.values()) {
1311
- // Only the newest generation per key still matters; older ones are
1312
- // superseded and their stage files are swept on next launch.
1313
- if (_snapshotGenerationStates.get(pending.key)?.generation !==
1314
- pending.generation)
1315
- continue;
1316
- writeSnapshotBodyOnMainThread(pending, "exit_hook");
1317
- }
1318
- void _snapshotPersistWorker?.terminate();
1319
- });
1320
- }
1321
- export function saveProjectSnapshot(cwd, snapshot) {
1322
- const gzPath = getProjectSnapshotPath(cwd);
1323
- const legacyPath = getProjectSnapshotLegacyPath(cwd);
1324
- const metaPath = getProjectSnapshotMetaPath(cwd);
1325
- const cacheDir = path.dirname(gzPath);
1326
- const key = normalizeMapKey(cwd);
1327
- fs.mkdirSync(cacheDir, { recursive: true });
1328
- const baselines = snapshotPersistBaselinesFor(cwd, key);
1329
- const priorPersist = baselines.durable;
1330
- logSnapshotPersistDecision({
1331
- cwd,
1332
- seq: snapshot.seq,
1333
- decision: "requested",
1334
- });
1335
- if (_failedSnapshotPersists.delete(key)) {
1336
- logSnapshotPersistDecision({ cwd, seq: snapshot.seq, decision: "retry" });
1337
- }
1338
- // #958: for a new seq, meta is written FIRST and body SECOND. A crash or
1339
- // failure between the two writes can now only produce
1340
- // "meta already claims the new seq, body hasn't caught up yet" (the meta
1341
- // races ahead). The meta-first gate (isProjectSnapshotMetaStale) reads
1342
- // that as *fresh* and falls through to parsing the body, whose own
1343
- // embedded `seq` is still the old one, so `isProjectSnapshotFresh`
1344
- // correctly rejects it as stale on the body's own merits — one wasted
1345
- // parse, self-healing, no data lost. The OLD body-then-meta order could
1346
- // instead leave an old-seq meta sitting over a freshly written body,
1347
- // which the meta-first gate discards WITHOUT ever reading it — throwing
1348
- // away a genuinely fresh snapshot. That direction is not recoverable
1349
- // until the next save, so it's the one this reorder eliminates.
1350
- //
1351
- // The new-seq meta write stays synchronous and throwing. Same-seq work does
1352
- // not need to advance the freshness gate, so it leaves the current sidecar
1353
- // untouched until the worker has a semantic verdict. This prevents a stale
1354
- // local request from replacing a
1355
- // newer sibling process's same-seq fingerprint before it can coalesce.
1356
- if (priorPersist?.seq !== snapshot.seq) {
1357
- writeProjectSnapshotMeta(metaPath, snapshot);
1358
- }
1359
- // Record the authoritative in-process write BEFORE handing the body off, so
1360
- // a merge-read between now and the worker's promotion sees our own object
1361
- // (the on-disk body still holds the previous generation until promotion). The
1362
- // pre-write mtime is our baseline: while disk stays at it (or below), our
1363
- // object wins; a promotion or an external write moves past it. Baseline off
1364
- // the CURRENTLY-RESOLVED body — which is the legacy uncompressed
1365
- // `project-snapshot.json` in the one-release upgrade window before the first
1366
- // gz promotion — not gz-only: statting only gzPath there would leave the
1367
- // baseline at -Infinity, so the load gate (which resolves the legacy body's
1368
- // real, positive mtime) would reject our own fresh write and serve the stale
1369
- // legacy body to a merge-consumer, silently dropping this snapshot's fields.
1370
- const priorBody = resolveSnapshotBodyPath(cwd);
1371
- const knownMtime = priorBody ? priorBody.mtimeMs : Number.NEGATIVE_INFINITY;
1372
- const knownSize = priorBody ? priorBody.size : Number.NEGATIVE_INFINITY;
1373
- const authoritativeEntry = {
1374
- snapshot,
1375
- knownMtime,
1376
- knownSize,
1377
- lastUsedAt: Date.now(),
1378
- };
1379
- const previousAuthoritativeEntry = authoritativeSnapshots.get(key);
1380
- if (previousAuthoritativeEntry)
1381
- clearAuthoritativeSnapshotTimer(previousAuthoritativeEntry);
1382
- authoritativeSnapshots.set(key, authoritativeEntry);
1383
- scheduleAuthoritativeSnapshotEviction(key, authoritativeEntry);
1384
- enforceAuthoritativeSnapshotCap();
1385
- // A stale disk-parse-cache entry for this path must not out-vote the fresh
1386
- // authoritative write once the latter is dropped (oversized bodies).
1387
- snapshotParseCache.delete(gzPath);
1388
- const generationState = _snapshotGenerationStates.get(key);
1389
- const generation = generationState?.seq === snapshot.seq
1390
- ? generationState.generation
1391
- : (generationState?.generation ?? 0) + 1;
1392
- _snapshotGenerationStates.set(key, { generation, seq: snapshot.seq });
1393
- const stagePath = `${gzPath}.stage-${process.pid}-${generation}`;
1394
- const pending = {
1395
- key,
1396
- cwd,
1397
- gzPath,
1398
- legacyPath,
1399
- stagePath,
1400
- snapshot,
1401
- generation,
1402
- durablePersist: priorPersist,
1403
- dedupeFingerprints: baselines.fingerprints,
1404
- };
1405
- sweepStaleSnapshotStageFiles(cacheDir);
1406
- ensureSnapshotPersistExitHook();
1407
- if (_activeSnapshotPersists.has(key)) {
1408
- _queuedSnapshotPersists.set(key, pending);
1409
- logSnapshotPersistDecision({
1410
- cwd,
1411
- seq: snapshot.seq,
1412
- decision: "coalesced",
1413
- });
1414
- return;
1415
- }
1416
- dispatchSnapshotPersist(pending);
1417
- }
1418
- // --- Test hooks for the worker persist path ---------------------------------
1419
- /** Test-only: wait until worker requests have either landed or degraded. */
1420
- export async function waitForProjectSnapshotPersistsForTests() {
1421
- for (let attempts = 0; attempts < 200 &&
1422
- (_snapshotWorkerRequests.size > 0 ||
1423
- _activeSnapshotPersists.size > 0 ||
1424
- _queuedSnapshotPersists.size > 0); attempts++) {
1425
- await new Promise((resolve) => setTimeout(resolve, 10));
1426
- }
1427
- }
1428
- /** Test-only: force any in-flight worker body write to the sync main-thread path. */
1429
- export function flushProjectSnapshotPersistsForTests() {
1430
- const requests = [..._snapshotWorkerRequests.values()];
1431
- _snapshotWorkerRequests.clear();
1432
- for (const pending of requests) {
1433
- dispatchMainThreadWriteThroughSeam(pending, undefined);
1434
- }
1435
- }
1436
- /** Test-only: exercise the degraded worker-death path. */
1437
- export async function terminateProjectSnapshotPersistWorkerForTests() {
1438
- const worker = _snapshotPersistWorker;
1439
- if (worker)
1440
- await worker.terminate();
1441
- }
1442
- /** Test-only: restore worker creation + clear generation state after a deliberate death. */
1443
- export function resetProjectSnapshotPersistWorkerForTests() {
1444
- _snapshotWorkerDisabled = false;
1445
- _snapshotGenerationGateEnabledForTests = true;
1446
- _snapshotPromotionSeamForTests = undefined;
1447
- _snapshotPersistWorker = undefined;
1448
- _snapshotWorkerRequests.clear();
1449
- _snapshotGenerationStates.clear();
1450
- _successfulSnapshotPersists.clear();
1451
- _failedSnapshotPersists.clear();
1452
- _activeSnapshotPersists.clear();
1453
- _queuedSnapshotPersists.clear();
1454
- _snapshotExiting = false;
1455
- _snapshotWorkerBodyWritesForTests = 0;
1456
- _lastSnapshotPersistErrorForTests = undefined;
1457
- }
1458
- /** Test-only: expose bounded queue state without retaining snapshot bodies. */
1459
- export function getProjectSnapshotPersistStateForTests(cwd) {
1460
- const key = normalizeMapKey(cwd);
1461
- return {
1462
- active: _activeSnapshotPersists.has(key),
1463
- queued: _queuedSnapshotPersists.has(key),
1464
- successfulFingerprint: _successfulSnapshotPersists.get(key)?.fingerprint,
1465
- workerBodyWrites: _snapshotWorkerBodyWritesForTests,
1466
- };
1467
- }
1468
- /** Test-only mutation switch for proving the supersession invariant. */
1469
- export function setProjectSnapshotGenerationGateForTests(enabled) {
1470
- _snapshotGenerationGateEnabledForTests = enabled;
1471
- }
1472
- /** Test-only seam immediately before generation-gated promotion. */
1473
- export function setProjectSnapshotPromotionSeamForTests(seam) {
1474
- _snapshotPromotionSeamForTests = seam;
1475
- }
1476
- export function getProjectSnapshotPersistErrorForTests() {
1477
- return _lastSnapshotPersistErrorForTests;
1478
- }
1479
- // ── #2442 test-only seams: exercise the three BoundedFifoMap-backed caches ──
1480
- // through the exact same write path production uses (cacheParsedSnapshot /
1481
- // rememberSuccessfulSnapshotPersist's delete+set refresh, and a direct write
1482
- // mirroring recordSnapshotPersistFailure's), without the real gzip/worker
1483
- // persistence pipeline or a full ProjectSnapshot fixture.
1484
- /** Test-only: seed the parse cache exactly as `cacheParsedSnapshot` would. */
1485
- export function _seedSnapshotParseCacheForTests(key, entry) {
1486
- cacheParsedSnapshot(key, entry);
1487
- }
1488
- export function _snapshotParseCacheKeysForTests() {
1489
- return [...snapshotParseCache.keys()];
1490
- }
1491
- /**
1492
- * #2442 test-only: the exact `snapshotParseCache.get(key)` the production
1493
- * read at {@link loadProjectSnapshot}'s parse-cache hit performs. A `.has()`
1494
- * would not do — `.has()` reorders nothing on either bounded class, so a
1495
- * has-based test cannot tell FIFO from LRU, which is the axis these bounded
1496
- * tests exist to pin (#2442 review F4).
1497
- */
1498
- export function _snapshotParseCacheGetForTests(key) {
1499
- return snapshotParseCache.get(key) !== undefined;
1500
- }
1501
- /** Test-only: seed the successful-persist cache exactly as production would. */
1502
- export function _seedSuccessfulSnapshotPersistForTests(key, record) {
1503
- rememberSuccessfulSnapshotPersist(key, record);
1504
- }
1505
- export function _successfulSnapshotPersistKeysForTests() {
1506
- return [..._successfulSnapshotPersists.keys()];
1507
- }
1508
- /** #2442 test-only: the same `_successfulSnapshotPersists.get(key)` the
1509
- * persist-dedupe read and `getProjectSnapshotPersistStateForTests` perform.
1510
- * See {@link _snapshotParseCacheGetForTests} for why `.has()` will not do. */
1511
- export function _successfulSnapshotPersistGetForTests(key) {
1512
- return _successfulSnapshotPersists.get(key) !== undefined;
1513
- }
1514
- /** Test-only: seed the failed-persist cache with the same write
1515
- * `recordSnapshotPersistFailure` performs, without its side effects
1516
- * (deleteAuthoritativeSnapshot / logLatency) or a full PendingSnapshotBody. */
1517
- export function _seedFailedSnapshotPersistForTests(key, record) {
1518
- _failedSnapshotPersists.set(key, record);
1519
- }
1520
- export function _failedSnapshotPersistKeysForTests() {
1521
- return [..._failedSnapshotPersists.keys()];
1522
- }
1523
- export function buildProjectSnapshotFromRuntime(args) {
1524
- return {
1525
- version: PROJECT_SNAPSHOT_VERSION,
1526
- projectRoot: normalizeMapKey(path.resolve(args.cwd)),
1527
- generatedAt: new Date().toISOString(),
1528
- seq: args.runtime.projectSeq,
1529
- files: {},
1530
- symbols: {},
1531
- reverseDeps: {},
1532
- cachedExports: [...args.runtime.cachedExports.entries()].sort((a, b) => a[0].localeCompare(b[0])),
1533
- // #1019: capture the runtime's live sequence index AT this seq. The runtime
1534
- // is seeded from the change log at session start and bumped in lockstep with
1535
- // every append, so `getFileSeqEntries()` IS the fold of the log up to
1536
- // `projectSeq` — and its keys are already `normalizeMapKey(path.resolve())`,
1537
- // the exact form the change-log replay produces.
1538
- sequenceIndex: {
1539
- projectSeq: args.runtime.projectSeq,
1540
- fileSeqByPath: args.runtime.getFileSeqEntries(),
1541
- },
1542
- wordIndex: args.runtime.wordIndex
1543
- ? serializeWordIndex(args.runtime.wordIndex)
1544
- : undefined,
1545
- projectRulesScan: args.runtime.projectRulesScan,
1546
- startupScan: args.startupScan,
1547
- languageProfile: args.languageProfile,
1548
- conventions: args.conventions,
1549
- };
1550
- }
1551
- export function hydrateRuntimeFromProjectSnapshot(runtime, snapshot) {
1552
- runtime.cachedExports.clear();
1553
- for (const [name, filePath] of snapshot.cachedExports) {
1554
- runtime.cachedExports.set(name, filePath);
1555
- }
1556
- if (snapshot.projectRulesScan) {
1557
- runtime.projectRulesScan = snapshot.projectRulesScan;
1558
- }
1559
- runtime.wordIndex = deserializeWordIndex(snapshot.wordIndex);
1560
- }
1561
- /**
1562
- * #1785 F2/F3: additive counterpart to `hydrateRuntimeFromProjectSnapshot`
1563
- * for a LATE/retroactive hydration attempt — one that runs after other work
1564
- * may already have populated the runtime for real (e.g. quick mode's
1565
- * background warmup building a genuine `wordIndex`, docCount > 0). The
1566
- * unconditional version above is only safe for the FIRST hydration attempt,
1567
- * made before anything else has run: clearing `cachedExports` is correct
1568
- * there because there is nothing yet to destroy.
1569
- *
1570
- * A late call cannot make that assumption, and `cachedExports` and
1571
- * `projectRulesScan` are populated by INDEPENDENT tasks from whatever else is
1572
- * running (nothing else in quick mode touches either), so this guards each
1573
- * field on its OWN "nothing computed since" check rather than one
1574
- * all-or-nothing bail-out — the field a concurrent task actually populated is
1575
- * protected without needlessly withholding the other, still-idle field the
1576
- * snapshot could still supply. Returns whether it hydrated ANY field, so the
1577
- * caller can log honestly instead of claiming success when nothing changed.
1578
- *
1579
- * #1785 F5: takes ONLY the narrow `{ cachedExports, projectRulesScan }`
1580
- * shape (see `ProjectSnapshotExportsAndRules`) — deliberately no `wordIndex`
1581
- * parameter at all, not even an optional one. The retroactive path's
1582
- * captured/reloaded snapshot always comes from
1583
- * `loadProjectSnapshotExportsAndRules`, which never parses `wordIndex` in
1584
- * the first place (avoiding its dominant share of a full body parse's cost —
1585
- * see that function's doc comment for the measured numbers). This is also
1586
- * the right behavior, not just a performance shortcut: quick mode's warmup
1587
- * is the only thing that ever builds a `wordIndex` in this window, and F2's
1588
- * hazard was this exact late-hydration path nulling that live index from a
1589
- * disk copy that predated it — removing the parameter removes the hazard by
1590
- * construction instead of merely guarding against it at runtime.
1591
- */
1592
- export function hydrateRuntimeFromProjectSnapshotIfIdle(runtime, snapshot) {
1593
- let hydratedAnything = false;
1594
- if (runtime.cachedExports.size === 0 && snapshot.cachedExports.length > 0) {
1595
- runtime.cachedExports.clear();
1596
- for (const [name, filePath] of snapshot.cachedExports) {
1597
- runtime.cachedExports.set(name, filePath);
1598
- }
1599
- hydratedAnything = true;
1600
- }
1601
- if (!runtime.projectRulesScan.hasCustomRules &&
1602
- runtime.projectRulesScan.rules.length === 0 &&
1603
- snapshot.projectRulesScan) {
1604
- runtime.projectRulesScan = snapshot.projectRulesScan;
1605
- hydratedAnything = true;
1606
- }
1607
- return hydratedAnything;
1608
- }
1609
- export function saveRuntimeProjectSnapshot(args) {
1610
- try {
1611
- if (typeof args.runtime.projectSeq !== "number")
1612
- return;
1613
- const existing = loadProjectSnapshot(args.cwd);
1614
- let conventions = args.conventions ?? existing?.conventions;
1615
- if (!conventions) {
1616
- try {
1617
- conventions = detectProjectConventions(args.cwd);
1618
- }
1619
- catch (err) {
1620
- args.dbg?.(`project_snapshot: convention detection failed: ${err}`);
1621
- }
1622
- }
1623
- const snapshot = buildProjectSnapshotFromRuntime({
1624
- ...args,
1625
- startupScan: args.startupScan ?? existing?.startupScan,
1626
- languageProfile: args.languageProfile ?? existing?.languageProfile,
1627
- conventions,
1628
- });
1629
- if (existing) {
1630
- snapshot.files = existing.files ?? {};
1631
- snapshot.symbols = existing.symbols ?? {};
1632
- snapshot.reverseDeps = existing.reverseDeps ?? {};
1633
- // The word index is built by its own session task, which may not have
1634
- // finished when another task triggers a save — keep the prior index
1635
- // rather than clobbering it with undefined. #348: only carry it forward
1636
- // when `existing` was built AT THIS SAME seq — otherwise a stale
1637
- // snapshot's leftover index (already correctly rejected as stale by
1638
- // isProjectSnapshotFresh on load, seq mismatch) would get silently
1639
- // re-stamped with the CURRENT seq by this save, "laundering" a stale
1640
- // index into looking fresh before the word-index task even runs.
1641
- if (!snapshot.wordIndex &&
1642
- existing.wordIndex &&
1643
- existing.seq === snapshot.seq) {
1644
- snapshot.wordIndex = existing.wordIndex;
1645
- }
1646
- }
1647
- saveProjectSnapshot(args.cwd, snapshot);
1648
- args.dbg?.(`project_snapshot: saved seq=${snapshot.seq} exports=${snapshot.cachedExports.length}`);
1649
- }
1650
- catch (err) {
1651
- args.dbg?.(`project_snapshot: save failed: ${err}`);
1652
- }
1653
- }