@vibgrate/cli 2026.722.2 → 2026.727.2

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 (145) hide show
  1. package/DOCS.md +418 -213
  2. package/README.md +34 -8
  3. package/dist/baseline-TG4ATZGZ.js +8 -0
  4. package/dist/{baseline-BD3A7EXD.js.map → baseline-TG4ATZGZ.js.map} +1 -1
  5. package/dist/chunk-2MBL43EJ.js +82 -0
  6. package/dist/chunk-2MBL43EJ.js.map +1 -0
  7. package/dist/chunk-2XQDMLKB.js +465 -0
  8. package/dist/chunk-2XQDMLKB.js.map +1 -0
  9. package/dist/{chunk-PY3DNX5H.js → chunk-3Q7QBWFW.js} +13 -2
  10. package/dist/chunk-3Q7QBWFW.js.map +1 -0
  11. package/dist/chunk-3V24O47U.js +478 -0
  12. package/dist/chunk-3V24O47U.js.map +1 -0
  13. package/dist/chunk-5I4VSBWQ.js +764 -0
  14. package/dist/chunk-5I4VSBWQ.js.map +1 -0
  15. package/dist/{chunk-WNIIKCNF.js → chunk-6ABXHZRN.js} +59 -311
  16. package/dist/chunk-6ABXHZRN.js.map +1 -0
  17. package/dist/chunk-6AYDFFP5.js +136 -0
  18. package/dist/chunk-6AYDFFP5.js.map +1 -0
  19. package/dist/chunk-6UQMXIAG.js +122 -0
  20. package/dist/chunk-6UQMXIAG.js.map +1 -0
  21. package/dist/chunk-7N4Y3E47.js +108 -0
  22. package/dist/chunk-7N4Y3E47.js.map +1 -0
  23. package/dist/chunk-BPF3YX2U.js +64 -0
  24. package/dist/chunk-BPF3YX2U.js.map +1 -0
  25. package/dist/chunk-BWPBB45M.js +88 -0
  26. package/dist/chunk-BWPBB45M.js.map +1 -0
  27. package/dist/{chunk-6CXTPC74.js → chunk-CY4WKXB2.js} +27 -6
  28. package/dist/chunk-CY4WKXB2.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +10 -0
  30. package/dist/chunk-DGUM43GV.js.map +1 -0
  31. package/dist/{chunk-NONYJLOJ.js → chunk-EX4PQT6W.js} +3 -3
  32. package/dist/{chunk-NONYJLOJ.js.map → chunk-EX4PQT6W.js.map} +1 -1
  33. package/dist/chunk-IS7VTH2Q.js +627 -0
  34. package/dist/chunk-IS7VTH2Q.js.map +1 -0
  35. package/dist/chunk-IZDH67DX.js +289 -0
  36. package/dist/chunk-IZDH67DX.js.map +1 -0
  37. package/dist/chunk-J4RFRKZH.js +2496 -0
  38. package/dist/chunk-J4RFRKZH.js.map +1 -0
  39. package/dist/chunk-J7LKEB2R.js +51 -0
  40. package/dist/chunk-J7LKEB2R.js.map +1 -0
  41. package/dist/chunk-JIBOJTGS.js +313 -0
  42. package/dist/chunk-JIBOJTGS.js.map +1 -0
  43. package/dist/chunk-K3MZIVZW.js +88 -0
  44. package/dist/chunk-K3MZIVZW.js.map +1 -0
  45. package/dist/chunk-K7REHDQS.js +776 -0
  46. package/dist/chunk-K7REHDQS.js.map +1 -0
  47. package/dist/{chunk-2O5YZVZV.js → chunk-KCKYKDMS.js} +23 -19
  48. package/dist/chunk-KCKYKDMS.js.map +1 -0
  49. package/dist/{chunk-3MXNNBLI.js → chunk-KNELIQJO.js} +1647 -2042
  50. package/dist/chunk-KNELIQJO.js.map +1 -0
  51. package/dist/chunk-KSBHGWRV.js +613 -0
  52. package/dist/chunk-KSBHGWRV.js.map +1 -0
  53. package/dist/chunk-LKVMI67M.js +1695 -0
  54. package/dist/chunk-LKVMI67M.js.map +1 -0
  55. package/dist/chunk-NDMDSPFX.js +69 -0
  56. package/dist/chunk-NDMDSPFX.js.map +1 -0
  57. package/dist/{chunk-CS37OBE3.js → chunk-OFUC6RYN.js} +791 -783
  58. package/dist/chunk-OFUC6RYN.js.map +1 -0
  59. package/dist/chunk-OOIG3RUM.js +276 -0
  60. package/dist/chunk-OOIG3RUM.js.map +1 -0
  61. package/dist/chunk-PMYWZRRS.js +62 -0
  62. package/dist/chunk-PMYWZRRS.js.map +1 -0
  63. package/dist/chunk-PXHNTC6D.js +382 -0
  64. package/dist/chunk-PXHNTC6D.js.map +1 -0
  65. package/dist/{chunk-I7GY7MVN.js → chunk-RNP3SMTV.js} +60 -12
  66. package/dist/chunk-RNP3SMTV.js.map +1 -0
  67. package/dist/chunk-TCDAZZNP.js +843 -0
  68. package/dist/chunk-TCDAZZNP.js.map +1 -0
  69. package/dist/{chunk-5BDHQ7DD.js → chunk-WGUL45AV.js} +24 -17
  70. package/dist/chunk-WGUL45AV.js.map +1 -0
  71. package/dist/cli.d.ts +3 -0
  72. package/dist/cli.js +3373 -617
  73. package/dist/cli.js.map +1 -1
  74. package/dist/execution-env-ZU45JZ4G.js +4 -0
  75. package/dist/execution-env-ZU45JZ4G.js.map +1 -0
  76. package/dist/federation-SZWZIFZ7.js +7 -0
  77. package/dist/federation-SZWZIFZ7.js.map +1 -0
  78. package/dist/{fs-IPY4FJKH.js → fs-B5HZ2MIU.js} +3 -2
  79. package/dist/fs-B5HZ2MIU.js.map +1 -0
  80. package/dist/{fs-KCABDURV.js → fs-O5IQYXHO.js} +3 -2
  81. package/dist/fs-O5IQYXHO.js.map +1 -0
  82. package/dist/git-ref-XDXB6JP5.js +4 -0
  83. package/dist/git-ref-XDXB6JP5.js.map +1 -0
  84. package/dist/graph-backend-73URGTFY.js +11 -0
  85. package/dist/graph-backend-73URGTFY.js.map +1 -0
  86. package/dist/index.d.ts +472 -137
  87. package/dist/index.js +15 -7
  88. package/dist/index.js.map +1 -1
  89. package/dist/{interactive-A4DISSIW.js → interactive-372NLI5C.js} +186 -226
  90. package/dist/interactive-372NLI5C.js.map +1 -0
  91. package/dist/llm-host-7GWDO6IX.js +9 -0
  92. package/dist/llm-host-7GWDO6IX.js.map +1 -0
  93. package/dist/load-I333TGNI.js +8 -0
  94. package/dist/load-I333TGNI.js.map +1 -0
  95. package/dist/local-runtime-5O2NN3GA.js +5 -0
  96. package/dist/local-runtime-5O2NN3GA.js.map +1 -0
  97. package/dist/mcp-tools-I7JK3S2M.js +4 -0
  98. package/dist/{mcp-tools-I6PME3AV.js.map → mcp-tools-I7JK3S2M.js.map} +1 -1
  99. package/dist/model-execution-profile-TFBKCNJG.js +4 -0
  100. package/dist/model-execution-profile-TFBKCNJG.js.map +1 -0
  101. package/dist/model-orchestrator-TVONAUPS.js +9 -0
  102. package/dist/model-orchestrator-TVONAUPS.js.map +1 -0
  103. package/dist/parse-worker.d.ts +1 -1
  104. package/dist/parse-worker.js +2 -1
  105. package/dist/parse-worker.js.map +1 -1
  106. package/dist/paths-2RAH3GME.js +6 -0
  107. package/dist/paths-2RAH3GME.js.map +1 -0
  108. package/dist/resolve-gguf-VPL4YQ6J.js +8 -0
  109. package/dist/resolve-gguf-VPL4YQ6J.js.map +1 -0
  110. package/dist/runtime-session-JRKCQUHY.js +18 -0
  111. package/dist/runtime-session-JRKCQUHY.js.map +1 -0
  112. package/dist/session-ITPYQ5XI.js +11 -0
  113. package/dist/{session-POJUDFPH.js.map → session-ITPYQ5XI.js.map} +1 -1
  114. package/dist/session-store-WFBX7HXL.js +4 -0
  115. package/dist/{session-store-W5RZZHA3.js.map → session-store-WFBX7HXL.js.map} +1 -1
  116. package/dist/{stream-json-Q2JGWPHB.js → stream-json-SLMDKLXP.js} +17 -6
  117. package/dist/stream-json-SLMDKLXP.js.map +1 -0
  118. package/dist/{types-Jl6RJ175.d.ts → types-7AHBUbFm.d.ts} +8 -2
  119. package/dist/ui-Q6DJ3GCU.js +5 -0
  120. package/dist/ui-Q6DJ3GCU.js.map +1 -0
  121. package/dist/vgd-7JV5KCNJ.js +17 -0
  122. package/dist/vgd-7JV5KCNJ.js.map +1 -0
  123. package/package.json +9 -6
  124. package/dist/baseline-BD3A7EXD.js +0 -7
  125. package/dist/chunk-2O5YZVZV.js.map +0 -1
  126. package/dist/chunk-3MXNNBLI.js.map +0 -1
  127. package/dist/chunk-5BDHQ7DD.js.map +0 -1
  128. package/dist/chunk-6CXTPC74.js.map +0 -1
  129. package/dist/chunk-CS37OBE3.js.map +0 -1
  130. package/dist/chunk-GGJZA3Q6.js +0 -961
  131. package/dist/chunk-GGJZA3Q6.js.map +0 -1
  132. package/dist/chunk-I7GY7MVN.js.map +0 -1
  133. package/dist/chunk-JBXNQCGE.js +0 -484
  134. package/dist/chunk-JBXNQCGE.js.map +0 -1
  135. package/dist/chunk-PY3DNX5H.js.map +0 -1
  136. package/dist/chunk-WNIIKCNF.js.map +0 -1
  137. package/dist/fs-IPY4FJKH.js.map +0 -1
  138. package/dist/fs-KCABDURV.js.map +0 -1
  139. package/dist/interactive-A4DISSIW.js.map +0 -1
  140. package/dist/mcp-tools-I6PME3AV.js +0 -3
  141. package/dist/session-POJUDFPH.js +0 -6
  142. package/dist/session-store-W5RZZHA3.js +0 -3
  143. package/dist/stream-json-Q2JGWPHB.js.map +0 -1
  144. package/dist/ui-HOVOPWMX.js +0 -4
  145. package/dist/ui-HOVOPWMX.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/lock.ts","../src/engine/embeddings.ts","../src/engine/relations.ts","../src/engine/query.ts","../src/engine/impact.ts"],"names":["fs","path","text","round"],"mappings":";;;;;;;;AAWO,IAAM,qBAAA,GAAwB,KAAK,EAAA,GAAK,GAAA;AAE/C,SAAS,eAAe,GAAA,EAAsB;AAC5C,EAAA,IAAI;AACF,IAAA,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAC,CAAA;AACnB,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,CAAA,EAAG;AACV,IAAA,OAAQ,EAA4B,IAAA,KAAS,OAAA;AAAA,EAC/C;AACF;AAEA,SAAS,WAAA,CAAY,MAAc,OAAA,EAA0B;AAC3D,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,KAAK,EAAA,EAAG,GAAI,KAAK,KAAA,CAASA,GAAA,CAAA,YAAA,CAAa,IAAA,EAAM,MAAM,CAAC,CAAA;AAC5D,IAAA,IAAI,OAAO,OAAO,QAAA,IAAY,IAAA,CAAK,KAAI,GAAI,EAAA,GAAK,SAAS,OAAO,IAAA;AAChE,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,CAAC,cAAA,CAAe,GAAG,GAAG,OAAO,IAAA;AAC5D,IAAA,OAAO,KAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGO,SAAS,WAAA,CAAY,IAAA,EAAc,OAAA,GAAU,qBAAA,EAAgC;AAClF,EAAA,MAAM,QAAQ,MAAe;AAC3B,IAAA,IAAI;AACF,MAAGA,cAAeC,KAAA,CAAA,OAAA,CAAQ,IAAI,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AACpD,MAAA,MAAM,EAAA,GAAQD,GAAA,CAAA,QAAA,CAAS,IAAA,EAAM,IAAI,CAAA;AACjC,MAAGA,GAAA,CAAA,aAAA,CAAc,EAAA,EAAI,IAAA,CAAK,SAAA,CAAU,EAAE,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,EAAA,EAAI,IAAA,CAAK,GAAA,EAAI,EAAG,CAAC,CAAA;AACzE,MAAGA,cAAU,EAAE,CAAA;AACf,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF,CAAA;AACA,EAAA,IAAI,KAAA,IAAS,OAAO,IAAA;AACpB,EAAA,IAAI,WAAA,CAAY,IAAA,EAAM,OAAO,CAAA,EAAG;AAC9B,IAAA,IAAI;AACF,MAAGA,GAAA,CAAA,MAAA,CAAO,IAAA,EAAM,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,IACjC,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,OAAO,KAAA,EAAM;AAAA,EACf;AACA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,YAAY,IAAA,EAAoB;AAC9C,EAAA,IAAI;AACF,IAAGA,GAAA,CAAA,MAAA,CAAO,IAAA,EAAM,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;ACnBO,SAAS,kBAAkB,KAAA,EAAwB;AACxD,EAAA,OAAO,KAAA,IAAS,mBAAA;AAClB;AAUO,SAAS,aAAA,GAAwB;AACtC,EAAA,MAAM,OAAO,OAAA,CAAQ,GAAA,CAAI,kBAAuB,KAAA,CAAA,IAAA,CAAQ,EAAA,CAAA,OAAA,IAAW,QAAQ,CAAA;AAC3E,EAAA,OAAY,KAAA,CAAA,IAAA,CAAK,IAAA,EAAM,UAAA,EAAY,QAAQ,CAAA;AAC7C;AAGA,SAAS,iBAAiB,OAAA,EAAyB;AACjD,EAAA,OAAY,WAAK,aAAA,EAAc,EAAG,UAAU,IAAA,CAAK,OAAO,CAAC,CAAA,CAAE,CAAA;AAC7D;AAOO,SAAS,YAAA,CAAa,OAAA,GAAU,iBAAA,EAAkB,EAAY;AACnE,EAAA,OAAU,GAAA,CAAA,UAAA,CAAW,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAChD;AAOO,SAAS,mBAAmB,MAAA,EAAkC;AACnE,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,eAAA;AACH,MAAA,OAAO,CAAA,kDAAA,EAAqD,eAAe,CAAA,gNAAA,CAAA;AAAA,IAC7E,KAAK,iBAAA;AACH,MAAA,OAAO,CAAA,0LAAA,CAAA;AAAA,IACT,KAAK,eAAA;AACH,MAAA,OAAO,CAAA,oFAAA,CAAA;AAAA,IACT,KAAK,aAAA;AAAA,IACL;AACE,MAAA,OAAO,CAAA,kEAAA,CAAA;AAAA;AAEb;AASO,SAAS,cAAA,CAAe,OAAA,GAAU,iBAAA,EAAkB,EAAmB;AAC5E,EAAA,MAAM,MAAM,aAAA,EAAc;AAC1B,EAAA,OAAO,EAAE,GAAA,EAAK,OAAA,EAAS,YAAA,CAAa,OAAO,CAAA,IAAQ,GAAA,CAAA,UAAA,CAAW,GAAG,CAAA,EAAG,KAAA,EAAO,OAAA,CAAQ,GAAG,CAAA,EAAE;AAC1F;AAGO,SAAS,eAAA,GAA0B;AACxC,EAAA,MAAM,MAAM,aAAA,EAAc;AAC1B,EAAA,MAAM,KAAA,GAAQ,QAAQ,GAAG,CAAA;AACzB,EAAA,IAAI;AACF,IAAG,WAAO,GAAA,EAAK,EAAE,WAAW,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,EACjD,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,QAAQ,GAAA,EAAqB;AACpC,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAa,GAAA,CAAA,WAAA,CAAY,GAAA,EAAK,EAAE,aAAA,EAAe,MAAM,CAAA;AAAA,EACvD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,MAAM,CAAA,GAAS,KAAA,CAAA,IAAA,CAAK,GAAA,EAAK,CAAA,CAAE,IAAI,CAAA;AAC/B,IAAA,IAAI,CAAA,CAAE,WAAA,EAAY,EAAG,KAAA,IAAS,QAAQ,CAAC,CAAA;AAAA,SAClC;AACH,MAAA,IAAI;AACF,QAAA,KAAA,IAAY,GAAA,CAAA,QAAA,CAAS,CAAC,CAAA,CAAE,IAAA;AAAA,MAC1B,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,kBAAkB,CAAA,EAAqB;AAC9C,EAAA,MAAM,OAAQ,CAAA,EAAyC,IAAA;AACvD,EAAA,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,OAAA,IAAW,IAAA,KAAS,OAAA;AAC3D;AAOO,SAAS,gBAAA,CAAiB,MAAc,OAAA,EAA0B;AACvE,EAAA,OAAU,GAAA,CAAA,UAAA,CAAgB,KAAA,CAAA,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG,cAAc,IAAA,CAAK,OAAO,CAAC,CAAA,KAAA,CAAO,CAAC,CAAA;AACpF;AAOA,eAAsB,YAAA,CAAa,OAAA,GAA+B,EAAC,EAA6B;AAG9F,EAAA,IAAI,OAAA,CAAQ,OAAO,OAAO,IAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,iBAAA,CAAkB,OAAA,CAAQ,KAAK,CAAA;AAE/C,EAAA,IAAI,QAAQ,UAAA,IAAc,CAAC,YAAA,CAAa,OAAO,GAAG,OAAO,IAAA;AACzD,EAAA,MAAM,IAAA,GAAO,CAAC,MAAA,KAAmC;AAC/C,IAAA,OAAA,CAAQ,gBAAgB,MAAM,CAAA;AAC9B,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAIA,EAAA,MAAM,GAAA,GAAW,MAAM,kBAAA,EAAmB;AAC1C,EAAA,IAAI,CAAC,GAAA,EAAK,aAAA,EAAe,OAAO,KAAK,eAAe,CAAA;AAEpD,EAAA,MAAM,QAAQ,aAAA,EAAc;AAC5B,EAAA,IAAI;AACF,IAAG,GAAA,CAAA,SAAA,CAAU,KAAA,EAAO,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,EACzC,SAAS,CAAA,EAAG;AACV,IAAA,OAAO,IAAA,CAAK,iBAAA,CAAkB,CAAC,CAAA,GAAI,kBAAkB,aAAa,CAAA;AAAA,EACpE;AAEA,EAAA,IAAI;AAMF,IAAA,MAAM,QAAa,MAAM,WAAA;AAAA,MACvB,GAAA,CAAI,cAAc,IAAA,CAAK;AAAA,QACrB,KAAA,EAAO,QAAA,CAAS,GAAA,EAAK,OAAO,CAAA;AAAA,QAC5B,QAAA,EAAU,KAAA;AAAA,QACV,oBAAA,EAAsB,QAAQ,oBAAA,IAAwB;AAAA,OACvD,CAAA;AAAA,MACD,kBAAA,EAAmB;AAAA,MACnB;AAAA,KACF;AAEA,IAAA,IAAI;AACF,MAAG,GAAA,CAAA,aAAA,CAAc,iBAAiB,OAAO,CAAA,EAAA,qBAAO,IAAA,CAAK,CAAC,CAAA,EAAE,WAAA,EAAa,CAAA;AAAA,IACvE,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,OAAA;AAAA,MACJ,MAAM,MAAM,KAAA,EAAO;AACjB,QAAA,MAAM,MAAkB,EAAC;AACzB,QAAA,WAAA,MAAiB,KAAA,IAAS,KAAA,CAAM,KAAA,CAAM,KAAA,EAAO,EAAE,CAAA,EAAG;AAChD,UAAA,KAAA,MAAW,KAAK,KAAA,EAAO,GAAA,CAAI,KAAK,KAAA,CAAM,IAAA,CAAK,CAAsB,CAAC,CAAA;AAAA,QACpE;AACA,QAAA,OAAO,GAAA;AAAA,MACT,CAAA;AAAA,MACA,MAAM,WAAW,IAAA,EAAM;AACrB,QAAA,MAAM,CAAA,GAAI,MAAM,KAAA,CAAM,UAAA,CAAW,IAAI,CAAA;AACrC,QAAA,OAAO,KAAA,CAAM,KAAK,CAAsB,CAAA;AAAA,MAC1C;AAAA,KACF;AAAA,EACF,SAAS,CAAA,EAAG;AACV,IAAA,OAAO,IAAA,CAAK,iBAAA,CAAkB,CAAC,CAAA,GAAI,kBAAkB,iBAAiB,CAAA;AAAA,EACxE;AACF;AAWA,eAAe,kBAAA,GAAmC;AAChD,EAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI,sBAAA;AAC5B,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,aAAA,CAAmB,KAAA,CAAA,IAAA,CAAK,OAAA,EAAS,cAAc,CAAC,CAAA;AAC5D,MAAA,MAAM,GAAA,GAAW,MAAM,OAAO,aAAA,CAAc,IAAI,OAAA,CAAQ,WAAW,CAAC,CAAA,CAAE,IAAA,CAAA;AAEtE,MAAA,MAAM,QAAA,GAAW,GAAA,EAAK,aAAA,GAAgB,GAAA,GAAM,GAAA,EAAK,OAAA;AACjD,MAAA,IAAI,QAAA,EAAU,eAAe,OAAO,QAAA;AAAA,IACtC,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,MAAM,OAAO,WAAqB,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAC7D;AAGA,SAAS,kBAAA,GAA6B;AACpC,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,mBAAmB,CAAA;AAChD,EAAA,OAAO,OAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,GAAI,IAAI,CAAA,GAAI,GAAA;AAC3C;AAGA,eAAsB,WAAA,CAAe,OAAA,EAAqB,EAAA,EAAY,OAAA,EAA6B;AACjG,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,QAAQ,IAAA,CAAK;AAAA,MACxB,OAAA;AAAA,MACA,IAAI,OAAA,CAAe,CAAC,CAAA,EAAG,MAAA,KAAW;AAChC,QAAA,KAAA,GAAQ,UAAA,CAAW,MAAM,MAAA,CAAO,IAAI,MAAM,OAAO,CAAC,GAAG,EAAE,CAAA;AACvD,QAAA,KAAA,CAAM,KAAA,IAAQ;AAAA,MAChB,CAAC;AAAA,KACF,CAAA;AAAA,EACH,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB;AACF;AAEA,SAAS,QAAA,CAAS,KAAU,EAAA,EAAqB;AAC/C,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,cAAA,IAAkB,EAAC;AACjC,EAAA,IAAI,YAAA,CAAa,KAAK,EAAE,CAAA,SAAU,CAAA,CAAE,aAAA,IAAiB,EAAE,UAAA,IAAc,EAAA;AACrE,EAAA,IAAI,YAAY,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,EAAE,YAAA,IAAgB,EAAA;AACnD,EAAA,IAAI,cAAc,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,EAAE,aAAA,IAAiB,EAAA;AACtD,EAAA,OAAO,EAAA;AACT;AAGA,IAAM,UAAA,uBAAiB,GAAA,CAAI;AAAA,EACzB,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,KAAA;AAAA,EAAO,OAAA;AAAA,EAAS,MAAA;AAAA,EACtE,UAAA;AAAA,EAAY,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,WAAA;AAAA,EAAa,MAAA;AAAA,EAAQ,cAAA;AAAA,EAAgB,UAAA;AAAA,EACzE,KAAA;AAAA,EAAO,SAAA;AAAA,EAAW,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO;AAClD,CAAC,CAAA;AAGD,SAAS,YAAY,IAAA,EAAsB;AACzC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC5B,EAAA,MAAM,QAAQ,KAAA,CAAM,GAAA,MAAS,EAAA,EAAI,OAAA,CAAQ,YAAY,EAAE,CAAA;AACvD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,IAAK,CAAC,UAAA,CAAW,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAC,CAAA;AACtE,EAAA,OAAO,CAAC,GAAG,IAAA,CAAK,KAAA,CAAM,EAAE,CAAA,EAAG,IAAI,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC3D;AAYO,SAAS,aAAA,CAAc,MAAiB,SAAA,EAA4B;AACzE,EAAA,IAAI,IAAA,CAAK,SAAS,UAAA,EAAY;AAC5B,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA,IAAa,UAAA,EAAY,OAAA,CAAQ,cAAc,EAAE,CAAA;AAExE,IAAA,MAAM,aAAA,GAAwC;AAAA,MAC5C,QAAA,EAAU,4DAAA;AAAA,MACV,MAAA,EAAQ,0CAAA;AAAA,MACR,OAAA,EAAS,uDAAA;AAAA,MACT,EAAA,EAAI,2EAAA;AAAA,MACJ,cAAA,EAAgB,+DAAA;AAAA,MAChB,cAAA,EAAgB,uDAAA;AAAA,MAChB,aAAA,EAAe,iDAAA;AAAA,MACf,SAAA,EAAW,2CAAA;AAAA,MACX,KAAA,EAAO,uEAAA;AAAA,MACP,aAAA,EAAe,sDAAA;AAAA,MACf,QAAA,EAAU;AAAA,KACZ;AACA,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,QAAQ,CAAA,IAAK,QAAA;AACxC,IAAA,OAAO;AAAA,MACL,IAAA,CAAK,aAAA;AAAA,MACL,UAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA;AAAA,MACA,WAAA,CAAY,KAAK,IAAI,CAAA;AAAA,MAAA,CACpB,IAAA,CAAK,GAAA,IAAO,EAAA,EAAI,KAAA,CAAM,GAAG,GAAI;AAAA,KAChC,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,IAAI,CAAA;AAAA,EACd;AACA,EAAA,OAAO,CAAC,KAAK,aAAA,EAAe,IAAA,CAAK,MAAM,IAAA,CAAK,SAAA,IAAa,EAAA,EAAI,IAAA,CAAK,GAAA,IAAO,EAAA,EAAI,YAAY,IAAA,CAAK,IAAI,GAAG,SAAA,IAAa,EAAE,EACjH,MAAA,CAAO,OAAO,CAAA,CACd,IAAA,CAAK,GAAG,CAAA;AACb;AAEO,SAAS,MAAA,CAAO,GAAa,CAAA,EAAqB;AACvD,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,EAAE,MAAM,CAAA;AACrC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,GAAA,IAAO,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AACjB,IAAA,EAAA,IAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAChB,IAAA,EAAA,IAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,EAClB;AACA,EAAA,IAAI,EAAA,KAAO,CAAA,IAAK,EAAA,KAAO,CAAA,EAAG,OAAO,CAAA;AACjC,EAAA,OAAO,OAAO,IAAA,CAAK,IAAA,CAAK,EAAE,CAAA,GAAI,IAAA,CAAK,KAAK,EAAE,CAAA,CAAA;AAC5C;AAWA,IAAM,WAAA,GAAc,GAAA;AAEpB,IAAM,uBAAA,GAA0B,IAAA;AAEhC,SAAS,eAAA,CAAgB,MAAc,OAAA,EAAyB;AAC9D,EAAA,OAAY,KAAA,CAAA,IAAA,CAAK,SAAS,IAAI,CAAA,EAAG,cAAc,IAAA,CAAK,OAAO,CAAC,CAAA,KAAA,CAAO,CAAA;AACrE;AAOO,SAAS,YAAA,CAAa,KAAA,EAAgB,IAAA,EAAc,OAAA,EAAyB;AAClF,EAAA,MAAM,UAAU,gBAAA,CAAiB,eAAA,CAAgB,IAAA,EAAM,OAAO,GAAG,OAAO,CAAA;AACxE,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,KAAA,CAAM,MAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAA,CAAE,KAAK,CAAU,CAAC,CAAA;AAC1E,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,MAAW,CAAA,IAAK,MAAM,KAAA,EAAO;AAE3B,IAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,IAAU,CAAA,CAAE,SAAS,UAAA,EAAY;AAChD,IAAA,MAAM,CAAA,GAAI,WAAW,aAAA,CAAc,CAAA,EAAG,UAAU,GAAA,CAAI,CAAA,CAAE,IAAI,CAAC,CAAC,CAAA;AAC5D,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,CAAA,CAAE,EAAE,CAAA;AAC3B,IAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,IAAA,KAAS,CAAA,EAAG,OAAA,EAAA;AAAA,EACpC;AACA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,gBAAA,CAAiB,MAAc,OAAA,EAAwC;AAC9E,EAAA,IAAI,CAAI,GAAA,CAAA,UAAA,CAAW,IAAI,CAAA,SAAU,EAAC;AAClC,EAAA,IAAI;AACF,IAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAS,GAAA,CAAA,YAAA,CAAa,IAAA,EAAM,MAAM,CAAC,CAAA;AACvD,IAAA,IAAI,OAAO,KAAA,KAAU,OAAA,IAAW,MAAA,CAAO,OAAA,SAAgB,MAAA,CAAO,OAAA;AAAA,EAChE,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,EAAC;AACV;AAYA,eAAsB,iBAAA,CACpB,KAAA,EACA,QAAA,EACA,IAAA,EACA,UAAA,EACgC;AAChC,EAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,IAAA,EAAM,QAAA,CAAS,EAAE,CAAA;AAC9C,EAAA,IAAI,QAAoB,EAAE,KAAA,EAAO,SAAS,EAAA,EAAI,OAAA,EAAS,EAAC,EAAE;AAC1D,EAAA,IAAO,GAAA,CAAA,UAAA,CAAW,IAAI,CAAA,EAAG;AACvB,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAS,GAAA,CAAA,YAAA,CAAa,IAAA,EAAM,MAAM,CAAC,CAAA;AACvD,MAAA,IAAI,OAAO,KAAA,KAAU,QAAA,CAAS,EAAA,IAAM,MAAA,CAAO,SAAS,KAAA,GAAQ,MAAA;AAAA,IAC9D,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,KAAA,CAAM,MAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAA,CAAE,KAAK,CAAU,CAAC,CAAA;AAE1E,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,MAAA,IAAU,CAAA,CAAE,IAAA,KAAS,UAAU,CAAA;AACpF,EAAA,MAAM,UAAwD,EAAC;AAC/D,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAsB;AAC1C,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,MAAM,OAAO,aAAA,CAAc,CAAA,EAAG,UAAU,GAAA,CAAI,CAAA,CAAE,IAAI,CAAC,CAAA;AACnD,IAAA,MAAM,CAAA,GAAI,WAAW,IAAI,CAAA;AACzB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,EAAE,CAAA;AACjC,IAAA,IAAI,MAAA,IAAU,OAAO,IAAA,KAAS,CAAA,UAAW,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,MAAA,CAAO,GAAG,CAAA;AAAA,SACxD,OAAA,CAAQ,KAAK,EAAE,EAAA,EAAI,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAM,CAAA,EAAG,CAAA;AAAA,EAC/C;AAGA,EAAA,MAAM,UAAU,MAAY;AAC1B,IAAA,IAAI;AACF,MAAG,cAAU,QAAA,CAAS,IAAI,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAChD,MAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAI,CAAA,KAAA,EAAQ,QAAQ,GAAG,CAAA,CAAA;AACtC,MAAG,GAAA,CAAA,aAAA,CAAc,GAAA,EAAK,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAC3C,MAAG,GAAA,CAAA,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IACzB,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAIlB,IAAA,MAAM,IAAA,GAAO,GAAG,IAAI,CAAA,KAAA,CAAA;AACpB,IAAA,IAAI,CAAC,WAAA,CAAY,IAAI,CAAA,EAAG,OAAO,OAAA;AAC/B,IAAA,IAAI;AACF,MAAA,UAAA,GAAa,CAAA,EAAG,QAAQ,MAAM,CAAA;AAC9B,MAAA,IAAI,SAAA,GAAY,KAAK,GAAA,EAAI;AACzB,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,MAAA,EAAQ,KAAK,WAAA,EAAa;AACpD,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,IAAI,WAAW,CAAA;AAC9C,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,KAAA,CAAM,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAC1D,QAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACtB,UAAA,MAAM,GAAA,GAAM,IAAA,CAAK,CAAC,CAAA,IAAK,EAAC;AACxB,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,GAAG,CAAA;AACrB,UAAA,KAAA,CAAM,OAAA,CAAQ,EAAE,EAAE,CAAA,GAAI,EAAE,IAAA,EAAM,CAAA,CAAE,MAAM,GAAA,EAAI;AAAA,QAC5C,CAAC,CAAA;AACD,QAAA,UAAA,GAAa,IAAA,CAAK,IAAI,CAAA,GAAI,WAAA,EAAa,QAAQ,MAAM,CAAA,EAAG,QAAQ,MAAM,CAAA;AAEtE,QAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,IAAa,uBAAA,EAAyB;AACrD,UAAA,OAAA,EAAQ;AACR,UAAA,SAAA,GAAY,KAAK,GAAA,EAAI;AAAA,QACvB;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAC,CAAA;AAC7C,MAAA,KAAA,MAAW,EAAA,IAAM,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,EAAG,IAAI,CAAC,IAAA,CAAK,IAAI,EAAE,CAAA,EAAG,OAAO,KAAA,CAAM,QAAQ,EAAE,CAAA;AACvF,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA,SAAE;AACA,MAAA,WAAA,CAAY,IAAI,CAAA;AAAA,IAClB;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,KAAK,EAAA,EAAoB;AAChC,EAAA,OAAO,EAAA,CAAG,OAAA,CAAQ,gBAAA,EAAkB,GAAG,CAAA;AACzC;;;ACteO,IAAM,aAAN,MAAiB;AAAA,EAKtB,YAAqB,KAAA,EAAgB;AAAhB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACnB,IAAA,KAAA,MAAW,CAAA,IAAK,MAAM,KAAA,EAAO,IAAA,CAAK,SAAS,GAAA,CAAI,CAAA,CAAE,IAAI,CAAC,CAAA;AACtD,IAAA,KAAA,MAAW,CAAA,IAAK,MAAM,KAAA,EAAO;AAC3B,MAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,CAAA,CAAE,GAAA,EAAK,CAAC,CAAA;AAC3B,MAAA,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,GAAA,EAAK,CAAC,CAAA;AAAA,IAC5B;AAAA,EACF;AAAA,EANqB,KAAA;AAAA,EAJZ,QAAA,uBAAe,GAAA,EAAuB;AAAA,EACvC,OAAA,uBAAc,GAAA,EAAyB;AAAA,EACvC,MAAA,uBAAa,GAAA,EAAyB;AAAA,EAU9C,GAAA,CAAI,IAAY,IAAA,EAA8B;AAC5C,IAAA,MAAM,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,KAAK,EAAC;AACrC,IAAA,OAAO,IAAA,GAAO,IAAI,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,IAAI,CAAA,GAAI,GAAA;AAAA,EACrD;AAAA,EAEA,EAAA,CAAG,IAAY,IAAA,EAA8B;AAC3C,IAAA,MAAM,MAAM,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,EAAE,KAAK,EAAC;AACpC,IAAA,OAAO,IAAA,GAAO,IAAI,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,IAAI,CAAA,GAAI,GAAA;AAAA,EACrD;AAAA,EAEA,KAAK,EAAA,EAAmC;AACtC,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAQ,EAAA,EAAoD;AAC1D,IAAA,OAAO,IAAA,CAAK,eAAe,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA,CAAE,MAAA,CAAO,WAAW,CAAA,EAAG,KAAK,CAAA;AAAA,EACpE;AAAA;AAAA,EAGA,QAAQ,EAAA,EAAoD;AAC1D,IAAA,OAAO,IAAA,CAAK,eAAe,IAAA,CAAK,EAAA,CAAG,EAAE,CAAA,CAAE,MAAA,CAAO,WAAW,CAAA,EAAG,KAAK,CAAA;AAAA,EACnE;AAAA,EAEQ,cAAA,CAAe,OAAoB,GAAA,EAAoB;AAC7D,IAAA,MAAM,MAA8C,EAAC;AACrD,IAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,MAAA,MAAM,OAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,GAAG,CAAC,CAAA;AACrC,MAAA,IAAI,MAAM,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,CAAA,EAAG,MAAM,CAAA;AAAA,IACtC;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACF;AAEA,IAAM,8BAAqC,IAAI,GAAA,CAAI,CAAC,MAAA,EAAQ,YAAY,CAAC,CAAA;AACzE,SAAS,YAAY,CAAA,EAAuB;AAC1C,EAAA,OAAO,WAAA,CAAY,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA;AAC/B;AAEA,SAAS,IAAA,CAAK,GAAA,EAA+B,GAAA,EAAa,KAAA,EAAwB;AAChF,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AACxB,EAAA,IAAI,IAAA,EAAM,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA;AAAA,OACpB,GAAA,CAAI,GAAA,CAAI,GAAA,EAAK,CAAC,KAAK,CAAC,CAAA;AAC3B;AAoBA,IAAM,WAAA,uBAAkB,OAAA,EAA6B;AAE9C,SAAS,SAAS,KAAA,EAA4B;AACnD,EAAA,IAAI,GAAA,GAAM,WAAA,CAAY,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,GAAA,GAAM,IAAI,WAAW,KAAK,CAAA;AAC1B,IAAA,WAAA,CAAY,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,EAC5B;AACA,EAAA,OAAO,GAAA;AACT;;;AC7DA,IAAM,SAAA,uBAAgB,GAAA,CAAI;AAAA,EACxB,KAAA;AAAA,EAAO,GAAA;AAAA,EAAK,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,IAAA;AAAA,EAC1F,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,KAAA;AAAA,EAAO,IAAA;AAAA,EAAM,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,GAAA;AAAA,EAAK,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,MAAA;AAAA,EACvF,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,QAAA;AAAA,EAAU,IAAA;AAAA,EAAM,KAAA;AAAA,EAAO,KAAA;AAAA,EAAO,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQvF,MAAA;AAAA,EAAQ,MAAA;AAAA,EAAQ,aAAA;AAAA,EAAe,MAAA;AAAA,EAAQ,QAAA;AAAA,EAAU,IAAA;AAAA,EACjD,gBAAA;AAAA,EAAkB,SAAA;AAAA,EAAW,OAAA;AAAA,EAAS,UAAA;AAAA,EAAY,UAAA;AAAA,EAAY;AAChE,CAAC,CAAA;AAEM,SAAS,UAAA,CAAW,KAAA,EAAgB,QAAA,EAAkB,OAAA,GAAwB,EAAC,EAAgB;AACpG,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,GAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,EAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,SAAS,QAAQ,CAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,KAAA,EAAO,KAAK,CAAA;AACzC,EAAA,MAAM,KAAA,GAAQ,SAAS,KAAK,CAAA;AAE5B,EAAA,MAAM,SAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,IAAA,CAAK,SAAS,UAAA,EAAY;AACtD,IAAA,MAAM,EAAE,KAAA,EAAO,GAAA,KAAQ,SAAA,CAAU,IAAA,EAAM,OAAO,QAAQ,CAAA;AACtD,IAAA,IAAI,KAAA,GAAQ,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,KAAA,IAAS,IAAI,iBAAA,GAAoB,IAAA,CAAK,UAAA,CAAW,CAAA,EAAG,KAAK,CAAA;AAAA,EAC3G;AACA,EAAA,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,KAAA,GAAQ,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,KAAK,aAAA,CAAc,aAAA,CAAc,CAAA,CAAE,IAAA,CAAK,aAAa,CAAC,CAAA;AAEnG,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AACnC,EAAA,MAAM,EAAE,SAAS,cAAA,EAAe,GAAI,aAAa,KAAA,EAAO,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,MAAM,CAAA;AAEtF,EAAA,OAAO,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAO,SAAS,cAAA,EAAe;AAC7D;AAeA,eAAsB,kBAAA,CACpB,KAAA,EACA,QAAA,EACA,OAAA,EACsB;AACtB,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,GAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,EAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,SAAS,QAAQ,CAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,KAAA,EAAO,KAAK,CAAA;AACzC,EAAA,MAAM,KAAA,GAAQ,SAAS,KAAK,CAAA;AAC5B,EAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,QAAQ,CAAA;AAG3D,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAoB;AACvC,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAoB;AACxC,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,IAAA,CAAK,SAAS,UAAA,EAAY;AACtD,IAAA,MAAM,EAAE,KAAA,EAAO,GAAA,KAAQ,SAAA,CAAU,IAAA,EAAM,OAAO,QAAQ,CAAA;AACtD,IAAA,MAAA,CAAO,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,KAAK,CAAA;AACzB,IAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,GAAG,CAAA;AACxB,IAAA,IAAI,KAAA,GAAQ,QAAQ,MAAA,GAAS,KAAA;AAAA,EAC/B;AAEA,EAAA,MAAM,SAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,IAAA,CAAK,SAAS,UAAA,EAAY;AACtD,IAAA,MAAM,OAAA,GAAU,SAAS,CAAA,GAAA,CAAK,MAAA,CAAO,IAAI,IAAA,CAAK,EAAE,CAAA,IAAK,CAAA,IAAK,MAAA,GAAS,CAAA;AACnE,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,WAAA,CAAY,GAAA,CAAI,KAAK,EAAE,CAAA;AAC3C,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,GAAA,CAAI,GAAG,MAAA,CAAO,QAAA,EAAU,GAAG,CAAC,CAAA,GAAI,CAAA;AACvD,IAAA,MAAM,MAAA,GAAS,GAAA,GAAM,OAAA,GAAU,GAAA,GAAM,GAAA;AACrC,IAAA,IAAI,UAAU,CAAA,EAAG;AACjB,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AAClC,IAAA,MAAM,GAAA,GAAM,WAAW,GAAA,GAAM,GAAA,GAAM,mBAAmB,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA,GAAM,YAAA,CAAA;AAC1E,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,MAAA,IAAU,CAAA,GAAI,iBAAA,GAAoB,IAAA,CAAK,UAAA,CAAW,CAAA,EAAG,GAAA,EAAK,CAAA;AAAA,EAC7F;AACA,EAAA,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,KAAA,GAAQ,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,KAAK,aAAA,CAAc,aAAA,CAAc,CAAA,CAAE,IAAA,CAAK,aAAa,CAAC,CAAA;AAEnG,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AACnC,EAAA,MAAM,EAAE,SAAS,cAAA,EAAe,GAAI,aAAa,KAAA,EAAO,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,MAAM,CAAA;AACtF,EAAA,OAAO,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAO,SAAS,cAAA,EAAe;AAC7D;AAaA,SAAS,SAAS,CAAA,EAAqB;AACrC,EAAA,OAAO;AAAA,IACL,GAAG,IAAI,GAAA;AAAA,MACL,EACG,WAAA,EAAY,CACZ,KAAA,CAAM,iBAAiB,EACvB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,CAAA,IAAK,CAAC,SAAA,CAAU,GAAA,CAAI,CAAC,CAAC;AAAA;AACrD,GACF;AACF;AAEA,SAAS,SAAA,CAAU,IAAA,EAAiB,KAAA,EAAiB,QAAA,GAAkC,MAAM,CAAA,EAAmC;AAC9H,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,MAAM,OAAiB,EAAC;AACxB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AACnC,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,aAAA,CAAc,WAAA,EAAY;AAC1C,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AAGnC,EAAA,MAAM,SAAA,GAAY,eAAA,CAAgB,IAAA,CAAK,IAAI,CAAA;AAC3C,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AAOrB,IAAA,MAAM,CAAA,GAAI,SAAS,CAAC,CAAA;AACpB,IAAA,IAAI,SAAS,CAAA,EAAG;AACd,MAAA,KAAA,IAAS,EAAA,GAAK,CAAA;AACd,MAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IACb,CAAA,MAAA,IAAW,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,EAAG;AAC3B,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA;AACb,MAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IACb,CAAA,MAAA,IAAW,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,EAAG;AAC3B,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA;AACb,MAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IACb,CAAA,MAAA,IAAW,EAAA,CAAG,QAAA,CAAS,CAAC,CAAA,EAAG;AACzB,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA;AACb,MAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IACb,CAAA,MAAA,IAAW,cAAA,CAAe,CAAA,EAAG,SAAS,CAAA,EAAG;AAIvC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA;AACb,MAAA,IAAA,CAAK,IAAA,CAAK,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IACnB,CAAA,MAAA,IAAW,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,EAAG;AAC3B,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA;AACb,MAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,GAAA,EAAK,IAAA,CAAK,MAAA,GAAS,CAAA,SAAA,EAAY,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,GAAK,EAAA,EAAG;AACxE;AAQA,IAAM,iBAAA,GAAoB,GAAA;AAU1B,SAAS,WAAA,CAAY,OAAgB,KAAA,EAAwC;AAC3E,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAM,CAAA;AACrC,EAAA,MAAM,EAAA,uBAAS,GAAA,EAAoB;AACnC,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,IAAA,CAAK,SAAS,UAAA,EAAY;AACtD,IAAA,CAAA,EAAA;AACA,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AACnC,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,IAAI,CAAA;AACvC,IAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,MAAA,IAAI,MAAM,GAAA,CAAI,CAAC,CAAA,IAAK,IAAA,CAAK,SAAS,CAAC,CAAA,EAAG,EAAA,CAAG,GAAA,CAAI,IAAI,EAAA,CAAG,GAAA,CAAI,CAAC,CAAA,IAAK,KAAK,CAAC,CAAA;AAAA,IACtE;AAAA,EACF;AACA,EAAA,MAAM,CAAA,uBAAQ,GAAA,EAAoB;AAClC,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAA,CAAK,CAAA,GAAI,CAAA,KAAA,CAAO,EAAA,CAAG,GAAA,CAAI,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,CAAE,CAAA,GAAI,CAAA;AAGzD,IAAA,CAAA,CAAE,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,CAAA,EAAG,GAAG,CAAC,CAAC,CAAA;AAAA,EAC1C;AACA,EAAA,OAAO,CAAC,CAAA,KAAc,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,IAAK,CAAA;AACpC;AAWO,SAAS,gBAAgB,IAAA,EAA2B;AACzD,EAAA,OAAO,IAAI,GAAA;AAAA,IACT,IAAA,CACG,KAAA,CAAM,iEAAiE,CAAA,CACvE,MAAA,CAAO,OAAO,CAAA,CACd,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,EAAa;AAAA,GAC/B;AACF;AAGA,SAAS,cAAA,CAAe,MAAc,KAAA,EAA6B;AACjE,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,EAAM,IAAI,CAAA;AACzC,IAAA,IAAI,MAAA,IAAU,CAAA,IAAK,MAAA,IAAU,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,IAAA;AAAA,EAChF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,eAAA,CAAgB,GAAW,CAAA,EAAmB;AACrD,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,EAAE,MAAM,CAAA;AACrC,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,IAAI,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,EAAA;AAC/B,EAAA,OAAO,CAAA;AACT;AAEA,SAAS,YAAA,CACP,KAAA,EACA,KAAA,EACA,QAAA,EACA,OACA,MAAA,EAC6C;AAC7C,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAE,CAAA;AACvC,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,KAAA,CAAM,KAAK,wGAAwG,CAAA;AACnH,IAAA,MAAME,KAAAA,GAAO,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC5B,IAAA,OAAO,EAAE,OAAA,EAASA,KAAAA,EAAM,cAAA,EAAgB,cAAA,CAAeA,KAAI,CAAA,EAAE;AAAA,EAC/D;AAEA,EAAA,KAAA,MAAW,EAAE,IAAA,EAAM,GAAA,EAAI,IAAK,KAAA,EAAO;AACjC,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,GAAA,EAAM,IAAA,CAAK,aAAa,MAAM,IAAA,CAAK,IAAI,CAAA,EAAA,EAAK,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA,CAAA,CAAG,CAAA;AACtF,IAAA,IAAI,KAAK,SAAA,EAAW,KAAA,CAAM,KAAK,GAAA,GAAM,IAAA,CAAK,YAAY,GAAG,CAAA;AACzD,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,aAAa,CAAA;AACtE,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,aAAa,CAAA;AACtE,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,UAAU,MAAA,CAAO,OAAO,CAAA,CAAE,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACjF,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,cAAc,MAAA,CAAO,OAAO,CAAA,CAAE,KAAA,CAAM,GAAG,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACrF,IAAA,KAAA,CAAM,KAAK,CAAA,WAAA,EAAc,IAAA,CAAK,UAAA,CAAW,OAAA,CAAQ,CAAC,CAAC,CAAA,YAAA,EAAY,IAAA,CAAK,IAAI,GAAG,IAAA,CAAK,KAAA,GAAQ,cAAW,EAAE,CAAA,MAAA,EAAM,GAAG,CAAA,CAAE,CAAA;AAChH,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAEb,IAAA,MAAM,YAAY,KAAA,CAAM,MAAA,CAAO,KAAK,CAAA,CAAE,KAAK,IAAI,CAAA;AAC/C,IAAA,IAAI,eAAe,SAAS,CAAA,GAAI,MAAA,IAAU,KAAA,CAAM,SAAS,CAAA,EAAG;AAC5D,IAAA,KAAA,CAAM,IAAA,CAAK,GAAG,KAAK,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC5B,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,cAAA,EAAgB,cAAA,CAAe,IAAI,CAAA,EAAE;AAC/D;AAEA,SAAS,OAAO,EAAA,EAAwB;AACtC,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,EAAE,CAAC,CAAA;AACxB;AAEA,SAAS,eAAe,IAAA,EAAsB;AAE5C,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAClC;AAEA,SAAS,MAAM,CAAA,EAAmB;AAChC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AAC/B;;;ACxSA,IAAM,YAAA,uBAAmB,GAAA,CAAc,CAAC,QAAQ,QAAA,EAAU,SAAA,EAAW,YAAA,EAAc,YAAY,CAAC,CAAA;AAsBzF,SAAS,QAAA,CAAS,KAAA,EAAgB,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAiB;AACpG,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,SAAS,CAAC,CAAA;AAC5C,EAAA,MAAM,KAAA,GAAQ,SAAS,KAAK,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA;AAE9B,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAwB;AAC7C,EAAA,IAAI,iBAAA,GAAoB,CAAA;AAGxB,EAAA,IAAI,WAA2C,CAAC,EAAE,IAAI,MAAA,EAAQ,IAAA,EAAM,GAAG,CAAA;AACvE,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,IAAS,QAAA,EAAU,KAAA,EAAA,EAAS;AAC9C,IAAA,MAAM,eAA+C,EAAC;AACtD,IAAA,KAAA,MAAW,EAAE,EAAA,EAAI,IAAA,EAAK,IAAK,QAAA,EAAU;AACnC,MAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,EAAA,CAAG,EAAE,CAAA,EAAG;AAC5B,QAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA,EAAG;AAC/B,QAAA,iBAAA,GAAoB,IAAA,CAAK,GAAA,CAAI,iBAAA,EAAmB,CAAA,CAAE,UAAU,CAAA;AAC5D,QAAA,MAAM,cAAc,CAAA,CAAE,GAAA;AACtB,QAAA,IAAI,WAAA,KAAgB,MAAA,IAAU,QAAA,CAAS,GAAA,CAAI,WAAW,CAAA,EAAG;AACzD,QAAA,MAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,WAAW,CAAA;AACnC,QAAA,IAAI,CAAC,IAAA,EAAM;AACX,QAAA,MAAM,KAAA,GAAQC,MAAAA,CAAM,IAAA,GAAO,CAAA,CAAE,aAAa,GAAG,CAAA;AAC7C,QAAA,QAAA,CAAS,IAAI,WAAA,EAAa;AAAA,UACxB,IAAI,IAAA,CAAK,EAAA;AAAA,UACT,MAAM,IAAA,CAAK,aAAA;AAAA,UACX,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,IAAA,EAAM,KAAK,IAAA,CAAK,KAAA;AAAA,UAChB,KAAA;AAAA,UACA,UAAA,EAAY;AAAA,SACb,CAAA;AACD,QAAA,YAAA,CAAa,KAAK,EAAE,EAAA,EAAI,WAAA,EAAa,IAAA,EAAM,OAAO,CAAA;AAAA,MACpD;AAAA,IACF;AACA,IAAA,QAAA,GAAW,YAAA;AACX,IAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAAA,EAC7B;AAEA,EAAA,MAAM,QAAQ,CAAC,GAAG,QAAA,CAAS,MAAA,EAAQ,CAAA,CAAE,IAAA;AAAA,IACnC,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,QAAQ,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,UAAA,GAAa,EAAE,UAAA,IAAc,CAAA,CAAE,IAAA,CAAK,aAAA,CAAc,EAAE,IAAI;AAAA,GAC3F;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,EAAE,EAAA,EAAI,QAAQ,IAAA,EAAM,IAAA,EAAM,iBAAiB,MAAA,EAAO;AAAA,IACxD,KAAA,EAAO,QAAA;AAAA,IACP,QAAA,EAAU,KAAA;AAAA,IACV,MAAA,EAAQ,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,KAAA,KAAU,CAAC,CAAA,CAAE,MAAA;AAAA,IAC3C,UAAA,EAAY,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,KAAA,GAAQ,CAAC,CAAA,CAAE,MAAA;AAAA,IAC7C,iBAAA,EAAmBA,OAAM,iBAAiB;AAAA,GAC5C;AACF;AAEA,SAASA,OAAM,CAAA,EAAmB;AAChC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AAC/B","file":"chunk-6ABXHZRN.js","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * Cross-process single-writer lock (O_EXCL create), shared by the embedding\n * cache writer and the auto-refresh rebuild so two vg processes never write\n * the same repo-local artifact at once. A lock whose owning process is dead,\n * or that is older than `staleMs`, is presumed abandoned and reclaimed.\n */\n\n/** A lock older than this is presumed dead (crashed process). */\nexport const DEFAULT_LOCK_STALE_MS = 15 * 60 * 1000;\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (e) {\n return (e as NodeJS.ErrnoException).code === 'EPERM'; // exists, just not ours to signal\n }\n}\n\nfunction lockIsStale(file: string, staleMs: number): boolean {\n try {\n const { pid, at } = JSON.parse(fs.readFileSync(file, 'utf8')) as { pid?: number; at?: number };\n if (typeof at === 'number' && Date.now() - at > staleMs) return true;\n if (typeof pid === 'number' && !isProcessAlive(pid)) return true;\n return false;\n } catch {\n return true; // unreadable/corrupt → reclaim it\n }\n}\n\n/** Take the lock (O_EXCL), reclaiming a stale/dead one. Returns success. */\nexport function acquireLock(file: string, staleMs = DEFAULT_LOCK_STALE_MS): boolean {\n const write = (): boolean => {\n try {\n fs.mkdirSync(path.dirname(file), { recursive: true });\n const fd = fs.openSync(file, 'wx');\n fs.writeFileSync(fd, JSON.stringify({ pid: process.pid, at: Date.now() }));\n fs.closeSync(fd);\n return true;\n } catch {\n return false;\n }\n };\n if (write()) return true;\n if (lockIsStale(file, staleMs)) {\n try {\n fs.rmSync(file, { force: true });\n } catch {\n /* another process may have reclaimed it */\n }\n return write();\n }\n return false;\n}\n\nexport function releaseLock(file: string): void {\n try {\n fs.rmSync(file, { force: true });\n } catch {\n /* best-effort */\n }\n}\n","import * as fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { hashString } from './hash.js';\nimport { cacheDir } from './cache.js';\nimport { acquireLock, releaseLock } from './lock.js';\nimport type { GraphNode, VgGraph } from '../schema.js';\n\n/**\n * Local-embedding semantic search for `vg ask --semantic`/`--deep` (no API key).\n *\n * The embedding backend is an OPTIONAL, lazily-loaded dependency (`fastembed`,\n * Apache-2.0, local ONNX) so the core install stays lean and `ask` never breaks:\n * if the backend or model isn't available it degrades to (prefix-fuzzy) lexical\n * search with a clear note. Embeddings are query-time + cached under\n * `.vibgrate/cache/` (keyed by node-text hash); they are NEVER written into the\n * committed `graph.json`, so the artifact stays byte-deterministic.\n *\n * `--local` disables the model download (semantic is skipped unless already\n * cached via an injected backend), keeping the air-gapped guarantee.\n */\n\nexport interface Embedder {\n /** Stable model id (recorded with cached vectors so a model change invalidates them). */\n id: string;\n /** Embed documents → unit-or-raw vectors (cosine handles normalization). */\n embed(texts: string[]): Promise<number[][]>;\n /** Embed a single query string. */\n embedQuery(text: string): Promise<number[]>;\n}\n\n/** Why semantic fell back to lexical — for calm, specific messaging. */\nexport type EmbedUnavailable = 'not-installed' | 'no-permission' | 'download-failed' | 'init-failed';\n\nexport interface LoadEmbedderOptions {\n local?: boolean; // --local: do not download a model\n model?: string; // override the embedding model id\n noDownload?: boolean; // only load if the model is already cached (never fetch)\n showDownloadProgress?: boolean; // let fastembed print its one-time download progress\n onUnavailable?: (reason: EmbedUnavailable) => void; // called (not thrown) when it can't load\n}\n\n/** The embedding model id in effect (explicit override → default). */\nexport function resolveEmbedModel(model?: string): string {\n return model ?? 'bge-small-en-v1.5';\n}\n\n/**\n * The **central, per-user** model cache — downloaded once per machine and shared\n * across every repo/folder (devs have many repos; the ~tens-of-MB model should\n * not re-download per project). Uses the XDG standard:\n * `$XDG_CACHE_HOME/vibgrate/models` (or `~/.cache/vibgrate/models`); relocate via\n * the standard `XDG_CACHE_HOME`. NB: fastembed's own default is the relative\n * `./local_cache`, i.e. per-CWD — which we override.\n */\nexport function modelCacheDir(): string {\n const base = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');\n return path.join(base, 'vibgrate', 'models');\n}\n\n/** A machine-global marker written once the model has loaded successfully. */\nfunction modelReadyMarker(modelId: string): string {\n return path.join(modelCacheDir(), `.ready-${safe(modelId)}`);\n}\n\n/**\n * Whether the embedding model is already present on this machine (loaded at least\n * once), so it can be used with **no network**. Lets the background warm-up\n * trigger only when it won't surprise-download.\n */\nexport function isModelReady(modelId = resolveEmbedModel()): boolean {\n return fs.existsSync(modelReadyMarker(modelId));\n}\n\n/**\n * A calm, specific, actionable one-liner for why semantic isn't available right\n * now — built to reassure (lexical still works) and inform, never to alarm. No\n * stack traces, no scary words; always names the off switch and the fix.\n */\nexport function unavailableMessage(reason: EmbedUnavailable): string {\n switch (reason) {\n case 'no-permission':\n return `semantic search couldn't write its model cache at ${modelCacheDir()} — using fast lexical search instead. Relocate it with the standard XDG_CACHE_HOME, or run with --local to stay lexical quietly. (No admin/sudo is ever needed — the cache lives in your home folder.)`;\n case 'download-failed':\n return `the semantic model isn't downloaded yet and couldn't be fetched (offline?) — using fast lexical search. It'll try again next time; run with --local to keep lexical without retrying.`;\n case 'not-installed':\n return `the optional semantic backend isn't available here — using fast lexical search.`;\n case 'init-failed':\n default:\n return `the semantic model couldn't load — using fast lexical search.`;\n }\n}\n\nexport interface ModelCacheInfo {\n dir: string;\n present: boolean;\n bytes: number;\n}\n\n/** Where the shared model lives, whether it's present, and how big it is. */\nexport function modelCacheInfo(modelId = resolveEmbedModel()): ModelCacheInfo {\n const dir = modelCacheDir();\n return { dir, present: isModelReady(modelId) || fs.existsSync(dir), bytes: dirSize(dir) };\n}\n\n/** Remove the shared, re-downloadable model from the central cache. Returns bytes freed. */\nexport function clearModelCache(): number {\n const dir = modelCacheDir();\n const bytes = dirSize(dir);\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n } catch {\n /* best-effort */\n }\n return bytes;\n}\n\nfunction dirSize(dir: string): number {\n let total = 0;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return 0;\n }\n for (const e of entries) {\n const p = path.join(dir, e.name);\n if (e.isDirectory()) total += dirSize(p);\n else {\n try {\n total += fs.statSync(p).size;\n } catch {\n /* skip unreadable */\n }\n }\n }\n return total;\n}\n\nfunction isPermissionError(e: unknown): boolean {\n const code = (e as NodeJS.ErrnoException | undefined)?.code;\n return code === 'EACCES' || code === 'EPERM' || code === 'EROFS';\n}\n\n/**\n * Whether this repo already has a cached vector set for `modelId` — i.e. semantic\n * search has run here before, so the next run is fast (no first-use download/embed).\n * Lets `ask` show the one-time setup note only when it's actually warranted.\n */\nexport function embeddingsCached(root: string, modelId: string): boolean {\n return fs.existsSync(path.join(cacheDir(root), `embeddings-${safe(modelId)}.json`));\n}\n\n/**\n * Try to load the optional local embedding backend. Returns null (→ caller falls\n * back to lexical) when running `--local`, when the dependency isn't installed,\n * or when the model can't initialize.\n */\nexport async function loadEmbedder(options: LoadEmbedderOptions = {}): Promise<Embedder | null> {\n // `--local` forces the deterministic lexical floor with no model load/download\n // (air-gapped guarantee; also how tests stay offline).\n if (options.local) return null;\n const modelId = resolveEmbedModel(options.model);\n // noDownload (used by the background warm-up): never fetch — bail if not cached.\n if (options.noDownload && !isModelReady(modelId)) return null;\n const fail = (reason: EmbedUnavailable): null => {\n options.onUnavailable?.(reason);\n return null;\n };\n\n // Lazy, optional dependency (native ONNX): loaded only for `vg ask`/`embed`,\n // never by build/verify, so the graph artifact stays deterministic.\n const mod: any = await importEmbedBackend();\n if (!mod?.FlagEmbedding) return fail('not-installed');\n\n const cache = modelCacheDir(); // central, shared across all repos\n try {\n fs.mkdirSync(cache, { recursive: true });\n } catch (e) {\n return fail(isPermissionError(e) ? 'no-permission' : 'init-failed');\n }\n\n try {\n // First use fetches the model. A refused connection fails fast, but a\n // black-holing proxy (common on corporate networks) would hang the first\n // `vg ask` / MCP query_graph forever — bound the wait and fall back to\n // lexical instead. Cached loads are local disk and get the same generous\n // ceiling without ever hitting it.\n const model: any = await withTimeout(\n mod.FlagEmbedding.init({\n model: mapModel(mod, modelId),\n cacheDir: cache,\n showDownloadProgress: options.showDownloadProgress ?? false,\n }) as Promise<unknown>,\n embedInitTimeoutMs(),\n 'embedding model init timed out',\n );\n // Record machine-global readiness so future builds can warm up offline.\n try {\n fs.writeFileSync(modelReadyMarker(modelId), new Date(0).toISOString());\n } catch {\n /* marker is best-effort */\n }\n return {\n id: modelId,\n async embed(texts) {\n const out: number[][] = [];\n for await (const batch of model.embed(texts, 64)) {\n for (const v of batch) out.push(Array.from(v as ArrayLike<number>));\n }\n return out;\n },\n async embedQuery(text) {\n const v = await model.queryEmbed(text);\n return Array.from(v as ArrayLike<number>);\n },\n };\n } catch (e) {\n return fail(isPermissionError(e) ? 'no-permission' : 'download-failed');\n }\n}\n\n/**\n * Import the optional native backend. A host can supply it out-of-tree via\n * `VIBGRATE_EMBEDDER_PATH` — a directory whose `node_modules` contains\n * `fastembed`. Editor integrations use this when their bundled engine ships\n * without the native optional dependency (the VS Code extension installs it\n * into its own storage on consent); the host dir wins over this package's own\n * dependency tree so the copy the user consented to is the one that loads.\n * Any resolution failure falls through — never throws.\n */\nasync function importEmbedBackend(): Promise<any> {\n const hostDir = process.env.VIBGRATE_EMBEDDER_PATH;\n if (hostDir) {\n try {\n const req = createRequire(path.join(hostDir, 'package.json'));\n const mod: any = await import(pathToFileURL(req.resolve('fastembed')).href);\n // A CJS entry imported over ESM may nest its exports under `default`.\n const resolved = mod?.FlagEmbedding ? mod : mod?.default;\n if (resolved?.FlagEmbedding) return resolved;\n } catch {\n /* fall through to normal resolution */\n }\n }\n return await import('fastembed' as string).catch(() => null);\n}\n\n/** Ceiling for the one-time model fetch/init; override via VG_EMBED_TIMEOUT_MS. */\nfunction embedInitTimeoutMs(): number {\n const n = Number(process.env.VG_EMBED_TIMEOUT_MS);\n return Number.isFinite(n) && n > 0 ? n : 60_000;\n}\n\n/** Reject `promise` if it hasn't settled within `ms` (the work itself is not cancelled). */\nexport async function withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), ms);\n timer.unref?.();\n }),\n ]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nfunction mapModel(mod: any, id: string): unknown {\n const m = mod.EmbeddingModel ?? {};\n if (/bge-small/i.test(id)) return m.BGESmallENV15 ?? m.BGESmallEN ?? id;\n if (/bge-base/i.test(id)) return m.BGEBaseENV15 ?? id;\n if (/all-minilm/i.test(id)) return m.AllMiniLML6V2 ?? id;\n return id;\n}\n\n/** Path segments that carry no semantic signal — dropped from embed context. */\nconst PATH_NOISE = new Set([\n 'src', 'app', 'apps', 'lib', 'libs', 'dist', 'build', 'out', 'index', 'main',\n 'packages', 'pkg', 'test', 'tests', '__tests__', 'spec', 'node_modules', 'internal',\n 'com', 'example', 'demo', 'java', 'net', 'org', 'www',\n]);\n\n/** Meaningful path context for a node: a couple of parent dirs + the filename stem. */\nfunction pathContext(file: string): string {\n const parts = file.split('/');\n const stem = (parts.pop() ?? '').replace(/\\.[^.]+$/, '');\n const dirs = parts.filter((p) => p && !PATH_NOISE.has(p.toLowerCase()));\n return [...dirs.slice(-2), stem].filter(Boolean).join(' ');\n}\n\n/**\n * The text we embed for a node. Alongside identity + signature we add the\n * strongest available signal — the node's **doc-comment / docstring** summary —\n * plus lightweight context already on the graph (file-path words, area label), so\n * a tersely-named symbol (`Table`, `NotificationJob`) a concept query can reach.\n *\n * `document` nodes (markdown, manifests, Docker, CI, OpenAPI, …) put the\n * scrubbed body in `doc` — that body is the primary embed signal so `vg ask`\n * can answer project-context questions, not only code symbols.\n */\nexport function nodeEmbedText(node: GraphNode, areaLabel?: string): string {\n if (node.kind === 'document') {\n const category = (node.signature ?? 'document').replace(/^document:/, '');\n // Category keywords help ops/config queries land on the right file type.\n const categoryHints: Record<string, string> = {\n manifest: 'package dependencies scripts install dependencies versions',\n docker: 'dockerfile container image build runtime',\n compose: 'docker-compose services containers networking volumes',\n ci: 'continuous integration github actions workflow pipeline test build deploy',\n 'build-config': 'typescript tsconfig bundler vite webpack eslint prettier test',\n 'api-contract': 'openapi swagger graphql protobuf api schema endpoints',\n 'task-runner': 'makefile justfile tasks build test run commands',\n workspace: 'monorepo workspace packages pnpm turbo nx',\n infra: 'deploy infrastructure kubernetes kubernetes terraform helm kubernetes',\n 'env-example': 'environment variables configuration secrets template',\n markdown: 'documentation readme guide',\n };\n const hint = categoryHints[category] ?? category;\n return [\n node.qualifiedName,\n 'document',\n category,\n hint,\n pathContext(node.file),\n (node.doc ?? '').slice(0, 5000),\n ]\n .filter(Boolean)\n .join('\\n');\n }\n return [node.qualifiedName, node.kind, node.signature ?? '', node.doc ?? '', pathContext(node.file), areaLabel ?? '']\n .filter(Boolean)\n .join(' ');\n}\n\nexport function cosine(a: number[], b: number[]): number {\n let dot = 0;\n let na = 0;\n let nb = 0;\n const n = Math.min(a.length, b.length);\n for (let i = 0; i < n; i++) {\n dot += a[i] * b[i];\n na += a[i] * a[i];\n nb += b[i] * b[i];\n }\n if (na === 0 || nb === 0) return 0;\n return dot / (Math.sqrt(na) * Math.sqrt(nb));\n}\n\ninterface EmbedCache {\n model: string;\n entries: Record<string, { hash: string; vec: number[] }>;\n}\n\n/** Reports embedding progress: how many of `total` nodes are done so far. */\nexport type EmbedProgress = (done: number, total: number) => void;\n\n/** Nodes embedded per chunk — bounds memory and gives progress granularity. */\nconst EMBED_CHUNK = 256;\n/** Min gap between incremental cache writes (ms) — caps IO on big repos. */\nconst CACHE_WRITE_INTERVAL_MS = 1500;\n\nfunction vectorCachePath(root: string, modelId: string): string {\n return path.join(cacheDir(root), `embeddings-${safe(modelId)}.json`);\n}\n\n/**\n * How many searchable nodes still need embedding for `modelId` — cheap (hashes\n * the embed-text, reads only the cache; never loads the model). Lets the embed\n * command / background warm-up exit instantly when nothing changed.\n */\nexport function countPending(graph: VgGraph, root: string, modelId: string): number {\n const entries = readCacheEntries(vectorCachePath(root, modelId), modelId);\n const areaLabel = new Map(graph.areas.map((a) => [a.id, a.label] as const));\n let pending = 0;\n for (const n of graph.nodes) {\n // file/external stay out of the index; document (docs/env examples) are in.\n if (n.kind === 'file' || n.kind === 'external') continue;\n const h = hashString(nodeEmbedText(n, areaLabel.get(n.area)));\n const cached = entries[n.id];\n if (!cached || cached.hash !== h) pending++;\n }\n return pending;\n}\n\nfunction readCacheEntries(file: string, modelId: string): EmbedCache['entries'] {\n if (!fs.existsSync(file)) return {};\n try {\n const loaded = JSON.parse(fs.readFileSync(file, 'utf8')) as EmbedCache;\n if (loaded.model === modelId && loaded.entries) return loaded.entries;\n } catch {\n /* treat as empty */\n }\n return {};\n}\n\n// Single-writer lock (shared helper — see ./lock.ts) so a foreground `ask`\n// and a background `embed` never both embed the same repo at once (which\n// would race on the cache file).\n\n/**\n * Node embeddings for the searchable (non-file/external) nodes, cache-backed:\n * only nodes whose embed-text changed are re-embedded. The first run embeds in\n * chunks, **persists the cache incrementally** (so an interrupted/timed-out run\n * resumes instead of wasting the work), and reports progress via `onProgress`.\n */\nexport async function getNodeEmbeddings(\n graph: VgGraph,\n embedder: Embedder,\n root: string,\n onProgress?: EmbedProgress,\n): Promise<Map<string, number[]>> {\n const file = vectorCachePath(root, embedder.id);\n let cache: EmbedCache = { model: embedder.id, entries: {} };\n if (fs.existsSync(file)) {\n try {\n const loaded = JSON.parse(fs.readFileSync(file, 'utf8')) as EmbedCache;\n if (loaded.model === embedder.id && loaded.entries) cache = loaded;\n } catch {\n /* rebuild */\n }\n }\n\n const areaLabel = new Map(graph.areas.map((a) => [a.id, a.label] as const));\n // Include document nodes (markdown/txt/env examples) so ask can retrieve docs.\n const targets = graph.nodes.filter((n) => n.kind !== 'file' && n.kind !== 'external');\n const toEmbed: { id: string; text: string; hash: string }[] = [];\n const vectors = new Map<string, number[]>();\n for (const n of targets) {\n const text = nodeEmbedText(n, areaLabel.get(n.area));\n const h = hashString(text);\n const cached = cache.entries[n.id];\n if (cached && cached.hash === h) vectors.set(n.id, cached.vec);\n else toEmbed.push({ id: n.id, text, hash: h });\n }\n\n // Atomic write (temp + rename) so a reader never sees a half-written cache.\n const persist = (): void => {\n try {\n fs.mkdirSync(cacheDir(root), { recursive: true });\n const tmp = `${file}.tmp.${process.pid}`;\n fs.writeFileSync(tmp, JSON.stringify(cache));\n fs.renameSync(tmp, file);\n } catch {\n /* cache write best-effort */\n }\n };\n\n if (toEmbed.length) {\n // Single-writer: if another process (e.g. a background warm-up) is already\n // embedding this repo, don't double-work or race the cache — return what's\n // cached so far (lexical floor still applies). It will be complete next run.\n const lock = `${file}.lock`;\n if (!acquireLock(lock)) return vectors;\n try {\n onProgress?.(0, toEmbed.length);\n let lastWrite = Date.now();\n for (let i = 0; i < toEmbed.length; i += EMBED_CHUNK) {\n const slice = toEmbed.slice(i, i + EMBED_CHUNK);\n const vecs = await embedder.embed(slice.map((t) => t.text));\n slice.forEach((t, j) => {\n const vec = vecs[j] ?? [];\n vectors.set(t.id, vec);\n cache.entries[t.id] = { hash: t.hash, vec };\n });\n onProgress?.(Math.min(i + EMBED_CHUNK, toEmbed.length), toEmbed.length);\n // Persist periodically so a crash/timeout resumes from here next run.\n if (Date.now() - lastWrite >= CACHE_WRITE_INTERVAL_MS) {\n persist();\n lastWrite = Date.now();\n }\n }\n // prune entries for nodes no longer present, then a final authoritative write\n const live = new Set(targets.map((n) => n.id));\n for (const id of Object.keys(cache.entries)) if (!live.has(id)) delete cache.entries[id];\n persist();\n } finally {\n releaseLock(lock);\n }\n }\n\n return vectors;\n}\n\nfunction safe(id: string): string {\n return id.replace(/[^a-z0-9.-]+/gi, '_');\n}\n","import type { EdgeKind, GraphEdge, GraphNode, VgGraph } from '../schema.js';\n\n/** Indexes over a graph for O(1) neighbor lookups (built once per command). */\nexport class GraphIndex {\n readonly nodeById = new Map<string, GraphNode>();\n private outById = new Map<string, GraphEdge[]>();\n private inById = new Map<string, GraphEdge[]>();\n\n constructor(readonly graph: VgGraph) {\n for (const n of graph.nodes) this.nodeById.set(n.id, n);\n for (const e of graph.edges) {\n push(this.outById, e.src, e);\n push(this.inById, e.dst, e);\n }\n }\n\n out(id: string, kind?: EdgeKind): GraphEdge[] {\n const all = this.outById.get(id) ?? [];\n return kind ? all.filter((e) => e.kind === kind) : all;\n }\n\n in(id: string, kind?: EdgeKind): GraphEdge[] {\n const all = this.inById.get(id) ?? [];\n return kind ? all.filter((e) => e.kind === kind) : all;\n }\n\n node(id: string): GraphNode | undefined {\n return this.nodeById.get(id);\n }\n\n /**\n * Resolved nodes called by `id` — invocations (`call`) plus structural\n * dependency references (`references`, e.g. a constructor-injected field's\n * type), since both represent real usage a caller/impact question cares\n * about. `references` is otherwise only emitted by the precise SCIP/tsc\n * rungs and (for Java DI wiring) the heuristic rung — never a guess.\n */\n callees(id: string): { edge: GraphEdge; node: GraphNode }[] {\n return this.resolveTargets(this.out(id).filter(isUsageEdge), 'dst');\n }\n\n /** Resolved nodes that call or structurally reference `id`. */\n callers(id: string): { edge: GraphEdge; node: GraphNode }[] {\n return this.resolveTargets(this.in(id).filter(isUsageEdge), 'src');\n }\n\n private resolveTargets(edges: GraphEdge[], end: 'src' | 'dst') {\n const out: { edge: GraphEdge; node: GraphNode }[] = [];\n for (const e of edges) {\n const node = this.nodeById.get(e[end]);\n if (node) out.push({ edge: e, node });\n }\n return out;\n }\n}\n\nconst USAGE_KINDS: ReadonlySet<EdgeKind> = new Set(['call', 'references']);\nfunction isUsageEdge(e: GraphEdge): boolean {\n return USAGE_KINDS.has(e.kind);\n}\n\nfunction push(map: Map<string, GraphEdge[]>, key: string, value: GraphEdge): void {\n const list = map.get(key);\n if (list) list.push(value);\n else map.set(key, [value]);\n}\n\n/**\n * Memoized `GraphIndex`, keyed on the graph object's identity.\n *\n * The index (node-by-id + in/out adjacency) is a pure function of the graph's\n * content, and every read path rebuilds it from scratch — an O(nodes + edges)\n * pass that, on a large map, costs hundreds of milliseconds *per query*. Under\n * `vg serve` the same parsed graph object is reused across many tool calls\n * (`GraphSource` caches it by file mtime and only replaces the reference when\n * `graph.json` actually changes), so rebuilding the index on every call is pure\n * waste. Keying a `WeakMap` on that object identity builds the index once and\n * reuses it until the file is rebuilt — at which point `GraphSource` hands back a\n * *new* object, this map misses, and the stale index is collected with the old\n * graph. Correct and stale-safe by construction: a different graph is a\n * different object, so there is no cross-graph reuse and nothing to invalidate.\n *\n * `GraphIndex` is read-only (no method mutates its maps), so sharing one\n * instance across callers is safe.\n */\nconst INDEX_CACHE = new WeakMap<VgGraph, GraphIndex>();\n\nexport function indexFor(graph: VgGraph): GraphIndex {\n let idx = INDEX_CACHE.get(graph);\n if (!idx) {\n idx = new GraphIndex(graph);\n INDEX_CACHE.set(graph, idx);\n }\n return idx;\n}\n","import { indexFor, type GraphIndex } from './relations.js';\nimport { cosine, type Embedder } from './embeddings.js';\nimport type { GraphNode, VgGraph } from '../schema.js';\n\n/**\n * Deterministic retrieval for `vg ask` (VG-CLI-SPEC §3.2).\n *\n * Builds a structured, fact-annotated, budget-bounded context block for a\n * question — designed to drop straight into an assistant's context. The default\n * is deterministic lexical+structural retrieval (identifier/term matching with\n * morphological prefix-fuzzing, ranked by importance). `--semantic`/`--deep` adds\n * a hybrid local-embedding pass (`queryGraphSemantic`) that surfaces conceptually\n * related code even when no word is shared — still no API key.\n */\n\nexport interface QueryOptions {\n budget?: number; // approx token budget for the context block (default 2000)\n limit?: number; // max seed matches to expand (default 12)\n}\n\nexport interface QueryMatch {\n node: GraphNode;\n score: number;\n why: string;\n}\n\nexport interface QueryResult {\n question: string;\n matches: QueryMatch[];\n context: string;\n tokensEstimate: number;\n}\n\nconst STOPWORDS = new Set([\n 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'to', 'of', 'in', 'on', 'for', 'and', 'or',\n 'where', 'what', 'which', 'how', 'do', 'does', 'did', 'i', 'we', 'it', 'this', 'that', 'with',\n 'when', 'who', 'why', 'can', 'should', 'my', 'our', 'you', 'your', 'from', 'by', 'at', 'as',\n // Discovery-question scaffolding: words a caller uses to FRAME the ask\n // (\"find the code responsible for X\", \"I need to modify X, where do I\n // start?\", \"explain how X works in this codebase\") rather than to name the\n // target. Left in, these compete on equal footing with the real identifier\n // terms and can outrank it outright — e.g. \"find the code responsible for\n // deleteAsync\" let \"find\" alone drag in every FindByIdAsync/FindAll method\n // in the repo, none of them the target (VG-LOCATE-FAILURE-ANALYSIS.md).\n 'find', 'code', 'responsible', 'need', 'modify', 'me',\n 'implementation', 'explain', 'works', 'codebase', 'contains', 'file',\n]);\n\nexport function queryGraph(graph: VgGraph, question: string, options: QueryOptions = {}): QueryResult {\n const budget = options.budget ?? 2000;\n const limit = options.limit ?? 12;\n const terms = tokenize(question);\n const weightOf = termWeights(graph, terms);\n const index = indexFor(graph);\n\n const scored: QueryMatch[] = [];\n for (const node of graph.nodes) {\n if (node.kind === 'file' || node.kind === 'external') continue;\n const { score, why } = scoreNode(node, terms, weightOf);\n if (score > 0) scored.push({ node, score: round(score * (1 + IMPORTANCE_WEIGHT * node.importance)), why });\n }\n scored.sort((a, b) => b.score - a.score || a.node.qualifiedName.localeCompare(b.node.qualifiedName));\n\n const seeds = scored.slice(0, limit);\n const { context, tokensEstimate } = buildContext(graph, index, question, seeds, budget);\n\n return { question, matches: seeds, context, tokensEstimate };\n}\n\nexport interface SemanticQueryOptions extends QueryOptions {\n embedder: Embedder;\n /** Precomputed node vectors (from getNodeEmbeddings); falls back to lexical for nodes without one. */\n nodeVectors: Map<string, number[]>;\n}\n\n/**\n * Hybrid lexical + local-embedding retrieval. Blends the normalized lexical score\n * with cosine similarity to the query embedding (50/50), so a question like\n * \"where do we handle auth failures?\" can surface `verify_token` even with no\n * shared identifier. Deterministic given the same model + cached vectors;\n * embeddings live only in the cache, never in `graph.json`.\n */\nexport async function queryGraphSemantic(\n graph: VgGraph,\n question: string,\n options: SemanticQueryOptions,\n): Promise<QueryResult> {\n const budget = options.budget ?? 2000;\n const limit = options.limit ?? 12;\n const terms = tokenize(question);\n const weightOf = termWeights(graph, terms);\n const index = indexFor(graph);\n const queryVec = await options.embedder.embedQuery(question);\n\n // Raw lexical scores (pre-importance) for normalization.\n const lexRaw = new Map<string, number>();\n let lexMax = 0;\n const whyById = new Map<string, string>();\n for (const node of graph.nodes) {\n if (node.kind === 'file' || node.kind === 'external') continue;\n const { score, why } = scoreNode(node, terms, weightOf);\n lexRaw.set(node.id, score);\n whyById.set(node.id, why);\n if (score > lexMax) lexMax = score;\n }\n\n const scored: QueryMatch[] = [];\n for (const node of graph.nodes) {\n if (node.kind === 'file' || node.kind === 'external') continue;\n const lexNorm = lexMax > 0 ? (lexRaw.get(node.id) ?? 0) / lexMax : 0;\n const vec = options.nodeVectors.get(node.id);\n const sem = vec ? Math.max(0, cosine(queryVec, vec)) : 0;\n const hybrid = 0.5 * lexNorm + 0.5 * sem;\n if (hybrid <= 0) continue;\n const lexWhy = whyById.get(node.id);\n const why = lexWhy || (sem > 0.3 ? `semantic match (${sem.toFixed(2)})` : 'weak match');\n scored.push({ node, score: round(hybrid * (1 + IMPORTANCE_WEIGHT * node.importance)), why });\n }\n scored.sort((a, b) => b.score - a.score || a.node.qualifiedName.localeCompare(b.node.qualifiedName));\n\n const seeds = scored.slice(0, limit);\n const { context, tokensEstimate } = buildContext(graph, index, question, seeds, budget);\n return { question, matches: seeds, context, tokensEstimate };\n}\n\n/**\n * Split on anything that isn't a Unicode letter/number (`\\p{L}\\p{N}`, not the\n * ASCII-only `[a-z0-9]`) so identifiers in non-Latin scripts (Japanese,\n * Cyrillic, ...) survive tokenization instead of vanishing entirely — the\n * ASCII-only split treated every character of e.g. `名前` as a separator,\n * producing zero terms and a guaranteed empty result for any question about\n * it (VG-LOCATE-FAILURE-ANALYSIS.md). Length floor is 1, not 2: a single\n * non-stopword letter/digit is still the whole identifier when that's genuinely\n * the symbol's name (adversarial fixtures deliberately use bare `f`/`x`/`h`\n * names to stress this) — STOPWORDS already screens out short function words.\n */\nfunction tokenize(q: string): string[] {\n return [\n ...new Set(\n q\n .toLowerCase()\n .split(/[^\\p{L}\\p{N}]+/u)\n .filter((t) => t.length >= 1 && !STOPWORDS.has(t)),\n ),\n ];\n}\n\nfunction scoreNode(node: GraphNode, terms: string[], weightOf: (t: string) => number = () => 1): { score: number; why: string } {\n let score = 0;\n const hits: string[] = [];\n const name = node.name.toLowerCase();\n const qn = node.qualifiedName.toLowerCase();\n const file = node.file.toLowerCase();\n // Split the ORIGINAL name on camelCase / snake_case, then lowercase the parts\n // (splitting must see the capitals, so it happens before lowercasing).\n const nameParts = identifierParts(node.name);\n for (const t of terms) {\n // Each term's contribution is weighted by its specificity (IDF over symbol\n // names): a match on a distinctive term (\"toComparable\", \"layoutFor\") counts\n // for more than a match on a term shared by hundreds of symbols (\"code\",\n // \"get\", \"run\"). Without this, an incidental exact-name hit on a common word\n // in a natural-language question outranked the conceptually-correct symbol,\n // and importance weighting amplified the wrong hit (VG-NAVIGATION trace).\n const w = weightOf(t);\n if (name === t) {\n score += 10 * w;\n hits.push(t);\n } else if (nameParts.has(t)) {\n score += 6 * w;\n hits.push(t);\n } else if (name.includes(t)) {\n score += 4 * w;\n hits.push(t);\n } else if (qn.includes(t)) {\n score += 3 * w;\n hits.push(t);\n } else if (fuzzyPartMatch(t, nameParts)) {\n // Morphological / subword match: \"authentication\" ↔ \"authenticate\"\n // (shared prefix), so lexical ask survives word-form differences without\n // a model. The semantic path handles non-shared-root synonyms.\n score += 2 * w;\n hits.push(`~${t}`);\n } else if (file.includes(t)) {\n score += 1 * w;\n hits.push(t);\n }\n }\n return { score, why: hits.length ? `matched: ${hits.join(', ')}` : '' };\n}\n\n/**\n * Importance is a mild tiebreaker, not a doubling. The old `1 + importance`\n * let a hub (importance→1) double its score and outrank a stronger textual\n * match on the actual target; at 0.4 a top hub adds at most 40%, enough to\n * break genuine ties without overriding term evidence.\n */\nconst IMPORTANCE_WEIGHT = 0.4;\n\n/**\n * Per-term specificity weights (IDF) for one question, computed over the graph's\n * symbol-name vocabulary: `ln((N+1)/(df+1)) + 1`, clamped to a sane band. A term\n * that appears in one symbol name is highly discriminating; one that appears in\n * hundreds (\"get\", \"code\", \"run\", \"handler\") is near-noise. Clamped so a term\n * matching nothing (huge idf, but it scores 0 anyway) or everything can't\n * distort the scale. Cost is one O(nodes) pass, dwarfed by the scoring loop.\n */\nfunction termWeights(graph: VgGraph, terms: string[]): (t: string) => number {\n if (terms.length === 0) return () => 1;\n const df = new Map<string, number>();\n let n = 0;\n for (const node of graph.nodes) {\n if (node.kind === 'file' || node.kind === 'external') continue;\n n++;\n const name = node.name.toLowerCase();\n const parts = identifierParts(node.name);\n for (const t of terms) {\n if (parts.has(t) || name.includes(t)) df.set(t, (df.get(t) ?? 0) + 1);\n }\n }\n const w = new Map<string, number>();\n for (const t of terms) {\n const idf = Math.log((n + 1) / ((df.get(t) ?? 0) + 1)) + 1;\n // Ceiling of 8 (vs a natural df≈40 idf ≈ 5.4) keeps genuinely rare terms\n // dominant while a term matching nothing/only a file path can't distort.\n w.set(t, Math.max(0.5, Math.min(8, idf)));\n }\n return (t: string) => w.get(t) ?? 1;\n}\n\n/**\n * camelCase / snake_case / kebab split of an identifier → lowercased parts.\n * The separator alternative is Unicode-letter-aware (`\\p{L}\\p{N}`, not\n * ASCII-only `a-zA-Z0-9`) so non-Latin identifiers split on punctuation\n * without losing every character to it; the camelCase boundary lookaround\n * stays ASCII-only since upper/lowercase casing is itself an ASCII-script\n * concept — scripts without case simply never trigger it and fall through to\n * the separator split.\n */\nexport function identifierParts(name: string): Set<string> {\n return new Set(\n name\n .split(/[^\\p{L}\\p{N}]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/u)\n .filter(Boolean)\n .map((s) => s.toLowerCase()),\n );\n}\n\n/** A term fuzzily matches a part if they share a long-enough prefix (same root). */\nfunction fuzzyPartMatch(term: string, parts: Set<string>): boolean {\n for (const part of parts) {\n const shared = sharedPrefixLen(term, part);\n if (shared >= 5 && shared >= 0.6 * Math.min(term.length, part.length)) return true;\n }\n return false;\n}\n\nfunction sharedPrefixLen(a: string, b: string): number {\n const n = Math.min(a.length, b.length);\n let i = 0;\n while (i < n && a[i] === b[i]) i++;\n return i;\n}\n\nfunction buildContext(\n graph: VgGraph,\n index: GraphIndex,\n question: string,\n seeds: QueryMatch[],\n budget: number,\n): { context: string; tokensEstimate: number } {\n const lines: string[] = [];\n lines.push(`# Context for: ${question}`);\n lines.push('');\n if (seeds.length === 0) {\n lines.push('_No matching symbols found in the map. Try different terms, or `vg hubs` for the most important code._');\n const text = lines.join('\\n');\n return { context: text, tokensEstimate: estimateTokens(text) };\n }\n\n for (const { node, why } of seeds) {\n const block: string[] = [];\n block.push(`## ${node.qualifiedName} (${node.kind}, ${node.file}:${node.span.start})`);\n if (node.signature) block.push('`' + node.signature + '`');\n const callees = index.callees(node.id).map((x) => x.node.qualifiedName);\n const callers = index.callers(node.id).map((x) => x.node.qualifiedName);\n if (callees.length) block.push(`calls: ${unique(callees).slice(0, 8).join(', ')}`);\n if (callers.length) block.push(`called by: ${unique(callers).slice(0, 8).join(', ')}`);\n block.push(`importance ${node.importance.toFixed(3)} · area #${node.area}${node.isHub ? ' · hub' : ''} · ${why}`);\n block.push('');\n\n const candidate = lines.concat(block).join('\\n');\n if (estimateTokens(candidate) > budget && lines.length > 2) break;\n lines.push(...block);\n }\n\n const text = lines.join('\\n');\n return { context: text, tokensEstimate: estimateTokens(text) };\n}\n\nfunction unique(xs: string[]): string[] {\n return [...new Set(xs)];\n}\n\nfunction estimateTokens(text: string): number {\n // ~4 chars per token, the standard rough estimate.\n return Math.ceil(text.length / 4);\n}\n\nfunction round(x: number): number {\n return Math.round(x * 1e6) / 1e6;\n}\n","import { indexFor } from './relations.js';\nimport type { EdgeKind, VgGraph } from '../schema.js';\n\n/**\n * Deterministic reverse-reachability impact analysis (VG-CLI-SPEC §3.5).\n *\n * \"What breaks if `<node>` changes\" = everything that (transitively) depends on\n * it: its callers, importers, and subtypes. We BFS *backwards* along dependency\n * edges, bounded by depth, with a confidence that decays with distance (direct =\n * high; transitive lower; ambiguous/dynamic edges already carry lower edge\n * confidence which we fold in). Test-impact selection (`--tests`) lands in\n * Phase 2; this is the structural blast radius.\n */\n\nconst DEPEND_EDGES = new Set<EdgeKind>(['call', 'import', 'extends', 'implements', 'references']);\n\nexport interface ImpactItem {\n id: string;\n name: string;\n kind: string;\n file: string;\n line: number;\n depth: number;\n confidence: number;\n}\n\nexport interface ImpactResult {\n root: { id: string; name: string };\n depth: number;\n affected: ImpactItem[];\n direct: number;\n transitive: number;\n /** Lowest edge confidence encountered (e.g. a dynamic-dispatch edge). */\n minEdgeConfidence: number;\n}\n\nexport function impactOf(graph: VgGraph, rootId: string, opts: { depth?: number } = {}): ImpactResult {\n const maxDepth = Math.max(1, opts.depth ?? 4);\n const index = indexFor(graph);\n const root = index.node(rootId);\n\n const affected = new Map<string, ImpactItem>();\n let minEdgeConfidence = 1;\n\n // BFS over incoming dependency edges (dependents of the frontier).\n let frontier: { id: string; conf: number }[] = [{ id: rootId, conf: 1 }];\n for (let depth = 1; depth <= maxDepth; depth++) {\n const nextFrontier: { id: string; conf: number }[] = [];\n for (const { id, conf } of frontier) {\n for (const e of index.in(id)) {\n if (!DEPEND_EDGES.has(e.kind)) continue;\n minEdgeConfidence = Math.min(minEdgeConfidence, e.confidence);\n const dependentId = e.src;\n if (dependentId === rootId || affected.has(dependentId)) continue;\n const node = index.node(dependentId);\n if (!node) continue;\n const conf2 = round(conf * e.confidence * 0.9); // decay with distance\n affected.set(dependentId, {\n id: node.id,\n name: node.qualifiedName,\n kind: node.kind,\n file: node.file,\n line: node.span.start,\n depth,\n confidence: conf2,\n });\n nextFrontier.push({ id: dependentId, conf: conf2 });\n }\n }\n frontier = nextFrontier;\n if (frontier.length === 0) break;\n }\n\n const items = [...affected.values()].sort(\n (a, b) => a.depth - b.depth || b.confidence - a.confidence || a.name.localeCompare(b.name),\n );\n\n return {\n root: { id: rootId, name: root?.qualifiedName ?? rootId },\n depth: maxDepth,\n affected: items,\n direct: items.filter((i) => i.depth === 1).length,\n transitive: items.filter((i) => i.depth > 1).length,\n minEdgeConfidence: round(minEdgeConfidence),\n };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 1e6) / 1e6;\n}\n"]}
@@ -0,0 +1,136 @@
1
+ import { vgdRequest } from './chunk-PMYWZRRS.js';
2
+ import { resolveOne } from './chunk-J7LKEB2R.js';
3
+ import { impactOf, queryGraph } from './chunk-6ABXHZRN.js';
4
+
5
+ // src/code/graph-backend.ts
6
+ function localGraphBackend(graph) {
7
+ return {
8
+ source: "local",
9
+ async search(query, opts) {
10
+ const res = queryGraph(graph, query, { budget: 1500, limit: opts?.limit ?? 10 });
11
+ return {
12
+ source: "local",
13
+ matches: res.matches.map((m) => ({
14
+ id: m.node.id,
15
+ qualifiedName: m.node.qualifiedName,
16
+ kind: m.node.kind,
17
+ file: m.node.file,
18
+ line: m.node.span?.start ?? 0,
19
+ score: m.score,
20
+ why: m.why,
21
+ signature: m.node.signature ?? null
22
+ }))
23
+ };
24
+ },
25
+ async impact(symbol, opts) {
26
+ const node = resolveSymbolId(graph, symbol);
27
+ if (!node) return null;
28
+ const imp = impactOf(graph, node, { depth: opts?.depth ?? 4 });
29
+ return {
30
+ source: "local",
31
+ root: imp.root,
32
+ depth: imp.depth,
33
+ affected: imp.affected.map((a) => ({
34
+ id: a.id,
35
+ name: a.name,
36
+ kind: a.kind,
37
+ file: a.file,
38
+ line: a.line,
39
+ depth: a.depth,
40
+ confidence: a.confidence
41
+ })),
42
+ direct: imp.direct,
43
+ transitive: imp.transitive
44
+ };
45
+ }
46
+ };
47
+ }
48
+ function vgdGraphBackend(options) {
49
+ const local = localGraphBackend(options.fallback);
50
+ const request = options.request ?? ((req, opts) => vgdRequest(req, opts));
51
+ const clientOpts = { socketPath: options.socketPath };
52
+ return {
53
+ source: "vgd",
54
+ async search(query, opts) {
55
+ try {
56
+ const res = await request(
57
+ {
58
+ op: "query-graph",
59
+ repositoryId: options.repositoryId,
60
+ query,
61
+ limit: opts?.limit ?? 10,
62
+ gitRef: options.gitRef
63
+ },
64
+ clientOpts
65
+ );
66
+ if (res?.ok && Array.isArray(res.matches)) {
67
+ return {
68
+ source: "vgd",
69
+ matches: res.matches.map((m) => ({
70
+ id: m.id,
71
+ qualifiedName: m.qualifiedName,
72
+ kind: m.kind,
73
+ file: m.file,
74
+ line: m.line,
75
+ score: m.score,
76
+ why: m.why,
77
+ signature: null
78
+ }))
79
+ };
80
+ }
81
+ } catch {
82
+ }
83
+ return local.search(query, opts);
84
+ },
85
+ async impact(symbol, opts) {
86
+ try {
87
+ const res = await request(
88
+ {
89
+ op: "impact-of",
90
+ repositoryId: options.repositoryId,
91
+ symbol,
92
+ depth: opts?.depth ?? 4,
93
+ gitRef: options.gitRef
94
+ },
95
+ clientOpts
96
+ );
97
+ if (res?.ok && res.root && Array.isArray(res.affected)) {
98
+ return {
99
+ source: "vgd",
100
+ root: res.root,
101
+ depth: res.depth ?? opts?.depth ?? 4,
102
+ affected: res.affected,
103
+ direct: res.direct ?? 0,
104
+ transitive: res.transitive ?? 0
105
+ };
106
+ }
107
+ } catch {
108
+ }
109
+ return local.impact(symbol, opts);
110
+ }
111
+ };
112
+ }
113
+ function resolveGraphBackend(input) {
114
+ if (input.repositoryId && input.socketPath) {
115
+ return vgdGraphBackend({
116
+ repositoryId: input.repositoryId,
117
+ gitRef: input.gitRef ?? void 0,
118
+ socketPath: input.socketPath,
119
+ fallback: input.graph
120
+ });
121
+ }
122
+ return localGraphBackend(input.graph);
123
+ }
124
+ function resolveSymbolId(graph, symbol) {
125
+ if (graph.nodes.some((n) => n.id === symbol)) return symbol;
126
+ const hit = resolveOne(graph, symbol);
127
+ if (hit.node?.id) return hit.node.id;
128
+ if (hit.candidates.length === 1 && hit.candidates[0]?.id) return hit.candidates[0].id;
129
+ const q = symbol.toLowerCase();
130
+ const byQn = graph.nodes.find((n) => n.qualifiedName?.toLowerCase() === q || n.name?.toLowerCase() === q);
131
+ return byQn?.id ?? null;
132
+ }
133
+
134
+ export { localGraphBackend, resolveGraphBackend, vgdGraphBackend };
135
+ //# sourceMappingURL=chunk-6AYDFFP5.js.map
136
+ //# sourceMappingURL=chunk-6AYDFFP5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/code/graph-backend.ts"],"names":[],"mappings":"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","file":"chunk-6AYDFFP5.js","sourcesContent":["/**\n * Graph query backend for the agent tool layer (Fusion Runtime).\n *\n * Tools prefer a warm ActiveGraph in vgd when a daemon session is attached;\n * otherwise they fall back to the in-process {@link VgGraph}. Failures never\n * surface to the model as transport errors — they degrade to local query.\n */\n\nimport { queryGraph } from '../engine/query.js';\nimport { impactOf } from '../engine/impact.js';\nimport { resolveOne } from '../engine/lookup.js';\nimport { vgdRequest, type VgdClientOptions } from '../runtime/vgd/client.js';\nimport type { VgdRequest } from '../runtime/vgd/protocol.js';\nimport type { VgGraph } from '../schema.js';\n\nexport type GraphBackendSource = 'local' | 'vgd';\n\nexport interface GraphSearchHit {\n id: string;\n qualifiedName: string;\n kind: string;\n file: string;\n line: number;\n score: number;\n why: string;\n signature?: string | null;\n}\n\nexport interface GraphImpactHit {\n id: string;\n name: string;\n kind: string;\n file: string;\n line: number;\n depth: number;\n confidence: number;\n}\n\nexport interface GraphImpactResult {\n root: { id: string; name: string };\n depth: number;\n affected: GraphImpactHit[];\n direct: number;\n transitive: number;\n source: GraphBackendSource;\n}\n\nexport interface GraphSearchResult {\n matches: GraphSearchHit[];\n source: GraphBackendSource;\n}\n\nexport interface GraphBackend {\n readonly source: GraphBackendSource;\n search(query: string, opts?: { limit?: number }): Promise<GraphSearchResult>;\n impact(symbol: string, opts?: { depth?: number }): Promise<GraphImpactResult | null>;\n}\n\n/** Pure in-process backend over a loaded graph. */\nexport function localGraphBackend(graph: VgGraph): GraphBackend {\n return {\n source: 'local',\n async search(query, opts) {\n const res = queryGraph(graph, query, { budget: 1500, limit: opts?.limit ?? 10 });\n return {\n source: 'local',\n matches: res.matches.map((m) => ({\n id: m.node.id,\n qualifiedName: m.node.qualifiedName,\n kind: m.node.kind,\n file: m.node.file,\n line: m.node.span?.start ?? 0,\n score: m.score,\n why: m.why,\n signature: m.node.signature ?? null,\n })),\n };\n },\n async impact(symbol, opts) {\n const node = resolveSymbolId(graph, symbol);\n if (!node) return null;\n const imp = impactOf(graph, node, { depth: opts?.depth ?? 4 });\n return {\n source: 'local',\n root: imp.root,\n depth: imp.depth,\n affected: imp.affected.map((a) => ({\n id: a.id,\n name: a.name,\n kind: a.kind,\n file: a.file,\n line: a.line,\n depth: a.depth,\n confidence: a.confidence,\n })),\n direct: imp.direct,\n transitive: imp.transitive,\n };\n },\n };\n}\n\nexport interface VgdGraphBackendOptions {\n repositoryId: string;\n gitRef?: string;\n socketPath?: string;\n /** Always required for fall back when vgd has no slot or is down. */\n fallback: VgGraph;\n request?: (req: VgdRequest, opts?: VgdClientOptions) => Promise<unknown>;\n}\n\n/**\n * Prefer vgd query/impact; on any failure or empty daemon state, use local.\n * The returned `source` reflects which path answered.\n */\nexport function vgdGraphBackend(options: VgdGraphBackendOptions): GraphBackend {\n const local = localGraphBackend(options.fallback);\n const request = options.request ?? ((req, opts) => vgdRequest(req, opts));\n const clientOpts: VgdClientOptions = { socketPath: options.socketPath };\n\n return {\n source: 'vgd',\n async search(query, opts) {\n try {\n const res = (await request(\n {\n op: 'query-graph',\n repositoryId: options.repositoryId,\n query,\n limit: opts?.limit ?? 10,\n gitRef: options.gitRef,\n },\n clientOpts,\n )) as {\n ok?: boolean;\n matches?: Array<{\n id: string;\n qualifiedName: string;\n kind: string;\n file: string;\n line: number;\n score: number;\n why: string;\n }>;\n };\n if (res?.ok && Array.isArray(res.matches)) {\n return {\n source: 'vgd',\n matches: res.matches.map((m) => ({\n id: m.id,\n qualifiedName: m.qualifiedName,\n kind: m.kind,\n file: m.file,\n line: m.line,\n score: m.score,\n why: m.why,\n signature: null,\n })),\n };\n }\n } catch {\n /* fall through */\n }\n return local.search(query, opts);\n },\n async impact(symbol, opts) {\n try {\n const res = (await request(\n {\n op: 'impact-of',\n repositoryId: options.repositoryId,\n symbol,\n depth: opts?.depth ?? 4,\n gitRef: options.gitRef,\n },\n clientOpts,\n )) as {\n ok?: boolean;\n root?: { id: string; name: string };\n depth?: number;\n affected?: GraphImpactHit[];\n direct?: number;\n transitive?: number;\n };\n if (res?.ok && res.root && Array.isArray(res.affected)) {\n return {\n source: 'vgd',\n root: res.root,\n depth: res.depth ?? opts?.depth ?? 4,\n affected: res.affected,\n direct: res.direct ?? 0,\n transitive: res.transitive ?? 0,\n };\n }\n } catch {\n /* fall through */\n }\n return local.impact(symbol, opts);\n },\n };\n}\n\n/**\n * Pick a backend: vgd when repositoryId + socket are known, else local.\n */\nexport function resolveGraphBackend(input: {\n graph: VgGraph;\n repositoryId?: string | null;\n gitRef?: string | null;\n socketPath?: string | null;\n}): GraphBackend {\n if (input.repositoryId && input.socketPath) {\n return vgdGraphBackend({\n repositoryId: input.repositoryId,\n gitRef: input.gitRef ?? undefined,\n socketPath: input.socketPath,\n fallback: input.graph,\n });\n }\n return localGraphBackend(input.graph);\n}\n\nfunction resolveSymbolId(graph: VgGraph, symbol: string): string | null {\n if (graph.nodes.some((n) => n.id === symbol)) return symbol;\n const hit = resolveOne(graph, symbol);\n if (hit.node?.id) return hit.node.id;\n if (hit.candidates.length === 1 && hit.candidates[0]?.id) return hit.candidates[0].id;\n const q = symbol.toLowerCase();\n const byQn = graph.nodes.find((n) => n.qualifiedName?.toLowerCase() === q || n.name?.toLowerCase() === q);\n return byQn?.id ?? null;\n}\n"]}
@@ -0,0 +1,122 @@
1
+ import { parseOllamaPs, parseNvidiaSmi } from './chunk-7N4Y3E47.js';
2
+ import * as os from 'os';
3
+ import { spawnSync, spawn } from 'child_process';
4
+ import * as fs from 'fs';
5
+
6
+ function parseVmStatAvailableBytes(stdout) {
7
+ if (!stdout || !/Pages free:/i.test(stdout)) return null;
8
+ const pageMatch = stdout.match(/page size of (\d+) bytes/i);
9
+ const pageSize = pageMatch ? Number(pageMatch[1]) : 4096;
10
+ if (!Number.isFinite(pageSize) || pageSize <= 0) return null;
11
+ const pages = (label) => {
12
+ const m = stdout.match(new RegExp(`${label}:\\s+(\\d+)\\.?`, "i"));
13
+ return m ? Number(m[1]) : 0;
14
+ };
15
+ const free = pages("Pages free");
16
+ const inactive = pages("Pages inactive");
17
+ const speculative = pages("Pages speculative");
18
+ const purgeable = pages("Pages purgeable");
19
+ const totalPages = free + inactive + speculative + purgeable;
20
+ if (!Number.isFinite(totalPages) || totalPages < 0) return null;
21
+ return totalPages * pageSize;
22
+ }
23
+ function parseMeminfoAvailableBytes(content) {
24
+ if (!content) return null;
25
+ const avail = content.match(/^MemAvailable:\s+(\d+)\s*kB/im);
26
+ if (avail) {
27
+ const n = Number(avail[1]) * 1024;
28
+ return Number.isFinite(n) && n >= 0 ? n : null;
29
+ }
30
+ const free = content.match(/^MemFree:\s+(\d+)\s*kB/im);
31
+ if (free) {
32
+ const n = Number(free[1]) * 1024;
33
+ return Number.isFinite(n) && n >= 0 ? n : null;
34
+ }
35
+ return null;
36
+ }
37
+ function availableRamBytes(platform = process.platform, freemem2 = () => os.freemem()) {
38
+ const nodeFree = safeNonNeg(freemem2());
39
+ let platformAvail = null;
40
+ if (platform === "darwin") {
41
+ platformAvail = readMacAvailableBytes();
42
+ } else if (platform === "linux") {
43
+ platformAvail = readLinuxAvailableBytes();
44
+ }
45
+ if (platformAvail != null && platformAvail > nodeFree) return platformAvail;
46
+ return nodeFree;
47
+ }
48
+ function readMacAvailableBytes() {
49
+ try {
50
+ const res = spawnSync("vm_stat", [], { encoding: "utf8", timeout: 3e3 });
51
+ if (res.status !== 0 || typeof res.stdout !== "string") return null;
52
+ return parseVmStatAvailableBytes(res.stdout);
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+ function readLinuxAvailableBytes() {
58
+ try {
59
+ const content = fs.readFileSync("/proc/meminfo", "utf8");
60
+ return parseMeminfoAvailableBytes(content);
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
65
+ function safeNonNeg(n) {
66
+ return Number.isFinite(n) && n > 0 ? n : 0;
67
+ }
68
+
69
+ // src/code/local-runtime.ts
70
+ function gatherSystemMemory() {
71
+ const loaded = safeRun("ollama", ["ps"]).map(parseOllamaPs).flat();
72
+ const smi = safeRun("nvidia-smi", ["--query-gpu=memory.total,memory.used", "--format=csv,noheader,nounits"]).map(parseNvidiaSmi).find(Boolean);
73
+ const sys = {
74
+ totalRamBytes: os.totalmem(),
75
+ freeRamBytes: availableRamBytes(),
76
+ loaded
77
+ };
78
+ if (smi) {
79
+ sys.vramTotalBytes = smi.totalBytes;
80
+ sys.vramFreeBytes = Math.max(0, smi.totalBytes - smi.usedBytes);
81
+ }
82
+ return sys;
83
+ }
84
+ function hasOllama() {
85
+ return spawnSync(process.platform === "win32" ? "where" : "which", ["ollama"], { stdio: "ignore" }).status === 0;
86
+ }
87
+ function stopModel(name) {
88
+ return spawnSync("ollama", ["stop", name], { stdio: "ignore" }).status === 0;
89
+ }
90
+ function pullModelClean(name, spinner) {
91
+ return new Promise((resolve) => {
92
+ const child = spawn("ollama", ["pull", name]);
93
+ const onData = (buf) => {
94
+ const line = lastMeaningfulLine(buf.toString());
95
+ if (line) spinner.update(`pulling ${name} \u2014 ${line}`);
96
+ };
97
+ child.stdout?.on("data", onData);
98
+ child.stderr?.on("data", onData);
99
+ child.on("error", () => resolve(false));
100
+ child.on("close", (code) => resolve(code === 0));
101
+ });
102
+ }
103
+ function lastMeaningfulLine(chunk) {
104
+ const lines = chunk.split(/[\r\n]+/).map((l) => l.trim()).map((l) => l.replace(/\x1b\[[0-9;]*[A-Za-z]/g, "").replace(/[▏▎▍▌▋▊▉█░▒▓⣀-⣿]/g, "").trim()).filter(Boolean);
105
+ const last = lines[lines.length - 1] ?? "";
106
+ const pct = last.match(/(\d+)\s*%/);
107
+ const status = last.replace(/\s{2,}.*$/, "").slice(0, 48);
108
+ return pct ? `${status} ${pct[1]}%`.trim() : status;
109
+ }
110
+ function safeRun(bin, args) {
111
+ try {
112
+ const res = spawnSync(bin, args, { encoding: "utf8", timeout: 5e3 });
113
+ if (res.status !== 0 || typeof res.stdout !== "string") return [];
114
+ return [res.stdout];
115
+ } catch {
116
+ return [];
117
+ }
118
+ }
119
+
120
+ export { gatherSystemMemory, hasOllama, pullModelClean, stopModel };
121
+ //# sourceMappingURL=chunk-6UQMXIAG.js.map
122
+ //# sourceMappingURL=chunk-6UQMXIAG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/code/available-memory.ts","../src/code/local-runtime.ts"],"names":["freemem","os2","spawnSync"],"mappings":"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","file":"chunk-6UQMXIAG.js","sourcesContent":["/**\n * Platform-accurate *available* RAM for model fit decisions.\n *\n * Node's `os.freemem()` is wrong for this use case on several OSes:\n * - **macOS**: returns only completely unused pages. The kernel fills the rest\n * with file cache that is reclaimable under pressure — Activity Monitor's\n * \"Available\" (and what a model can actually use). Under normal load\n * `os.freemem()` often reports ~0 while many GiB are available.\n * - **Linux**: prefers `/proc/meminfo` `MemAvailable` (reclaim-aware) over\n * `MemFree`.\n * - **Windows**: `os.freemem()` already maps to available physical memory\n * (`GlobalMemoryStatusEx.ullAvailPhys`) and is fine.\n *\n * Fit/install gates must use *available* memory, not bare free pages, or\n * Spark/Flow falsely report \"0.0 GiB free after reserves\" on machines with\n * tens of GiB of reclaimable RAM.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport { spawnSync } from 'node:child_process';\n\n/**\n * Parse `vm_stat` output into reclaimable/available bytes.\n * Available ≈ free + inactive + speculative + purgeable (file cache that the\n * kernel can reclaim). Returns null when the output is unparseable.\n */\nexport function parseVmStatAvailableBytes(stdout: string): number | null {\n if (!stdout || !/Pages free:/i.test(stdout)) return null;\n const pageMatch = stdout.match(/page size of (\\d+) bytes/i);\n // Apple Silicon is typically 16 KiB; Intel macOS 4 KiB. Default conservatively.\n const pageSize = pageMatch ? Number(pageMatch[1]) : 4096;\n if (!Number.isFinite(pageSize) || pageSize <= 0) return null;\n\n const pages = (label: string): number => {\n // Lines look like: \"Pages free: 4085.\"\n const m = stdout.match(new RegExp(`${label}:\\\\s+(\\\\d+)\\\\.?`, 'i'));\n return m ? Number(m[1]) : 0;\n };\n\n const free = pages('Pages free');\n const inactive = pages('Pages inactive');\n const speculative = pages('Pages speculative');\n const purgeable = pages('Pages purgeable');\n const totalPages = free + inactive + speculative + purgeable;\n if (!Number.isFinite(totalPages) || totalPages < 0) return null;\n return totalPages * pageSize;\n}\n\n/**\n * Parse `/proc/meminfo` for MemAvailable (kB). Falls back to MemFree when\n * MemAvailable is missing (very old kernels).\n */\nexport function parseMeminfoAvailableBytes(content: string): number | null {\n if (!content) return null;\n const avail = content.match(/^MemAvailable:\\s+(\\d+)\\s*kB/im);\n if (avail) {\n const n = Number(avail[1]) * 1024;\n return Number.isFinite(n) && n >= 0 ? n : null;\n }\n const free = content.match(/^MemFree:\\s+(\\d+)\\s*kB/im);\n if (free) {\n const n = Number(free[1]) * 1024;\n return Number.isFinite(n) && n >= 0 ? n : null;\n }\n return null;\n}\n\n/** Best-effort available RAM in bytes. Never throws; falls back to os.freemem(). */\nexport function availableRamBytes(\n platform: NodeJS.Platform = process.platform,\n freemem: () => number = () => os.freemem(),\n): number {\n const nodeFree = safeNonNeg(freemem());\n let platformAvail: number | null = null;\n\n if (platform === 'darwin') {\n platformAvail = readMacAvailableBytes();\n } else if (platform === 'linux') {\n platformAvail = readLinuxAvailableBytes();\n }\n // win32 and others: Node freemem is already \"available\".\n\n // Prefer the larger of the two when both exist — never under-report\n // availability because of a stale/partial platform probe.\n if (platformAvail != null && platformAvail > nodeFree) return platformAvail;\n return nodeFree;\n}\n\nfunction readMacAvailableBytes(): number | null {\n try {\n const res = spawnSync('vm_stat', [], { encoding: 'utf8', timeout: 3000 });\n if (res.status !== 0 || typeof res.stdout !== 'string') return null;\n return parseVmStatAvailableBytes(res.stdout);\n } catch {\n return null;\n }\n}\n\nfunction readLinuxAvailableBytes(): number | null {\n try {\n const content = fs.readFileSync('/proc/meminfo', 'utf8');\n return parseMeminfoAvailableBytes(content);\n } catch {\n return null;\n }\n}\n\nfunction safeNonNeg(n: number): number {\n return Number.isFinite(n) && n > 0 ? n : 0;\n}\n","/**\n * Thin I/O wrappers around the local model runtime (Ollama / GPU) for the\n * `vg code` guided flow (VG-CLI-CODE §10). The pure parsing/estimation these\n * feed lives in capability.ts and is unit-tested; this file just gathers real\n * system state and wraps the noisy `ollama pull` behind a single clean status\n * line (no raw progress spam), per the \"clean UI for devs\" requirement.\n */\n\nimport * as os from 'node:os';\nimport { spawn, spawnSync } from 'node:child_process';\nimport { availableRamBytes } from './available-memory.js';\nimport { parseOllamaPs, parseNvidiaSmi, type SystemMemory } from './capability.js';\nimport type { Spinner } from './ui.js';\n\n/**\n * Gather current system memory, loaded models, and (best-effort) GPU VRAM.\n *\n * `freeRamBytes` is *available* RAM (reclaim-aware on macOS/Linux), not bare\n * free pages from `os.freemem()` — see `available-memory.ts`.\n */\nexport function gatherSystemMemory(): SystemMemory {\n const loaded = safeRun('ollama', ['ps']).map(parseOllamaPs).flat();\n const smi = safeRun('nvidia-smi', ['--query-gpu=memory.total,memory.used', '--format=csv,noheader,nounits'])\n .map(parseNvidiaSmi)\n .find(Boolean);\n const sys: SystemMemory = {\n totalRamBytes: os.totalmem(),\n freeRamBytes: availableRamBytes(),\n loaded,\n };\n if (smi) {\n sys.vramTotalBytes = smi.totalBytes;\n sys.vramFreeBytes = Math.max(0, smi.totalBytes - smi.usedBytes);\n }\n return sys;\n}\n\n/** True if the `ollama` binary is on PATH. */\nexport function hasOllama(): boolean {\n return spawnSync(process.platform === 'win32' ? 'where' : 'which', ['ollama'], { stdio: 'ignore' }).status === 0;\n}\n\n/** Unload a running model to free memory. Returns true on success. */\nexport function stopModel(name: string): boolean {\n return spawnSync('ollama', ['stop', name], { stdio: 'ignore' }).status === 0;\n}\n\n/**\n * Pull a model, wrapping Ollama's chatty progress in one clean spinner line.\n * We read its stderr, keep only the latest human-meaningful status (e.g.\n * \"pulling manifest\", \"downloading … 42%\"), and never echo the raw stream.\n */\nexport function pullModelClean(name: string, spinner: Spinner): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn('ollama', ['pull', name]);\n const onData = (buf: Buffer): void => {\n const line = lastMeaningfulLine(buf.toString());\n if (line) spinner.update(`pulling ${name} — ${line}`);\n };\n child.stdout?.on('data', onData);\n child.stderr?.on('data', onData);\n child.on('error', () => resolve(false));\n child.on('close', (code) => resolve(code === 0));\n });\n}\n\n/** The last non-empty, de-noised status token from an ollama progress chunk. */\nfunction lastMeaningfulLine(chunk: string): string {\n const lines = chunk\n .split(/[\\r\\n]+/)\n .map((l) => l.trim())\n // ollama redraws a progress bar with escape codes; strip them and bar glyphs.\n .map((l) => l.replace(/\\x1b\\[[0-9;]*[A-Za-z]/g, '').replace(/[▏▎▍▌▋▊▉█░▒▓⣀-⣿]/g, '').trim())\n .filter(Boolean);\n const last = lines[lines.length - 1] ?? '';\n // Keep a short, meaningful summary (status + any percentage).\n const pct = last.match(/(\\d+)\\s*%/);\n const status = last.replace(/\\s{2,}.*$/, '').slice(0, 48);\n return pct ? `${status} ${pct[1]}%`.trim() : status;\n}\n\n/** Run a command and return its stdout lines (or [] if the binary is missing/fails). */\nfunction safeRun(bin: string, args: string[]): string[] {\n try {\n const res = spawnSync(bin, args, { encoding: 'utf8', timeout: 5000 });\n if (res.status !== 0 || typeof res.stdout !== 'string') return [];\n return [res.stdout];\n } catch {\n return [];\n }\n}\n"]}
@@ -0,0 +1,108 @@
1
+ // src/code/capability.ts
2
+ var GiB = 1024 ** 3;
3
+ var QUANT_BYTES_PER_PARAM = {
4
+ f16: 2,
5
+ fp16: 2,
6
+ f32: 4,
7
+ q8: 1.06,
8
+ q8_0: 1.06,
9
+ q6: 0.82,
10
+ q6_k: 0.82,
11
+ q5: 0.7,
12
+ q5_k_m: 0.72,
13
+ q5_k_s: 0.68,
14
+ q5_0: 0.71,
15
+ q5_1: 0.77,
16
+ q4: 0.58,
17
+ q4_k_m: 0.6,
18
+ q4_k_s: 0.56,
19
+ q4_0: 0.56,
20
+ q4_1: 0.63,
21
+ q3: 0.46,
22
+ q3_k_m: 0.48,
23
+ q3_k_s: 0.44,
24
+ q2: 0.36,
25
+ q2_k: 0.4
26
+ };
27
+ var DEFAULT_QUANT = "q4_k_m";
28
+ var RUNTIME_OVERHEAD = 1.2;
29
+ function estimateModelBytes(slug, defaultParamsB = 7) {
30
+ const lower = slug.toLowerCase();
31
+ const paramMatch = lower.match(/(\d+(?:\.\d+)?)\s*b\b/);
32
+ const paramsB = paramMatch ? Number(paramMatch[1]) : void 0;
33
+ const quant = detectQuant(lower);
34
+ const bytesPerParam = QUANT_BYTES_PER_PARAM[quant] ?? QUANT_BYTES_PER_PARAM[DEFAULT_QUANT];
35
+ const effectiveParams = (paramsB ?? defaultParamsB) * 1e9;
36
+ const bytes = Math.round(effectiveParams * bytesPerParam * RUNTIME_OVERHEAD);
37
+ return { paramsB, quant, bytes, guessed: paramsB === void 0 };
38
+ }
39
+ function detectQuant(lower) {
40
+ const keys = Object.keys(QUANT_BYTES_PER_PARAM).sort((a, b) => b.length - a.length);
41
+ for (const k of keys) if (lower.includes(k)) return k;
42
+ return DEFAULT_QUANT;
43
+ }
44
+ function parseOllamaPs(stdout) {
45
+ const lines = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
46
+ const out = [];
47
+ for (const line of lines) {
48
+ if (/^NAME\b/i.test(line)) continue;
49
+ const sizeMatch = line.match(/(\d+(?:\.\d+)?)\s*(GB|GiB|MB|MiB|TB)/i);
50
+ const name = line.split(/\s+/)[0];
51
+ if (!name || !sizeMatch) continue;
52
+ out.push({ name, bytes: toBytes(Number(sizeMatch[1]), sizeMatch[2]) });
53
+ }
54
+ return out;
55
+ }
56
+ function parseNvidiaSmi(stdout) {
57
+ const line = stdout.split("\n").map((l) => l.trim()).find(Boolean);
58
+ if (!line) return null;
59
+ const parts = line.split(",").map((p) => Number(p.trim()));
60
+ if (parts.length < 2 || !Number.isFinite(parts[0]) || !Number.isFinite(parts[1])) return null;
61
+ return { totalBytes: parts[0] * 1024 * 1024, usedBytes: parts[1] * 1024 * 1024 };
62
+ }
63
+ function assessCapability(model, sys) {
64
+ const useVram = typeof sys.vramTotalBytes === "number" && sys.vramTotalBytes > 0;
65
+ const free = useVram ? sys.vramFreeBytes ?? 0 : sys.freeRamBytes;
66
+ const loadedBytes = sys.loaded.reduce((n, m) => n + m.bytes, 0);
67
+ const margin = Math.min(2 * GiB, (useVram ? sys.vramTotalBytes : sys.totalRamBytes) * 0.1);
68
+ const available = Math.max(0, free - margin);
69
+ const availableIfUnloaded = Math.max(0, free + loadedBytes - margin);
70
+ const need = model.bytes;
71
+ const canRunNow = available >= need;
72
+ const canRunUnloaded = availableIfUnloaded >= need;
73
+ const suggestions = [];
74
+ if (!canRunNow && canRunUnloaded && sys.loaded.length) {
75
+ const biggest = [...sys.loaded].sort((a, b) => b.bytes - a.bytes);
76
+ suggestions.push(`unload a loaded model to free memory (e.g. \`ollama stop ${biggest[0].name}\` frees ~${fmt(biggest[0].bytes)})`);
77
+ }
78
+ if (!canRunUnloaded) {
79
+ suggestions.push(`this model needs ~${fmt(need)} but only ~${fmt(availableIfUnloaded)} is available \u2014 choose a smaller model or a lower quant (e.g. q4_K_M)`);
80
+ }
81
+ if (model.guessed) {
82
+ suggestions.push(`couldn't read the parameter count from the name \u2014 this estimate assumes a ~${(model.bytes / GiB).toFixed(1)} GiB model; verify before pulling`);
83
+ }
84
+ return {
85
+ model,
86
+ availableBytes: available,
87
+ availableIfUnloadedBytes: availableIfUnloaded,
88
+ canRun: canRunNow || canRunUnloaded,
89
+ needsUnload: !canRunNow && canRunUnloaded,
90
+ suggestions,
91
+ loaded: sys.loaded
92
+ };
93
+ }
94
+ function fmt(bytes) {
95
+ if (bytes >= GiB) return `${(bytes / GiB).toFixed(1)} GiB`;
96
+ return `${(bytes / (1024 * 1024)).toFixed(0)} MiB`;
97
+ }
98
+ function toBytes(n, unit) {
99
+ const u = unit.toLowerCase();
100
+ if (u.startsWith("t")) return n * 1e3 ** 4;
101
+ if (u.startsWith("g")) return n * (u.includes("i") ? GiB : 1e9);
102
+ if (u.startsWith("m")) return n * (u.includes("i") ? 1024 * 1024 : 1e6);
103
+ return n;
104
+ }
105
+
106
+ export { assessCapability, estimateModelBytes, fmt, parseNvidiaSmi, parseOllamaPs };
107
+ //# sourceMappingURL=chunk-7N4Y3E47.js.map
108
+ //# sourceMappingURL=chunk-7N4Y3E47.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/code/capability.ts"],"names":[],"mappings":";AAeA,IAAM,MAAM,IAAA,IAAQ,CAAA;AAGpB,IAAM,qBAAA,GAAgD;AAAA,EACpD,GAAA,EAAK,CAAA;AAAA,EAAK,IAAA,EAAM,CAAA;AAAA,EAAK,GAAA,EAAK,CAAA;AAAA,EAC1B,EAAA,EAAI,IAAA;AAAA,EAAM,IAAA,EAAM,IAAA;AAAA,EAChB,EAAA,EAAI,IAAA;AAAA,EAAM,IAAA,EAAM,IAAA;AAAA,EAChB,EAAA,EAAI,GAAA;AAAA,EAAK,MAAA,EAAQ,IAAA;AAAA,EAAM,MAAA,EAAQ,IAAA;AAAA,EAAM,IAAA,EAAM,IAAA;AAAA,EAAM,IAAA,EAAM,IAAA;AAAA,EACvD,EAAA,EAAI,IAAA;AAAA,EAAM,MAAA,EAAQ,GAAA;AAAA,EAAK,MAAA,EAAQ,IAAA;AAAA,EAAM,IAAA,EAAM,IAAA;AAAA,EAAM,IAAA,EAAM,IAAA;AAAA,EACvD,EAAA,EAAI,IAAA;AAAA,EAAM,MAAA,EAAQ,IAAA;AAAA,EAAM,MAAA,EAAQ,IAAA;AAAA,EAChC,EAAA,EAAI,IAAA;AAAA,EAAM,IAAA,EAAM;AAClB,CAAA;AACA,IAAM,aAAA,GAAgB,QAAA;AAEtB,IAAM,gBAAA,GAAmB,GAAA;AAiBlB,SAAS,kBAAA,CAAmB,IAAA,EAAc,cAAA,GAAiB,CAAA,EAAsB;AACtF,EAAA,MAAM,KAAA,GAAQ,KAAK,WAAA,EAAY;AAC/B,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,uBAAuB,CAAA;AACtD,EAAA,MAAM,UAAU,UAAA,GAAa,MAAA,CAAO,UAAA,CAAW,CAAC,CAAC,CAAA,GAAI,MAAA;AACrD,EAAA,MAAM,KAAA,GAAQ,YAAY,KAAK,CAAA;AAC/B,EAAA,MAAM,aAAA,GAAgB,qBAAA,CAAsB,KAAK,CAAA,IAAK,sBAAsB,aAAa,CAAA;AACzF,EAAA,MAAM,eAAA,GAAA,CAAmB,WAAW,cAAA,IAAkB,GAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,eAAA,GAAkB,gBAAgB,gBAAgB,CAAA;AAC3E,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,YAAY,MAAA,EAAU;AACjE;AAEA,SAAS,YAAY,KAAA,EAAuB;AAE1C,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,qBAAqB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,MAAM,CAAA;AAClF,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM,IAAI,MAAM,QAAA,CAAS,CAAC,GAAG,OAAO,CAAA;AACpD,EAAA,OAAO,aAAA;AACT;AAWO,SAAS,cAAc,MAAA,EAA+B;AAC3D,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AACpE,EAAA,MAAM,MAAqB,EAAC;AAC5B,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAI,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA,EAAG;AAC3B,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,uCAAuC,CAAA;AACpE,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,KAAK,EAAE,CAAC,CAAA;AAChC,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,SAAA,EAAW;AACzB,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,QAAQ,MAAA,CAAO,SAAA,CAAU,CAAC,CAAC,CAAA,EAAG,SAAA,CAAU,CAAC,CAAC,GAAG,CAAA;AAAA,EACvE;AACA,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,eAAe,MAAA,EAAkE;AAC/F,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,KAAK,OAAO,CAAA;AACjE,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,IAAA,EAAM,CAAC,CAAA;AACzD,EAAA,IAAI,MAAM,MAAA,GAAS,CAAA,IAAK,CAAC,MAAA,CAAO,SAAS,KAAA,CAAM,CAAC,CAAC,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAC,GAAG,OAAO,IAAA;AACzF,EAAA,OAAO,EAAE,UAAA,EAAY,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,GAAO,IAAA,EAAM,SAAA,EAAW,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA,GAAO,IAAA,EAAK;AACjF;AAkCO,SAAS,gBAAA,CAAiB,OAA0B,GAAA,EAAqC;AAC9F,EAAA,MAAM,UAAU,OAAO,GAAA,CAAI,cAAA,KAAmB,QAAA,IAAY,IAAI,cAAA,GAAiB,CAAA;AAC/E,EAAA,MAAM,IAAA,GAAO,OAAA,GAAW,GAAA,CAAI,aAAA,IAAiB,IAAK,GAAA,CAAI,YAAA;AACtD,EAAA,MAAM,WAAA,GAAc,GAAA,CAAI,MAAA,CAAO,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,CAAA,CAAE,KAAA,EAAO,CAAC,CAAA;AAE9D,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,GAAA,EAAA,CAAM,UAAU,GAAA,CAAI,cAAA,GAAkB,GAAA,CAAI,aAAA,IAAiB,GAAG,CAAA;AAC1F,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,MAAM,CAAA;AAC3C,EAAA,MAAM,sBAAsB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,GAAO,cAAc,MAAM,CAAA;AAEnE,EAAA,MAAM,OAAO,KAAA,CAAM,KAAA;AACnB,EAAA,MAAM,YAAY,SAAA,IAAa,IAAA;AAC/B,EAAA,MAAM,iBAAiB,mBAAA,IAAuB,IAAA;AAE9C,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,IAAI,CAAC,SAAA,IAAa,cAAA,IAAkB,GAAA,CAAI,OAAO,MAAA,EAAQ;AACrD,IAAA,MAAM,OAAA,GAAU,CAAC,GAAG,GAAA,CAAI,MAAM,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AAChE,IAAA,WAAA,CAAY,IAAA,CAAK,CAAA,yDAAA,EAA4D,OAAA,CAAQ,CAAC,CAAA,CAAE,IAAI,CAAA,UAAA,EAAa,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAA,CAAE,KAAK,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,EACnI;AACA,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,WAAA,CAAY,IAAA,CAAK,qBAAqB,GAAA,CAAI,IAAI,CAAC,CAAA,WAAA,EAAc,GAAA,CAAI,mBAAmB,CAAC,CAAA,0EAAA,CAAuE,CAAA;AAAA,EAC9J;AACA,EAAA,IAAI,MAAM,OAAA,EAAS;AACjB,IAAA,WAAA,CAAY,IAAA,CAAK,oFAA+E,KAAA,CAAM,KAAA,GAAQ,KAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,iCAAA,CAAmC,CAAA;AAAA,EAClK;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,cAAA,EAAgB,SAAA;AAAA,IAChB,wBAAA,EAA0B,mBAAA;AAAA,IAC1B,QAAQ,SAAA,IAAa,cAAA;AAAA,IACrB,WAAA,EAAa,CAAC,SAAA,IAAa,cAAA;AAAA,IAC3B,WAAA;AAAA,IACA,QAAQ,GAAA,CAAI;AAAA,GACd;AACF;AAGO,SAAS,IAAI,KAAA,EAAuB;AACzC,EAAA,IAAI,KAAA,IAAS,KAAK,OAAO,CAAA,EAAA,CAAI,QAAQ,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAC,CAAA,IAAA,CAAA;AACpD,EAAA,OAAO,IAAI,KAAA,IAAS,IAAA,GAAO,IAAA,CAAA,EAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,IAAA,CAAA;AAC9C;AAEA,SAAS,OAAA,CAAQ,GAAW,IAAA,EAAsB;AAChD,EAAA,MAAM,CAAA,GAAI,KAAK,WAAA,EAAY;AAC3B,EAAA,IAAI,EAAE,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,IAAI,GAAA,IAAQ,CAAA;AAC1C,EAAA,IAAI,CAAA,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,KAAK,CAAA,CAAE,QAAA,CAAS,GAAG,CAAA,GAAI,GAAA,GAAM,GAAA,CAAA;AAC3D,EAAA,IAAI,CAAA,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,CAAA,IAAK,CAAA,CAAE,QAAA,CAAS,GAAG,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,GAAA,CAAA;AACnE,EAAA,OAAO,CAAA;AACT","file":"chunk-7N4Y3E47.js","sourcesContent":["/**\n * Local capability + memory pre-flight for `vg code` (VG-CLI-CODE §10).\n *\n * Before we ever pull or run a local model we check the machine can actually\n * hold it: estimate the model's memory footprint from its parameter count and\n * quantization, read available system memory (and GPU VRAM where we can see\n * it), account for models already loaded, and produce a clear go / no-go with\n * actionable suggestions — free memory by unloading a model, pick a smaller\n * quant, or don't install. We never download a model the machine can't run.\n *\n * The estimators and parsers here are pure and unit-tested; the command layer\n * feeds them real `os` memory, `ollama ps`, and (best-effort) `nvidia-smi`\n * output.\n */\n\nconst GiB = 1024 ** 3;\n\n/** Approximate bytes-per-weight for common gguf quantizations. */\nconst QUANT_BYTES_PER_PARAM: Record<string, number> = {\n f16: 2.0, fp16: 2.0, f32: 4.0,\n q8: 1.06, q8_0: 1.06,\n q6: 0.82, q6_k: 0.82,\n q5: 0.7, q5_k_m: 0.72, q5_k_s: 0.68, q5_0: 0.71, q5_1: 0.77,\n q4: 0.58, q4_k_m: 0.6, q4_k_s: 0.56, q4_0: 0.56, q4_1: 0.63,\n q3: 0.46, q3_k_m: 0.48, q3_k_s: 0.44,\n q2: 0.36, q2_k: 0.4,\n};\nconst DEFAULT_QUANT = 'q4_k_m';\n/** Runtime overhead over raw weights: KV cache, context, activations. */\nconst RUNTIME_OVERHEAD = 1.2;\n\nexport interface ModelSizeEstimate {\n /** Parsed parameter count in billions (e.g. 7, 13, 70), or undefined if unknown. */\n paramsB?: number;\n quant: string;\n /** Estimated resident bytes to run the model (weights × quant × overhead). */\n bytes: number;\n /** True when we had to guess the size because the slug didn't state params. */\n guessed: boolean;\n}\n\n/**\n * Estimate a model's memory footprint from its slug/name/tag, e.g.\n * `qwen2.5-coder:7b-instruct-q4_K_M` → ~5 GiB. Falls back to a conservative\n * default size when the parameter count isn't stated.\n */\nexport function estimateModelBytes(slug: string, defaultParamsB = 7): ModelSizeEstimate {\n const lower = slug.toLowerCase();\n const paramMatch = lower.match(/(\\d+(?:\\.\\d+)?)\\s*b\\b/);\n const paramsB = paramMatch ? Number(paramMatch[1]) : undefined;\n const quant = detectQuant(lower);\n const bytesPerParam = QUANT_BYTES_PER_PARAM[quant] ?? QUANT_BYTES_PER_PARAM[DEFAULT_QUANT];\n const effectiveParams = (paramsB ?? defaultParamsB) * 1e9;\n const bytes = Math.round(effectiveParams * bytesPerParam * RUNTIME_OVERHEAD);\n return { paramsB, quant, bytes, guessed: paramsB === undefined };\n}\n\nfunction detectQuant(lower: string): string {\n // Longest key match first so `q4_k_m` beats `q4`.\n const keys = Object.keys(QUANT_BYTES_PER_PARAM).sort((a, b) => b.length - a.length);\n for (const k of keys) if (lower.includes(k)) return k;\n return DEFAULT_QUANT;\n}\n\nexport interface LoadedModel {\n name: string;\n bytes: number;\n}\n\n/**\n * Parse `ollama ps` output into currently-loaded models and their sizes. The\n * table looks like: `NAME ID SIZE PROCESSOR UNTIL` with SIZE like `5.5 GB`.\n */\nexport function parseOllamaPs(stdout: string): LoadedModel[] {\n const lines = stdout.split('\\n').map((l) => l.trim()).filter(Boolean);\n const out: LoadedModel[] = [];\n for (const line of lines) {\n if (/^NAME\\b/i.test(line)) continue; // header\n const sizeMatch = line.match(/(\\d+(?:\\.\\d+)?)\\s*(GB|GiB|MB|MiB|TB)/i);\n const name = line.split(/\\s+/)[0];\n if (!name || !sizeMatch) continue;\n out.push({ name, bytes: toBytes(Number(sizeMatch[1]), sizeMatch[2]) });\n }\n return out;\n}\n\n/** Parse `nvidia-smi --query-gpu=memory.total,memory.used --format=csv,noheader,nounits` (MiB). */\nexport function parseNvidiaSmi(stdout: string): { totalBytes: number; usedBytes: number } | null {\n const line = stdout.split('\\n').map((l) => l.trim()).find(Boolean);\n if (!line) return null;\n const parts = line.split(',').map((p) => Number(p.trim()));\n if (parts.length < 2 || !Number.isFinite(parts[0]) || !Number.isFinite(parts[1])) return null;\n return { totalBytes: parts[0] * 1024 * 1024, usedBytes: parts[1] * 1024 * 1024 };\n}\n\nexport interface SystemMemory {\n totalRamBytes: number;\n /**\n * Bytes available for a new allocation right now (reclaim-aware on macOS/Linux —\n * not bare free pages from `os.freemem()`, which under-reports on macOS).\n */\n freeRamBytes: number;\n /** GPU total/free if a discrete GPU was detected (else undefined → CPU/unified). */\n vramTotalBytes?: number;\n vramFreeBytes?: number;\n loaded: LoadedModel[];\n}\n\nexport interface CapabilityReport {\n model: ModelSizeEstimate;\n /** Bytes available to a new model right now (the larger of free VRAM or free RAM). */\n availableBytes: number;\n /** Bytes available if every currently-loaded model were unloaded. */\n availableIfUnloadedBytes: number;\n canRun: boolean;\n /** True only after unloading currently-loaded models. */\n needsUnload: boolean;\n suggestions: string[];\n loaded: LoadedModel[];\n}\n\n/**\n * Decide whether `model` can run on `sys`, and if not, what to do about it.\n * Prefers GPU memory when a discrete GPU is present, else system RAM (covers\n * Apple-silicon unified memory too). Leaves a safety margin so we don't wedge\n * the machine at 100% memory.\n */\nexport function assessCapability(model: ModelSizeEstimate, sys: SystemMemory): CapabilityReport {\n const useVram = typeof sys.vramTotalBytes === 'number' && sys.vramTotalBytes > 0;\n const free = useVram ? (sys.vramFreeBytes ?? 0) : sys.freeRamBytes;\n const loadedBytes = sys.loaded.reduce((n, m) => n + m.bytes, 0);\n // A margin so we never fill memory completely.\n const margin = Math.min(2 * GiB, (useVram ? sys.vramTotalBytes! : sys.totalRamBytes) * 0.1);\n const available = Math.max(0, free - margin);\n const availableIfUnloaded = Math.max(0, free + loadedBytes - margin);\n\n const need = model.bytes;\n const canRunNow = available >= need;\n const canRunUnloaded = availableIfUnloaded >= need;\n\n const suggestions: string[] = [];\n if (!canRunNow && canRunUnloaded && sys.loaded.length) {\n const biggest = [...sys.loaded].sort((a, b) => b.bytes - a.bytes);\n suggestions.push(`unload a loaded model to free memory (e.g. \\`ollama stop ${biggest[0].name}\\` frees ~${fmt(biggest[0].bytes)})`);\n }\n if (!canRunUnloaded) {\n suggestions.push(`this model needs ~${fmt(need)} but only ~${fmt(availableIfUnloaded)} is available — choose a smaller model or a lower quant (e.g. q4_K_M)`);\n }\n if (model.guessed) {\n suggestions.push(`couldn't read the parameter count from the name — this estimate assumes a ~${(model.bytes / GiB).toFixed(1)} GiB model; verify before pulling`);\n }\n\n return {\n model,\n availableBytes: available,\n availableIfUnloadedBytes: availableIfUnloaded,\n canRun: canRunNow || canRunUnloaded,\n needsUnload: !canRunNow && canRunUnloaded,\n suggestions,\n loaded: sys.loaded,\n };\n}\n\n/** Human-readable byte size. */\nexport function fmt(bytes: number): string {\n if (bytes >= GiB) return `${(bytes / GiB).toFixed(1)} GiB`;\n return `${(bytes / (1024 * 1024)).toFixed(0)} MiB`;\n}\n\nfunction toBytes(n: number, unit: string): number {\n const u = unit.toLowerCase();\n if (u.startsWith('t')) return n * 1000 ** 4;\n if (u.startsWith('g')) return n * (u.includes('i') ? GiB : 1e9);\n if (u.startsWith('m')) return n * (u.includes('i') ? 1024 * 1024 : 1e6);\n return n;\n}\n"]}