@vibgrate/cli 2026.814.2 → 2026.817.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.
- package/DOCS.md +61 -0
- package/README.md +1 -0
- package/dist/agent-UQC7QN77.js +27 -0
- package/dist/{agent-5ANHRYEI.js.map → agent-UQC7QN77.js.map} +1 -1
- package/dist/{approvals-T2KXPJLV.js → approvals-ASPJQUZK.js} +6 -5
- package/dist/{approvals-T2KXPJLV.js.map → approvals-ASPJQUZK.js.map} +1 -1
- package/dist/baseline-FIV6PR2M.js +9 -0
- package/dist/{baseline-WVD6P5IO.js.map → baseline-FIV6PR2M.js.map} +1 -1
- package/dist/{chunk-FOW5IF73.js → chunk-2FEB5KJS.js} +11 -34
- package/dist/chunk-2FEB5KJS.js.map +1 -0
- package/dist/{chunk-WQLZSVNF.js → chunk-3FMRFECC.js} +7 -6
- package/dist/chunk-3FMRFECC.js.map +1 -0
- package/dist/{chunk-7QDHQLUS.js → chunk-3H3SVJUY.js} +13 -11
- package/dist/chunk-3H3SVJUY.js.map +1 -0
- package/dist/{chunk-REIGWTTH.js → chunk-3HNPVXUK.js} +3 -3
- package/dist/{chunk-REIGWTTH.js.map → chunk-3HNPVXUK.js.map} +1 -1
- package/dist/{chunk-YQNTIBKS.js → chunk-3NJUOIZQ.js} +6 -6
- package/dist/{chunk-YQNTIBKS.js.map → chunk-3NJUOIZQ.js.map} +1 -1
- package/dist/{chunk-BH54SLGZ.js → chunk-5OL2TSHK.js} +4 -4
- package/dist/{chunk-BH54SLGZ.js.map → chunk-5OL2TSHK.js.map} +1 -1
- package/dist/{chunk-TFAXW7VM.js → chunk-6K3XK7C5.js} +69 -976
- package/dist/chunk-6K3XK7C5.js.map +1 -0
- package/dist/{chunk-N3XFY3PX.js → chunk-74UBGF4P.js} +3 -3
- package/dist/{chunk-N3XFY3PX.js.map → chunk-74UBGF4P.js.map} +1 -1
- package/dist/{chunk-X76VPOYH.js → chunk-AXZZ5CCG.js} +4 -4
- package/dist/{chunk-X76VPOYH.js.map → chunk-AXZZ5CCG.js.map} +1 -1
- package/dist/{chunk-5GLQNMTI.js → chunk-C3LMWZKF.js} +6 -6
- package/dist/{chunk-5GLQNMTI.js.map → chunk-C3LMWZKF.js.map} +1 -1
- package/dist/{chunk-WWGLVF7D.js → chunk-DVW3SVCW.js} +9 -8
- package/dist/chunk-DVW3SVCW.js.map +1 -0
- package/dist/{chunk-TNROG5CO.js → chunk-E2FAQREZ.js} +1739 -116
- package/dist/chunk-E2FAQREZ.js.map +1 -0
- package/dist/{chunk-7NMXE6KG.js → chunk-EXV4QSAD.js} +4 -4
- package/dist/{chunk-7NMXE6KG.js.map → chunk-EXV4QSAD.js.map} +1 -1
- package/dist/{chunk-3LSG7Z4I.js → chunk-EZ7UC5Y5.js} +25 -4
- package/dist/chunk-EZ7UC5Y5.js.map +1 -0
- package/dist/{chunk-OWSFZQOP.js → chunk-FJG5AXKZ.js} +3 -3
- package/dist/{chunk-OWSFZQOP.js.map → chunk-FJG5AXKZ.js.map} +1 -1
- package/dist/{chunk-NKFXXP6W.js → chunk-GOGMS3ST.js} +8 -6
- package/dist/chunk-GOGMS3ST.js.map +1 -0
- package/dist/{chunk-WHJMS7XC.js → chunk-I5LP55B6.js} +3 -3
- package/dist/{chunk-WHJMS7XC.js.map → chunk-I5LP55B6.js.map} +1 -1
- package/dist/{chunk-IHXNOY3R.js → chunk-K6DXETMC.js} +12 -12
- package/dist/{chunk-IHXNOY3R.js.map → chunk-K6DXETMC.js.map} +1 -1
- package/dist/{chunk-DSUGC7F5.js → chunk-KJT2R6WW.js} +4 -4
- package/dist/{chunk-DSUGC7F5.js.map → chunk-KJT2R6WW.js.map} +1 -1
- package/dist/chunk-KNGAZDGF.js +467 -0
- package/dist/chunk-KNGAZDGF.js.map +1 -0
- package/dist/{chunk-JCN6MSXQ.js → chunk-LHKQGVRF.js} +17 -29
- package/dist/chunk-LHKQGVRF.js.map +1 -0
- package/dist/{chunk-YNV5M3JW.js → chunk-M7IO3DXH.js} +9 -8
- package/dist/chunk-M7IO3DXH.js.map +1 -0
- package/dist/chunk-MS6V5XKB.js +33 -0
- package/dist/chunk-MS6V5XKB.js.map +1 -0
- package/dist/{chunk-2U37PFB2.js → chunk-MVPRPSXU.js} +7 -4
- package/dist/chunk-MVPRPSXU.js.map +1 -0
- package/dist/{chunk-DT4KIVRI.js → chunk-NG4KIJW6.js} +34 -2
- package/dist/chunk-NG4KIJW6.js.map +1 -0
- package/dist/{chunk-IHLLWBZU.js → chunk-O2DL2Q55.js} +6 -6
- package/dist/{chunk-IHLLWBZU.js.map → chunk-O2DL2Q55.js.map} +1 -1
- package/dist/chunk-O3LABX6I.js +43 -0
- package/dist/chunk-O3LABX6I.js.map +1 -0
- package/dist/chunk-OZ3IFXRD.js +22 -0
- package/dist/chunk-OZ3IFXRD.js.map +1 -0
- package/dist/chunk-PRG2ULPK.js +6 -0
- package/dist/{chunk-2H2U3DC7.js.map → chunk-PRG2ULPK.js.map} +1 -1
- package/dist/{chunk-TVDYEHIM.js → chunk-Q3M6K3HY.js} +3 -3
- package/dist/{chunk-TVDYEHIM.js.map → chunk-Q3M6K3HY.js.map} +1 -1
- package/dist/{chunk-KGPX4EUN.js → chunk-Q4G2BWE3.js} +4 -4
- package/dist/{chunk-KGPX4EUN.js.map → chunk-Q4G2BWE3.js.map} +1 -1
- package/dist/chunk-T7RSQ5WD.js +227 -0
- package/dist/chunk-T7RSQ5WD.js.map +1 -0
- package/dist/{chunk-54RGT2T5.js → chunk-TVDMNIUT.js} +3 -3
- package/dist/{chunk-54RGT2T5.js.map → chunk-TVDMNIUT.js.map} +1 -1
- package/dist/{chunk-N6ZMZ5AI.js → chunk-WAKP7SK7.js} +4922 -1011
- package/dist/chunk-WAKP7SK7.js.map +1 -0
- package/dist/{chunk-75LJM5XD.js → chunk-WVMOGIPC.js} +9 -43
- package/dist/chunk-WVMOGIPC.js.map +1 -0
- package/dist/{chunk-UTNNGKKX.js → chunk-XLXJC7H3.js} +142 -14
- package/dist/chunk-XLXJC7H3.js.map +1 -0
- package/dist/cli.js +1727 -1127
- package/dist/cli.js.map +1 -1
- package/dist/daemon-FPTRHO5N.js +26 -0
- package/dist/daemon-FPTRHO5N.js.map +1 -0
- package/dist/embed-worker-main.js +5 -4
- package/dist/embed-worker-main.js.map +1 -1
- package/dist/ensure-map-342G2IV3.js +33 -0
- package/dist/{ensure-map-HQ7A5NDL.js.map → ensure-map-342G2IV3.js.map} +1 -1
- package/dist/{fs-NTQUFCXV.js → fs-TLPOWC2D.js} +3 -3
- package/dist/fs-TLPOWC2D.js.map +1 -0
- package/dist/graph-backend-RNWQBT3P.js +15 -0
- package/dist/{graph-backend-W2TNTMY7.js.map → graph-backend-RNWQBT3P.js.map} +1 -1
- package/dist/index.d.ts +28 -6
- package/dist/index.js +21 -18
- package/dist/index.js.map +1 -1
- package/dist/{interactive-EW2VJ3BZ.js → interactive-SR7TMF6M.js} +36 -33
- package/dist/interactive-SR7TMF6M.js.map +1 -0
- package/dist/load-AYFECIQB.js +11 -0
- package/dist/{load-64RK5O6C.js.map → load-AYFECIQB.js.map} +1 -1
- package/dist/local-runtime-6SNWKSA7.js +6 -0
- package/dist/{local-runtime-2ED33KK6.js.map → local-runtime-6SNWKSA7.js.map} +1 -1
- package/dist/model-manager-SXHZ5VD4.js +10 -0
- package/dist/{model-manager-GJ2YSTSK.js.map → model-manager-SXHZ5VD4.js.map} +1 -1
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +5 -2
- package/dist/parse-worker.js.map +1 -1
- package/dist/{run-outcome-6QNQIHPV.js → run-outcome-YQQJG3LW.js} +7 -6
- package/dist/run-outcome-YQQJG3LW.js.map +1 -0
- package/dist/runtime-session-CNJ4DAV5.js +22 -0
- package/dist/{runtime-session-RJHH3KMF.js.map → runtime-session-CNJ4DAV5.js.map} +1 -1
- package/dist/session-H34HUV2Y.js +17 -0
- package/dist/{session-4BGYASOH.js.map → session-H34HUV2Y.js.map} +1 -1
- package/dist/{stream-json-GY5N7WZT.js → stream-json-55YDNAFX.js} +18 -17
- package/dist/stream-json-55YDNAFX.js.map +1 -0
- package/dist/{types-DLH-Ritr.d.ts → types-DHqH0XIE.d.ts} +68 -6
- package/dist/version-WSE3QOPK.js +4 -0
- package/dist/{version-DPAMQW6M.js.map → version-WSE3QOPK.js.map} +1 -1
- package/dist/{vg-mcp-bridge-IGHJKKSL.js → vg-mcp-bridge-2CNLHNEL.js} +13 -12
- package/dist/vg-mcp-bridge-2CNLHNEL.js.map +1 -0
- package/dist/{vgd-ORPA5C2K.js → vgd-URUZQORN.js} +10 -9
- package/dist/vgd-URUZQORN.js.map +1 -0
- package/grammars/tree-sitter-hcl.wasm +0 -0
- package/package.json +9 -8
- package/dist/agent-5ANHRYEI.js +0 -26
- package/dist/baseline-WVD6P5IO.js +0 -9
- package/dist/chunk-2H2U3DC7.js +0 -6
- package/dist/chunk-2U37PFB2.js.map +0 -1
- package/dist/chunk-3LSG7Z4I.js.map +0 -1
- package/dist/chunk-75LJM5XD.js.map +0 -1
- package/dist/chunk-7QDHQLUS.js.map +0 -1
- package/dist/chunk-DT4KIVRI.js.map +0 -1
- package/dist/chunk-FOW5IF73.js.map +0 -1
- package/dist/chunk-JCN6MSXQ.js.map +0 -1
- package/dist/chunk-N6ZMZ5AI.js.map +0 -1
- package/dist/chunk-NKFXXP6W.js.map +0 -1
- package/dist/chunk-RXP66R2E.js +0 -39
- package/dist/chunk-RXP66R2E.js.map +0 -1
- package/dist/chunk-TFAXW7VM.js.map +0 -1
- package/dist/chunk-TNROG5CO.js.map +0 -1
- package/dist/chunk-UTNNGKKX.js.map +0 -1
- package/dist/chunk-WQLZSVNF.js.map +0 -1
- package/dist/chunk-WWGLVF7D.js.map +0 -1
- package/dist/chunk-YNV5M3JW.js.map +0 -1
- package/dist/ensure-map-HQ7A5NDL.js +0 -30
- package/dist/fs-NTQUFCXV.js.map +0 -1
- package/dist/graph-backend-W2TNTMY7.js +0 -14
- package/dist/interactive-EW2VJ3BZ.js.map +0 -1
- package/dist/load-64RK5O6C.js +0 -10
- package/dist/local-runtime-2ED33KK6.js +0 -6
- package/dist/model-manager-GJ2YSTSK.js +0 -10
- package/dist/run-outcome-6QNQIHPV.js.map +0 -1
- package/dist/runtime-session-RJHH3KMF.js +0 -21
- package/dist/session-4BGYASOH.js +0 -16
- package/dist/stream-json-GY5N7WZT.js.map +0 -1
- package/dist/version-DPAMQW6M.js +0 -4
- package/dist/vg-mcp-bridge-IGHJKKSL.js.map +0 -1
- package/dist/vgd-ORPA5C2K.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveIngestHost } from './chunk-HTLDXEHW.js';
|
|
2
|
-
import { cacheDir } from './chunk-
|
|
3
|
-
import { VERSION } from './chunk-
|
|
2
|
+
import { cacheDir } from './chunk-MVPRPSXU.js';
|
|
3
|
+
import { VERSION } from './chunk-PRG2ULPK.js';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import * as os from 'os';
|
|
6
6
|
import * as path from 'path';
|
|
@@ -212,5 +212,5 @@ var StatsSharer = class {
|
|
|
212
212
|
};
|
|
213
213
|
|
|
214
214
|
export { StatsSharer, installId, isCI, statsEndpoint, telemetryOptOut };
|
|
215
|
-
//# sourceMappingURL=chunk-
|
|
216
|
-
//# sourceMappingURL=chunk-
|
|
215
|
+
//# sourceMappingURL=chunk-EXV4QSAD.js.map
|
|
216
|
+
//# sourceMappingURL=chunk-EXV4QSAD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine/stats-share.ts"],"names":[],"mappings":";;;;;;;;AAiCA,IAAM,cAAA,GAAiB,GAAA;AAEvB,IAAM,WAAA,GAAc,kBAAA;AAEpB,IAAM,cAAA,GAAsB,IAAA,CAAA,IAAA,CAAQ,EAAA,CAAA,OAAA,EAAQ,EAAG,WAAW,CAAA;AAC1D,IAAM,eAAA,GAAuB,IAAA,CAAA,IAAA,CAAK,cAAA,EAAgB,YAAY,CAAA;AAE9D,IAAM,eAAA,GAAkB,GAAA;AAgCjB,SAAS,eAAA,CAAgB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AACnF,EAAA,MAAM,OAAO,GAAA,CAAI,YAAA,IAAgB,EAAA,EAAI,IAAA,GAAO,WAAA,EAAY;AACxD,EAAA,IAAI,QAAQ,EAAA,IAAM,GAAA,KAAQ,GAAA,IAAO,GAAA,KAAQ,SAAS,OAAO,cAAA;AACzD,EAAA,MAAM,MAAM,GAAA,CAAI,kBAAA,IAAsB,EAAA,EAAI,IAAA,GAAO,WAAA,EAAY;AAC7D,EAAA,IAAI,OAAO,GAAA,IAAO,EAAA,KAAO,OAAA,IAAW,EAAA,KAAO,OAAO,OAAO,oBAAA;AACzD,EAAA,OAAO,IAAA;AACT;AAGA,IAAM,WAAA,GAAc;AAAA,EAClB,IAAA;AAAA,EACA,gBAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAA;AAGO,SAAS,IAAA,CAAK,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAc;AAClE,EAAA,OAAO,WAAA,CAAY,IAAA,CAAK,CAAC,CAAA,KAAM;AAC7B,IAAA,MAAM,OAAO,GAAA,CAAI,CAAC,KAAK,EAAA,EAAI,IAAA,GAAO,WAAA,EAAY;AAC9C,IAAA,OAAO,GAAA,KAAQ,EAAA,IAAM,GAAA,KAAQ,GAAA,IAAO,GAAA,KAAQ,OAAA;AAAA,EAC9C,CAAC,CAAA;AACH;AAcO,SAAS,SAAA,CAAU,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAa;AACtE,EAAA,IAAI,eAAA,CAAgB,GAAG,CAAA,KAAM,IAAA,IAAQ,KAAK,GAAG,CAAA,SAAU,UAAA,EAAW;AAClE,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAc,EAAA,CAAA,YAAA,CAAa,eAAA,EAAiB,MAAM,EAAE,IAAA,EAAK;AAC/D,IAAA,IAAI,MAAA,CAAO,QAAQ,CAAA,EAAG,OAAO,QAAA;AAAA,EAC/B,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,MAAM,KAAK,UAAA,EAAW;AACtB,EAAA,IAAI;AACF,IAAG,EAAA,CAAA,SAAA,CAAU,cAAA,EAAgB,EAAE,SAAA,EAAW,MAAM,CAAA;AAChD,IAAG,iBAAc,eAAA,EAAiB,EAAA,GAAK,MAAM,EAAE,IAAA,EAAM,KAAO,CAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,OAAO,CAAA,EAAoB;AAClC,EAAA,OAAO,iEAAA,CAAkE,KAAK,CAAC,CAAA;AACjF;AAEA,SAAS,UAAA,GAAqB;AAC5B,EAAA,OAAO,UAAA,EAAW;AACpB;AAGO,SAAS,aAAA,GAAwB;AACtC,EAAA,MAAM,QAAA,GAAW,QAAQ,GAAA,CAAI,uBAAA;AAC7B,EAAA,IAAI,QAAA,IAAY,cAAA,CAAe,IAAA,CAAK,QAAQ,GAAG,OAAO,QAAA;AACtD,EAAA,OAAO,CAAA,QAAA,EAAW,mBAAmB,CAAA,wBAAA,CAAA;AACvC;AAEA,SAAS,WAAW,IAAA,EAAsB;AACxC,EAAA,OAAY,IAAA,CAAA,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG,WAAW,CAAA;AAC9C;AAEA,SAAS,eAAe,IAAA,EAAsB;AAC5C,EAAA,OAAY,IAAA,CAAA,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG,eAAe,CAAA;AAClD;AAEA,SAAS,WAAW,IAAA,EAAsB;AACxC,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,KAAK,KAAA,CAAS,EAAA,CAAA,YAAA,CAAa,WAAW,IAAI,CAAA,EAAG,MAAM,CAAC,CAAA;AAChE,IAAA,OAAO,OAAO,IAAI,MAAA,KAAW,QAAA,IAAY,IAAI,MAAA,IAAU,CAAA,GAAI,IAAI,MAAA,GAAS,CAAA;AAAA,EAC1E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,CAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAA,CAAY,MAAc,MAAA,EAAsB;AACvD,EAAA,IAAI;AACF,IAAG,aAAU,QAAA,CAAS,IAAI,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAChD,IAAG,EAAA,CAAA,aAAA,CAAc,UAAA,CAAW,IAAI,CAAA,EAAG,IAAA,CAAK,UAAU,EAAE,MAAA,EAAQ,CAAA,GAAI,IAAI,CAAA;AAAA,EACtE,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAOO,SAAS,UAAA,CACd,IAAA,EACA,UAAA,EACA,EAAA,GAAK,WAAU,EACkC;AACjD,EAAA,MAAM,IAAA,GAAO,eAAe,IAAI,CAAA;AAChC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI;AACF,IAAA,IAAA,GAAU,EAAA,CAAA,QAAA,CAAS,IAAI,CAAA,CAAE,IAAA;AAAA,EAC3B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW,CAAA,EAAE;AAAA,EACrC;AAEA,EAAA,MAAM,KAAA,GAAQ,UAAA,GAAa,IAAA,GAAO,CAAA,GAAI,UAAA;AACtC,EAAA,IAAI,SAAS,IAAA,EAAM,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,WAAW,IAAA,EAAK;AAEzD,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI;AACF,IAAA,MAAM,EAAA,GAAQ,EAAA,CAAA,QAAA,CAAS,IAAA,EAAM,GAAG,CAAA;AAChC,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAA,CAAO,KAAA,CAAM,IAAA,GAAO,KAAK,CAAA;AACrC,MAAG,YAAS,EAAA,EAAI,GAAA,EAAK,CAAA,EAAG,GAAA,CAAI,QAAQ,KAAK,CAAA;AACzC,MAAA,IAAA,GAAO,GAAA,CAAI,SAAS,MAAM,CAAA;AAAA,IAC5B,CAAA,SAAE;AACA,MAAG,aAAU,EAAE,CAAA;AAAA,IACjB;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW,UAAA,EAAW;AAAA,EAC9C;AAIA,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,WAAA,CAAY,IAAI,CAAA;AACpC,EAAA,IAAI,SAAS,CAAA,EAAG,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,WAAW,KAAA,EAAM;AACvD,EAAA,MAAM,QAAA,GAAW,QAAQ,MAAA,GAAS,CAAA;AAClC,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAsB;AACvC,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,QAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,CAAA,QAAA;AACZ,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAK,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA,EAAG;AACpD,IAAA,IAAI,CAAC,IAAA,CAAK,IAAA,EAAK,EAAG;AAClB,IAAA,IAAI,CAAA;AACJ,IAAA,IAAI;AACF,MAAA,CAAA,GAAI,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IACrB,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAiB,EAAE,MAAA,IAAU,KAAA;AACnC,IAAA,MAAM,MAAA,GAAS,EAAE,MAAA,IAAU,SAAA;AAC3B,IAAA,MAAM,OAAA,GAAmB,EAAE,OAAA,IAAW,UAAA;AACtC,IAAA,MAAM,GAAA,GAAM,GAAG,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AACpD,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,IAAK;AAAA,MAC3B,MAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,OAAA;AAAA,MACA,KAAA,EAAO,CAAA;AAAA,MACP,QAAA,EAAU,CAAA;AAAA,MACV,cAAA,EAAgB;AAAA,KAClB;AACA,IAAA,GAAA,CAAI,KAAA,EAAA;AACJ,IAAA,GAAA,CAAI,QAAA,IAAY,EAAE,QAAA,IAAY,CAAA;AAC9B,IAAA,GAAA,CAAI,cAAA,IAAkB,EAAE,cAAA,IAAkB,CAAA;AAC1C,IAAA,IAAA,CAAK,GAAA,CAAI,KAAK,GAAG,CAAA;AACjB,IAAA,KAAA,EAAA;AACA,IAAA,IAAI,OAAO,CAAA,CAAE,EAAA,KAAO,QAAA,EAAU;AAC5B,MAAA,IAAI,CAAA,CAAE,EAAA,GAAK,KAAA,EAAO,KAAA,GAAQ,CAAA,CAAE,EAAA;AAC5B,MAAA,IAAI,CAAA,CAAE,EAAA,GAAK,KAAA,EAAO,KAAA,GAAQ,CAAA,CAAE,EAAA;AAAA,IAC9B;AAAA,EACF;AACA,EAAA,IAAI,KAAA,KAAU,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW,QAAA,EAAS;AACtF,EAAA,MAAM,KAAA,GAAoB;AAAA,IACxB,aAAA,EAAe,cAAA;AAAA,IACf,SAAA,EAAW,EAAA;AAAA,IACX,SAAA,EAAW,OAAA;AAAA,IACX,IAAI,OAAA,CAAQ,QAAA;AAAA,IACZ,MAAM,OAAA,CAAQ,IAAA;AAAA,IACd,WAAA,EAAa,IAAI,IAAA,CAAK,KAAK,EAAE,WAAA,EAAY;AAAA,IACzC,SAAA,EAAW,IAAI,IAAA,CAAK,KAAK,EAAE,WAAA,EAAY;AAAA,IACvC,UAAA,EAAY,KAAA;AAAA,IACZ,IAAA,EAAM,CAAC,GAAG,IAAA,CAAK,QAAQ;AAAA,GACzB;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,SAAA,EAAW,QAAA,EAAS;AACtC;AAMA,eAAe,UAAU,KAAA,EAAqC;AAC5D,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,eAAe,CAAA;AAClE,EAAA,KAAA,CAAM,KAAA,IAAQ;AACd,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,aAAA,EAAc,EAAG;AAAA,MACvC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,YAAY,OAAA,EAAQ;AAAA,MACnE,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAAA,MAC1B,QAAQ,UAAA,CAAW;AAAA,KACpB,CAAA;AACD,IAAA,OAAO,GAAA,CAAI,EAAA;AAAA,EACb,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB;AACF;AAOO,IAAM,cAAN,MAAkB;AAAA,EAKvB,YAA6B,IAAA,EAAc;AAAd,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,GAAS,WAAW,IAAI,CAAA;AAAA,EAC/B;AAAA,EAF6B,IAAA;AAAA,EAJZ,KAAK,SAAA,EAAU;AAAA,EACxB,MAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUnB,MAAM,KAAA,GAAuB;AAC3B,IAAA,IAAI,KAAK,QAAA,EAAU;AACnB,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,KAAA,EAAO,SAAA,EAAU,GAAI,UAAA,CAAW,KAAK,IAAA,EAAM,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,EAAE,CAAA;AACvE,MAAA,IAAI,CAAC,KAAA,EAAO;AAEV,QAAA,IAAI,SAAA,GAAY,KAAK,MAAA,EAAQ;AAC3B,UAAA,IAAA,CAAK,MAAA,GAAS,SAAA;AACd,UAAA,WAAA,CAAY,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,QAClC;AACA,QAAA;AAAA,MACF;AACA,MAAA,MAAM,EAAA,GAAK,MAAM,SAAA,CAAU,KAAK,CAAA;AAChC,MAAA,IAAI,EAAA,EAAI;AACN,QAAA,IAAA,CAAK,MAAA,GAAS,SAAA;AACd,QAAA,WAAA,CAAY,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,MAClC;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,QAAA,GAAW,KAAA;AAAA,IAClB;AAAA,EACF;AACF","file":"chunk-7NMXE6KG.js","sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { cacheDir } from './cache.js';\nimport { VERSION } from '../version.js';\nimport { resolveIngestHost } from '../reporting/regions.js';\nimport type { SavingEntry, Source, Outcome } from './savings.js';\n\n/**\n * Opt-in usage-stats sharing for `vg serve --share-stats`.\n *\n * This is the ONLY path in `vg serve` that sends anything off the machine, and\n * it is off unless the operator explicitly asks for it. What we send is the\n * same counts-only ledger `vg savings` reports locally — per (source, client,\n * tool, outcome): how many calls and the vg-vs-grep token figures — plus the vg\n * version, OS/arch, and a random per-install id. We never send code, file paths,\n * question text, repo identity, or any credential. See GUARDRAILS §3.4.\n *\n * Even when the flag is passed, the universal `DO_NOT_TRACK` opt-out (or\n * `VIBGRATE_TELEMETRY=0`) wins: nothing is uploaded and no install id is ever\n * minted or persisted (see `telemetryOptOut` / `installId`).\n *\n * Design:\n * - The local ledger (savings.jsonl) is the single source of truth; the flusher\n * reads only the tail past a persisted byte offset, so a batch is sent once.\n * - Fire-and-forget with a short timeout. A network problem never blocks a tool\n * call and never throws — the offset only advances on a confirmed 2xx, so a\n * failed batch is retried on the next flush.\n * - Fully offline-safe: under `--local` the sharer is never constructed.\n */\n\n/** Payload schema version — must match the server's `mcpUsageStatsSchema`. */\nconst SCHEMA_VERSION = '1';\n/** Where the offset (and cached install id) live, per repo, beside the ledger. */\nconst OFFSET_FILE = 'stats-share.json';\n/** The machine-global anonymous install id lives here (stable across repos). */\nconst INSTALL_ID_DIR = path.join(os.homedir(), '.vibgrate');\nconst INSTALL_ID_FILE = path.join(INSTALL_ID_DIR, 'install-id');\n/** Give a flush POST a hard ceiling so a hung endpoint never stalls shutdown. */\nconst SEND_TIMEOUT_MS = 4000;\n\n/** One aggregated row of the shared batch — counts only. */\nexport interface StatsRow {\n source: Source;\n client: string;\n tool: string;\n outcome: Outcome;\n calls: number;\n vgTokens: number;\n baselineTokens: number;\n}\n\n/** The counts-only batch POSTed to the ingest endpoint. */\nexport interface StatsBatch {\n schemaVersion: string;\n installId: string;\n vgVersion: string;\n os: string;\n arch: string;\n windowStart: string;\n windowEnd: string;\n totalCalls: number;\n rows: StatsRow[];\n}\n\n/**\n * The universal opt-out (https://consoledonottrack.com) plus a tool-specific\n * alias, honoured even when `--share-stats` is passed explicitly. Pure function\n * of the environment for testability. Returns the name of the variable that\n * opted out (for the disclosure message), or null when sharing may proceed.\n */\nexport function telemetryOptOut(env: NodeJS.ProcessEnv = process.env): string | null {\n const dnt = (env.DO_NOT_TRACK ?? '').trim().toLowerCase();\n if (dnt !== '' && dnt !== '0' && dnt !== 'false') return 'DO_NOT_TRACK';\n const vt = (env.VIBGRATE_TELEMETRY ?? '').trim().toLowerCase();\n if (vt === '0' || vt === 'false' || vt === 'off') return 'VIBGRATE_TELEMETRY';\n return null;\n}\n\n/** Common CI environment markers — a CI runner is never an interactive session. */\nconst CI_ENV_VARS = [\n 'CI',\n 'GITHUB_ACTIONS',\n 'GITLAB_CI',\n 'CIRCLECI',\n 'TRAVIS',\n 'BUILDKITE',\n 'JENKINS_URL',\n 'TF_BUILD',\n] as const;\n\n/** True when running under a recognised CI system. Pure function of the env. */\nexport function isCI(env: NodeJS.ProcessEnv = process.env): boolean {\n return CI_ENV_VARS.some((v) => {\n const val = (env[v] ?? '').trim().toLowerCase();\n return val !== '' && val !== '0' && val !== 'false';\n });\n}\n\n/**\n * Read (or lazily create) the anonymous per-install id — a random UUID stored in\n * `~/.vibgrate/install-id`. It is *not* tied to the user, the repo, or any\n * account; it only lets us de-duplicate batches from the same install when\n * aggregating. If the home dir isn't writable we fall back to an ephemeral id\n * so sharing still works (it just can't be de-duplicated across restarts).\n *\n * Under an env opt-out no id is ever read or persisted (the sharing path isn't\n * reached then either — this is defence in depth), and on CI runners the id is\n * ephemeral: a persisted id on a shared/throwaway runner would be meaningless\n * for de-duplication and would leave state behind on machines we don't own.\n */\nexport function installId(env: NodeJS.ProcessEnv = process.env): string {\n if (telemetryOptOut(env) !== null || isCI(env)) return randomUuid();\n try {\n const existing = fs.readFileSync(INSTALL_ID_FILE, 'utf8').trim();\n if (isUuid(existing)) return existing;\n } catch {\n /* not created yet */\n }\n const id = randomUuid();\n try {\n fs.mkdirSync(INSTALL_ID_DIR, { recursive: true });\n fs.writeFileSync(INSTALL_ID_FILE, id + '\\n', { mode: 0o600 });\n } catch {\n /* home dir read-only — use the ephemeral id for this process */\n }\n return id;\n}\n\nfunction isUuid(s: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);\n}\n\nfunction randomUuid(): string {\n return randomUUID();\n}\n\n/** Resolve the ingest endpoint: env override wins, else the default region host. */\nexport function statsEndpoint(): string {\n const override = process.env.VIBGRATE_STATS_ENDPOINT;\n if (override && /^https?:\\/\\//.test(override)) return override;\n return `https://${resolveIngestHost()}/v1/ingest/cli-mcp-usage`;\n}\n\nfunction offsetPath(root: string): string {\n return path.join(cacheDir(root), OFFSET_FILE);\n}\n\nfunction ledgerFilePath(root: string): string {\n return path.join(cacheDir(root), 'savings.jsonl');\n}\n\nfunction readOffset(root: string): number {\n try {\n const raw = JSON.parse(fs.readFileSync(offsetPath(root), 'utf8')) as { offset?: number };\n return typeof raw.offset === 'number' && raw.offset >= 0 ? raw.offset : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeOffset(root: string, offset: number): void {\n try {\n fs.mkdirSync(cacheDir(root), { recursive: true });\n fs.writeFileSync(offsetPath(root), JSON.stringify({ offset }) + '\\n');\n } catch {\n /* best-effort; a lost offset just means one batch may re-send */\n }\n}\n\n/**\n * Aggregate the ledger entries after `fromOffset` into a counts-only batch.\n * Returns the batch (or null if there's nothing new) and the new byte offset to\n * persist once the batch is confirmed sent.\n */\nexport function buildBatch(\n root: string,\n fromOffset: number,\n id = installId(),\n): { batch: StatsBatch | null; newOffset: number } {\n const file = ledgerFilePath(root);\n let size = 0;\n try {\n size = fs.statSync(file).size;\n } catch {\n return { batch: null, newOffset: 0 };\n }\n // The ledger was truncated/recreated under us — re-read from the top.\n const start = fromOffset > size ? 0 : fromOffset;\n if (start >= size) return { batch: null, newOffset: size };\n\n let text = '';\n try {\n const fd = fs.openSync(file, 'r');\n try {\n const buf = Buffer.alloc(size - start);\n fs.readSync(fd, buf, 0, buf.length, start);\n text = buf.toString('utf8');\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return { batch: null, newOffset: fromOffset };\n }\n\n // Only whole lines are complete; a trailing partial line (mid-append) is left\n // for the next flush by rewinding the offset to the last newline.\n const lastNl = text.lastIndexOf('\\n');\n if (lastNl < 0) return { batch: null, newOffset: start };\n const consumed = start + lastNl + 1;\n const rows = new Map<string, StatsRow>();\n let total = 0;\n let minTs = Infinity;\n let maxTs = -Infinity;\n for (const line of text.slice(0, lastNl).split('\\n')) {\n if (!line.trim()) continue;\n let e: SavingEntry;\n try {\n e = JSON.parse(line) as SavingEntry;\n } catch {\n continue;\n }\n const source: Source = e.source ?? 'mcp';\n const client = e.client ?? 'unknown';\n const outcome: Outcome = e.outcome ?? 'complete';\n const key = `${source}|${client}|${e.tool}|${outcome}`;\n const row = rows.get(key) ?? {\n source,\n client,\n tool: e.tool,\n outcome,\n calls: 0,\n vgTokens: 0,\n baselineTokens: 0,\n };\n row.calls++;\n row.vgTokens += e.vgTokens ?? 0;\n row.baselineTokens += e.baselineTokens ?? 0;\n rows.set(key, row);\n total++;\n if (typeof e.ts === 'number') {\n if (e.ts < minTs) minTs = e.ts;\n if (e.ts > maxTs) maxTs = e.ts;\n }\n }\n if (total === 0 || !Number.isFinite(minTs)) return { batch: null, newOffset: consumed };\n const batch: StatsBatch = {\n schemaVersion: SCHEMA_VERSION,\n installId: id,\n vgVersion: VERSION,\n os: process.platform,\n arch: process.arch,\n windowStart: new Date(minTs).toISOString(),\n windowEnd: new Date(maxTs).toISOString(),\n totalCalls: total,\n rows: [...rows.values()],\n };\n return { batch, newOffset: consumed };\n}\n\n/**\n * POST a batch to the endpoint. Never throws; returns whether it was accepted.\n * A short timeout keeps a hung endpoint from stalling the caller (e.g. shutdown).\n */\nasync function postBatch(batch: StatsBatch): Promise<boolean> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);\n timer.unref?.();\n try {\n const res = await fetch(statsEndpoint(), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Connection: 'close' },\n body: JSON.stringify(batch),\n signal: controller.signal,\n });\n return res.ok;\n } catch {\n return false;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Periodic + on-shutdown flusher for one serve session. Holds the install id and\n * the persisted offset so each flush reads only new ledger lines and advances the\n * offset only when the batch is confirmed sent.\n */\nexport class StatsSharer {\n private readonly id = installId();\n private offset: number;\n private flushing = false;\n\n constructor(private readonly root: string) {\n this.offset = readOffset(root);\n }\n\n /**\n * Flush any new ledger entries. Single-flight (a slow POST won't overlap the\n * next tick). Best-effort: any failure is swallowed and retried next time.\n */\n async flush(): Promise<void> {\n if (this.flushing) return;\n this.flushing = true;\n try {\n const { batch, newOffset } = buildBatch(this.root, this.offset, this.id);\n if (!batch) {\n // Nothing to send, but still advance past consumed blank/partial space.\n if (newOffset > this.offset) {\n this.offset = newOffset;\n writeOffset(this.root, newOffset);\n }\n return;\n }\n const ok = await postBatch(batch);\n if (ok) {\n this.offset = newOffset;\n writeOffset(this.root, newOffset);\n }\n } catch {\n /* never let sharing break serving */\n } finally {\n this.flushing = false;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/engine/stats-share.ts"],"names":[],"mappings":"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","file":"chunk-EXV4QSAD.js","sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { cacheDir } from './cache.js';\nimport { VERSION } from '../version.js';\nimport { resolveIngestHost } from '../reporting/regions.js';\nimport type { SavingEntry, Source, Outcome } from './savings.js';\n\n/**\n * Opt-in usage-stats sharing for `vg serve --share-stats`.\n *\n * This is the ONLY path in `vg serve` that sends anything off the machine, and\n * it is off unless the operator explicitly asks for it. What we send is the\n * same counts-only ledger `vg savings` reports locally — per (source, client,\n * tool, outcome): how many calls and the vg-vs-grep token figures — plus the vg\n * version, OS/arch, and a random per-install id. We never send code, file paths,\n * question text, repo identity, or any credential. See GUARDRAILS §3.4.\n *\n * Even when the flag is passed, the universal `DO_NOT_TRACK` opt-out (or\n * `VIBGRATE_TELEMETRY=0`) wins: nothing is uploaded and no install id is ever\n * minted or persisted (see `telemetryOptOut` / `installId`).\n *\n * Design:\n * - The local ledger (savings.jsonl) is the single source of truth; the flusher\n * reads only the tail past a persisted byte offset, so a batch is sent once.\n * - Fire-and-forget with a short timeout. A network problem never blocks a tool\n * call and never throws — the offset only advances on a confirmed 2xx, so a\n * failed batch is retried on the next flush.\n * - Fully offline-safe: under `--local` the sharer is never constructed.\n */\n\n/** Payload schema version — must match the server's `mcpUsageStatsSchema`. */\nconst SCHEMA_VERSION = '1';\n/** Where the offset (and cached install id) live, per repo, beside the ledger. */\nconst OFFSET_FILE = 'stats-share.json';\n/** The machine-global anonymous install id lives here (stable across repos). */\nconst INSTALL_ID_DIR = path.join(os.homedir(), '.vibgrate');\nconst INSTALL_ID_FILE = path.join(INSTALL_ID_DIR, 'install-id');\n/** Give a flush POST a hard ceiling so a hung endpoint never stalls shutdown. */\nconst SEND_TIMEOUT_MS = 4000;\n\n/** One aggregated row of the shared batch — counts only. */\nexport interface StatsRow {\n source: Source;\n client: string;\n tool: string;\n outcome: Outcome;\n calls: number;\n vgTokens: number;\n baselineTokens: number;\n}\n\n/** The counts-only batch POSTed to the ingest endpoint. */\nexport interface StatsBatch {\n schemaVersion: string;\n installId: string;\n vgVersion: string;\n os: string;\n arch: string;\n windowStart: string;\n windowEnd: string;\n totalCalls: number;\n rows: StatsRow[];\n}\n\n/**\n * The universal opt-out (https://consoledonottrack.com) plus a tool-specific\n * alias, honoured even when `--share-stats` is passed explicitly. Pure function\n * of the environment for testability. Returns the name of the variable that\n * opted out (for the disclosure message), or null when sharing may proceed.\n */\nexport function telemetryOptOut(env: NodeJS.ProcessEnv = process.env): string | null {\n const dnt = (env.DO_NOT_TRACK ?? '').trim().toLowerCase();\n if (dnt !== '' && dnt !== '0' && dnt !== 'false') return 'DO_NOT_TRACK';\n const vt = (env.VIBGRATE_TELEMETRY ?? '').trim().toLowerCase();\n if (vt === '0' || vt === 'false' || vt === 'off') return 'VIBGRATE_TELEMETRY';\n return null;\n}\n\n/** Common CI environment markers — a CI runner is never an interactive session. */\nconst CI_ENV_VARS = [\n 'CI',\n 'GITHUB_ACTIONS',\n 'GITLAB_CI',\n 'CIRCLECI',\n 'TRAVIS',\n 'BUILDKITE',\n 'JENKINS_URL',\n 'TF_BUILD',\n] as const;\n\n/** True when running under a recognised CI system. Pure function of the env. */\nexport function isCI(env: NodeJS.ProcessEnv = process.env): boolean {\n return CI_ENV_VARS.some((v) => {\n const val = (env[v] ?? '').trim().toLowerCase();\n return val !== '' && val !== '0' && val !== 'false';\n });\n}\n\n/**\n * Read (or lazily create) the anonymous per-install id — a random UUID stored in\n * `~/.vibgrate/install-id`. It is *not* tied to the user, the repo, or any\n * account; it only lets us de-duplicate batches from the same install when\n * aggregating. If the home dir isn't writable we fall back to an ephemeral id\n * so sharing still works (it just can't be de-duplicated across restarts).\n *\n * Under an env opt-out no id is ever read or persisted (the sharing path isn't\n * reached then either — this is defence in depth), and on CI runners the id is\n * ephemeral: a persisted id on a shared/throwaway runner would be meaningless\n * for de-duplication and would leave state behind on machines we don't own.\n */\nexport function installId(env: NodeJS.ProcessEnv = process.env): string {\n if (telemetryOptOut(env) !== null || isCI(env)) return randomUuid();\n try {\n const existing = fs.readFileSync(INSTALL_ID_FILE, 'utf8').trim();\n if (isUuid(existing)) return existing;\n } catch {\n /* not created yet */\n }\n const id = randomUuid();\n try {\n fs.mkdirSync(INSTALL_ID_DIR, { recursive: true });\n fs.writeFileSync(INSTALL_ID_FILE, id + '\\n', { mode: 0o600 });\n } catch {\n /* home dir read-only — use the ephemeral id for this process */\n }\n return id;\n}\n\nfunction isUuid(s: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);\n}\n\nfunction randomUuid(): string {\n return randomUUID();\n}\n\n/** Resolve the ingest endpoint: env override wins, else the default region host. */\nexport function statsEndpoint(): string {\n const override = process.env.VIBGRATE_STATS_ENDPOINT;\n if (override && /^https?:\\/\\//.test(override)) return override;\n return `https://${resolveIngestHost()}/v1/ingest/cli-mcp-usage`;\n}\n\nfunction offsetPath(root: string): string {\n return path.join(cacheDir(root), OFFSET_FILE);\n}\n\nfunction ledgerFilePath(root: string): string {\n return path.join(cacheDir(root), 'savings.jsonl');\n}\n\nfunction readOffset(root: string): number {\n try {\n const raw = JSON.parse(fs.readFileSync(offsetPath(root), 'utf8')) as { offset?: number };\n return typeof raw.offset === 'number' && raw.offset >= 0 ? raw.offset : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeOffset(root: string, offset: number): void {\n try {\n fs.mkdirSync(cacheDir(root), { recursive: true });\n fs.writeFileSync(offsetPath(root), JSON.stringify({ offset }) + '\\n');\n } catch {\n /* best-effort; a lost offset just means one batch may re-send */\n }\n}\n\n/**\n * Aggregate the ledger entries after `fromOffset` into a counts-only batch.\n * Returns the batch (or null if there's nothing new) and the new byte offset to\n * persist once the batch is confirmed sent.\n */\nexport function buildBatch(\n root: string,\n fromOffset: number,\n id = installId(),\n): { batch: StatsBatch | null; newOffset: number } {\n const file = ledgerFilePath(root);\n let size = 0;\n try {\n size = fs.statSync(file).size;\n } catch {\n return { batch: null, newOffset: 0 };\n }\n // The ledger was truncated/recreated under us — re-read from the top.\n const start = fromOffset > size ? 0 : fromOffset;\n if (start >= size) return { batch: null, newOffset: size };\n\n let text = '';\n try {\n const fd = fs.openSync(file, 'r');\n try {\n const buf = Buffer.alloc(size - start);\n fs.readSync(fd, buf, 0, buf.length, start);\n text = buf.toString('utf8');\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return { batch: null, newOffset: fromOffset };\n }\n\n // Only whole lines are complete; a trailing partial line (mid-append) is left\n // for the next flush by rewinding the offset to the last newline.\n const lastNl = text.lastIndexOf('\\n');\n if (lastNl < 0) return { batch: null, newOffset: start };\n const consumed = start + lastNl + 1;\n const rows = new Map<string, StatsRow>();\n let total = 0;\n let minTs = Infinity;\n let maxTs = -Infinity;\n for (const line of text.slice(0, lastNl).split('\\n')) {\n if (!line.trim()) continue;\n let e: SavingEntry;\n try {\n e = JSON.parse(line) as SavingEntry;\n } catch {\n continue;\n }\n const source: Source = e.source ?? 'mcp';\n const client = e.client ?? 'unknown';\n const outcome: Outcome = e.outcome ?? 'complete';\n const key = `${source}|${client}|${e.tool}|${outcome}`;\n const row = rows.get(key) ?? {\n source,\n client,\n tool: e.tool,\n outcome,\n calls: 0,\n vgTokens: 0,\n baselineTokens: 0,\n };\n row.calls++;\n row.vgTokens += e.vgTokens ?? 0;\n row.baselineTokens += e.baselineTokens ?? 0;\n rows.set(key, row);\n total++;\n if (typeof e.ts === 'number') {\n if (e.ts < minTs) minTs = e.ts;\n if (e.ts > maxTs) maxTs = e.ts;\n }\n }\n if (total === 0 || !Number.isFinite(minTs)) return { batch: null, newOffset: consumed };\n const batch: StatsBatch = {\n schemaVersion: SCHEMA_VERSION,\n installId: id,\n vgVersion: VERSION,\n os: process.platform,\n arch: process.arch,\n windowStart: new Date(minTs).toISOString(),\n windowEnd: new Date(maxTs).toISOString(),\n totalCalls: total,\n rows: [...rows.values()],\n };\n return { batch, newOffset: consumed };\n}\n\n/**\n * POST a batch to the endpoint. Never throws; returns whether it was accepted.\n * A short timeout keeps a hung endpoint from stalling the caller (e.g. shutdown).\n */\nasync function postBatch(batch: StatsBatch): Promise<boolean> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);\n timer.unref?.();\n try {\n const res = await fetch(statsEndpoint(), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Connection: 'close' },\n body: JSON.stringify(batch),\n signal: controller.signal,\n });\n return res.ok;\n } catch {\n return false;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Periodic + on-shutdown flusher for one serve session. Holds the install id and\n * the persisted offset so each flush reads only new ledger lines and advances the\n * offset only when the batch is confirmed sent.\n */\nexport class StatsSharer {\n private readonly id = installId();\n private offset: number;\n private flushing = false;\n\n constructor(private readonly root: string) {\n this.offset = readOffset(root);\n }\n\n /**\n * Flush any new ledger entries. Single-flight (a slow POST won't overlap the\n * next tick). Best-effort: any failure is swallowed and retried next time.\n */\n async flush(): Promise<void> {\n if (this.flushing) return;\n this.flushing = true;\n try {\n const { batch, newOffset } = buildBatch(this.root, this.offset, this.id);\n if (!batch) {\n // Nothing to send, but still advance past consumed blank/partial space.\n if (newOffset > this.offset) {\n this.offset = newOffset;\n writeOffset(this.root, newOffset);\n }\n return;\n }\n const ok = await postBatch(batch);\n if (ok) {\n this.offset = newOffset;\n writeOffset(this.root, newOffset);\n }\n } catch {\n /* never let sharing break serving */\n } finally {\n this.flushing = false;\n }\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __esm } from './chunk-Z6ZWNWWR.js';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
3
4
|
import { execFileSync } from 'child_process';
|
|
4
5
|
|
|
5
6
|
function whichOnPath(cmd) {
|
|
@@ -49,13 +50,33 @@ function resolveCliInvocation(which) {
|
|
|
49
50
|
if (!which) cached = result;
|
|
50
51
|
return result;
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
function resolveSelfJsEntry(argv1 = process.argv[1] ?? "") {
|
|
54
|
+
if (!argv1) return null;
|
|
55
|
+
const candidates = [argv1];
|
|
56
|
+
try {
|
|
57
|
+
const real = fs.realpathSync(argv1);
|
|
58
|
+
if (real !== argv1) candidates.push(real);
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
for (const p of candidates) {
|
|
62
|
+
if (!JS_ENTRY.test(p)) continue;
|
|
63
|
+
return path.isAbsolute(p) ? p : path.resolve(p);
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
function reinvokeCli(args) {
|
|
68
|
+
const js = resolveSelfJsEntry();
|
|
69
|
+
if (js) return { command: process.execPath, argv: [js, ...args] };
|
|
70
|
+
return { command: process.argv[0] || "vg", argv: args };
|
|
71
|
+
}
|
|
72
|
+
var JS_ENTRY, NPX_INVOCATION, cached;
|
|
53
73
|
var init_cli_invocation = __esm({
|
|
54
74
|
"src/util/cli-invocation.ts"() {
|
|
75
|
+
JS_ENTRY = /\.(c|m)?js$/i;
|
|
55
76
|
NPX_INVOCATION = "npx @vibgrate/cli";
|
|
56
77
|
}
|
|
57
78
|
});
|
|
58
79
|
|
|
59
|
-
export { NPX_INVOCATION, init_cli_invocation, isInstalledOwnBinary, resolveCliInvocation, whichOnPath };
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
61
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
export { NPX_INVOCATION, init_cli_invocation, isInstalledOwnBinary, reinvokeCli, resolveCliInvocation, resolveSelfJsEntry, whichOnPath };
|
|
81
|
+
//# sourceMappingURL=chunk-EZ7UC5Y5.js.map
|
|
82
|
+
//# sourceMappingURL=chunk-EZ7UC5Y5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util/cli-invocation.ts"],"names":[],"mappings":"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","file":"chunk-EZ7UC5Y5.js","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { execFileSync } from 'node:child_process';\n\n/** JS entry we can hand to `node` when re-spawning this CLI. */\nconst JS_ENTRY = /\\.(c|m)?js$/i;\n\n/**\n * How the user should re-invoke this CLI in a \"next step\" hint.\n *\n * A user who ran `npx @vibgrate/cli scan` has no *persistent* `vg` (or\n * `vibgrate`) on PATH, so a hint like `vg install` or `vg login` would fail for\n * them once the run ends. We answer the practical question \"what will actually\n * run this CLI for this user again?\" by checking whether an *installed* copy of\n * our binary is reachable on PATH:\n *\n * installed `vg` → `vg` (the normal installed case)\n * installed `vibgrate` → `vibgrate` (alias present, `vg` shadowed)\n * neither → `npx @vibgrate/cli` (npx / not installed globally)\n *\n * \"Installed\" is the key qualifier: `npx` prepends its own throwaway\n * `_npx/<hash>/node_modules/.bin` to PATH for the run, so `which vg` finds a `vg`\n * that is genuinely ours yet gone the moment the process exits. That ephemeral\n * binary is excluded (see {@link isEphemeralNpxBinary}) so npx users get the npx\n * form, not a `vg` they can't call again.\n *\n * This is deliberately the same ladder `detectServeLaunch` uses for the MCP\n * launch command — the underlying question (\"is an installed `vg` ours?\") is\n * identical.\n */\n\n/** The npx form that always works without a global install. */\nexport const NPX_INVOCATION = 'npx @vibgrate/cli';\n\n/**\n * Locate `cmd` on PATH, returning its resolved path or null. Best-effort: a\n * missing command or an unavailable `which`/`where` both yield null.\n */\nexport function whichOnPath(cmd: string): string | null {\n try {\n const out = execFileSync(process.platform === 'win32' ? 'where' : 'which', [cmd], {\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .trim()\n .split(/\\r?\\n/)[0];\n return out || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Does this PATH entry launch *this* package? Symlink installs resolve into a\n * `…/@vibgrate/cli/…` directory; script shims (pnpm/bun/yarn, Windows .cmd)\n * reference the package path in their first bytes. Best-effort: unreadable or\n * unrecognisable entries count as foreign, which only makes callers pick a safer\n * fallback.\n */\nexport function isOwnBinary(binPath: string): boolean {\n try {\n const real = fs.realpathSync(binPath);\n if (/[\\\\/]@vibgrate[\\\\/]cli[\\\\/]/.test(real)) return true;\n const head = fs.readFileSync(real, { encoding: 'utf8' }).slice(0, 2048);\n return head.includes('@vibgrate/cli') || head.includes('vibgrate');\n } catch {\n return false;\n }\n}\n\n/**\n * Is this resolved binary an *ephemeral* npx-cache entry rather than a persistent\n * install? `npx @vibgrate/cli …` unpacks the package into an npm `_npx/<hash>/`\n * cache directory and prepends its `node_modules/.bin` to PATH for the duration\n * of the run — so `which vg` finds a `vg` that is *ours* yet vanishes the instant\n * the process exits. Treating that as an installed `vg` is exactly what made the\n * post-scan hints tell npx users to run `vg login`/`vg push`, commands they have\n * no `vg` on PATH for. npm's cache segment is `_npx` on every platform; we test\n * the raw PATH entry and its realpath (symlink shims resolve into the same tree).\n */\nexport function isEphemeralNpxBinary(binPath: string): boolean {\n const NPX_SEGMENT = /[\\\\/]_npx[\\\\/]/;\n if (NPX_SEGMENT.test(binPath)) return true;\n try {\n return NPX_SEGMENT.test(fs.realpathSync(binPath));\n } catch {\n return false;\n }\n}\n\n/**\n * Does this PATH entry launch *this* CLI in a way that will still work after the\n * current process exits? True only for a persistent install of our package — an\n * ephemeral npx-cache binary does not count, because the user cannot re-invoke it\n * by name. This is the predicate \"next step\" hints and the MCP launch command\n * must use, not {@link isOwnBinary} alone.\n */\nexport function isInstalledOwnBinary(binPath: string): boolean {\n return isOwnBinary(binPath) && !isEphemeralNpxBinary(binPath);\n}\n\nlet cached: string | undefined;\n\n/**\n * The command prefix a user should type to re-run this CLI (see module doc).\n * Memoized per-process: PATH does not change mid-run, and each call would\n * otherwise spawn `which`. Pass `which` to override lookup in tests, which also\n * bypasses the cache.\n */\nexport function resolveCliInvocation(which?: (cmd: string) => string | null): string {\n if (!which && cached !== undefined) return cached;\n const lookup = which ?? whichOnPath;\n\n const vg = lookup('vg');\n let result: string;\n if (vg && isInstalledOwnBinary(vg)) {\n result = 'vg';\n } else {\n const vibgrate = lookup('vibgrate');\n result = vibgrate && isInstalledOwnBinary(vibgrate) ? 'vibgrate' : NPX_INVOCATION;\n }\n\n if (!which) cached = result;\n return result;\n}\n\n/** Reset the memoized invocation. Test-only. */\nexport function resetCliInvocationCache(): void {\n cached = undefined;\n}\n\n/**\n * Absolute path of the JS file this process is running, when there is one.\n *\n * npm / pnpm / yarn / bun global bins are symlinks named `vg` (no `.js`\n * suffix). Callers that re-spawn as `node ${argv[1]} …` must realpath those,\n * otherwise `argv[1]` looks like a packaged binary and they exec\n * `node daemon …` — Node then exits 1 looking for a module named `daemon`.\n *\n * Returns null for a packaged binary, where `argv[1]` is the first user\n * argument (`daemon`, `scan`, …) rather than a script path.\n */\nexport function resolveSelfJsEntry(argv1: string = process.argv[1] ?? ''): string | null {\n if (!argv1) return null;\n const candidates = [argv1];\n try {\n const real = fs.realpathSync(argv1);\n if (real !== argv1) candidates.push(real);\n } catch {\n /* argv[1] is not a path (packaged binary: first CLI arg) */\n }\n for (const p of candidates) {\n if (!JS_ENTRY.test(p)) continue;\n return path.isAbsolute(p) ? p : path.resolve(p);\n }\n return null;\n}\n\n/**\n * Command + argv to re-invoke this CLI (detached daemon start, background\n * embed warm, …). Prefers `node <js-entry> <args>` so a global `vg` symlink\n * is not mistaken for a packaged binary.\n */\nexport function reinvokeCli(args: string[]): { command: string; argv: string[] } {\n const js = resolveSelfJsEntry();\n if (js) return { command: process.execPath, argv: [js, ...args] };\n return { command: process.argv[0] || 'vg', argv: args };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseOllamaPs, parseNvidiaSmi } from './chunk-7N4Y3E47.js';
|
|
2
|
-
import { whichOnPath, init_cli_invocation } from './chunk-
|
|
2
|
+
import { whichOnPath, init_cli_invocation } from './chunk-EZ7UC5Y5.js';
|
|
3
3
|
import { __export, __esm } from './chunk-Z6ZWNWWR.js';
|
|
4
4
|
import * as fs2 from 'fs';
|
|
5
5
|
import * as os2 from 'os';
|
|
@@ -168,5 +168,5 @@ function safeRun(bin, args) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
export { gatherSystemMemory, hasOllama, hasOllamaBinary, init_resolve_ollama, pullModelClean, resolveOllamaBinary, resolve_ollama_exports, stopModel };
|
|
171
|
-
//# sourceMappingURL=chunk-
|
|
172
|
-
//# sourceMappingURL=chunk-
|
|
171
|
+
//# sourceMappingURL=chunk-FJG5AXKZ.js.map
|
|
172
|
+
//# sourceMappingURL=chunk-FJG5AXKZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/util/resolve-ollama.ts","../src/code/available-memory.ts","../src/code/local-runtime.ts"],"names":["freemem","os","fs","os3","spawnSync"],"mappings":"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","file":"chunk-OWSFZQOP.js","sourcesContent":["/**\n * Locate the Ollama CLI for install/uninstall/pull.\n *\n * Dock-launched GUI apps (VS Code, Cursor) often inherit a stripped PATH that\n * omits Homebrew (`/opt/homebrew/bin`) and the official installer locations.\n * Discovery of models still works (on-disk manifests under ~/.ollama), so the\n * UI lists models that then fail to uninstall with \"ollama not on PATH\".\n * Resolve the binary via PATH first, then well-known install prefixes.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { whichOnPath } from './cli-invocation.js';\n\n/** Absolute path to the ollama binary, or null if not found. */\nexport function resolveOllamaBinary(): string | null {\n const names = process.platform === 'win32' ? ['ollama.exe', 'ollama'] : ['ollama'];\n for (const name of names) {\n const hit = whichOnPath(name);\n if (hit) return hit;\n }\n\n const candidates =\n process.platform === 'win32'\n ? [\n path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Ollama', 'ollama.exe'),\n path.join(process.env.ProgramFiles || 'C:\\\\Program Files', 'Ollama', 'ollama.exe'),\n ]\n : [\n '/opt/homebrew/bin/ollama',\n '/usr/local/bin/ollama',\n '/usr/bin/ollama',\n path.join(os.homedir(), '.local', 'bin', 'ollama'),\n ];\n\n for (const c of candidates) {\n if (!c) continue;\n try {\n if (fs.existsSync(c)) return c;\n } catch {\n /* ignore */\n }\n }\n return null;\n}\n\n/** True when the Ollama CLI is on PATH or at a known install location. */\nexport function hasOllamaBinary(): boolean {\n return resolveOllamaBinary() !== null;\n}\n","/**\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 { hasOllamaBinary, resolveOllamaBinary } from '../util/resolve-ollama.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 ollama = resolveOllamaBinary();\n const loaded = ollama ? 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 or a known install location. */\nexport function hasOllama(): boolean {\n return hasOllamaBinary();\n}\n\n/** Unload a running model to free memory. Returns true on success. */\nexport function stopModel(name: string): boolean {\n const ollama = resolveOllamaBinary();\n if (!ollama) return false;\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 ollama = resolveOllamaBinary();\n if (!ollama) {\n resolve(false);\n return;\n }\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/util/resolve-ollama.ts","../src/code/available-memory.ts","../src/code/local-runtime.ts"],"names":["freemem","os","fs","os3","spawnSync"],"mappings":"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","file":"chunk-FJG5AXKZ.js","sourcesContent":["/**\n * Locate the Ollama CLI for install/uninstall/pull.\n *\n * Dock-launched GUI apps (VS Code, Cursor) often inherit a stripped PATH that\n * omits Homebrew (`/opt/homebrew/bin`) and the official installer locations.\n * Discovery of models still works (on-disk manifests under ~/.ollama), so the\n * UI lists models that then fail to uninstall with \"ollama not on PATH\".\n * Resolve the binary via PATH first, then well-known install prefixes.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { whichOnPath } from './cli-invocation.js';\n\n/** Absolute path to the ollama binary, or null if not found. */\nexport function resolveOllamaBinary(): string | null {\n const names = process.platform === 'win32' ? ['ollama.exe', 'ollama'] : ['ollama'];\n for (const name of names) {\n const hit = whichOnPath(name);\n if (hit) return hit;\n }\n\n const candidates =\n process.platform === 'win32'\n ? [\n path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Ollama', 'ollama.exe'),\n path.join(process.env.ProgramFiles || 'C:\\\\Program Files', 'Ollama', 'ollama.exe'),\n ]\n : [\n '/opt/homebrew/bin/ollama',\n '/usr/local/bin/ollama',\n '/usr/bin/ollama',\n path.join(os.homedir(), '.local', 'bin', 'ollama'),\n ];\n\n for (const c of candidates) {\n if (!c) continue;\n try {\n if (fs.existsSync(c)) return c;\n } catch {\n /* ignore */\n }\n }\n return null;\n}\n\n/** True when the Ollama CLI is on PATH or at a known install location. */\nexport function hasOllamaBinary(): boolean {\n return resolveOllamaBinary() !== null;\n}\n","/**\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 { hasOllamaBinary, resolveOllamaBinary } from '../util/resolve-ollama.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 ollama = resolveOllamaBinary();\n const loaded = ollama ? 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 or a known install location. */\nexport function hasOllama(): boolean {\n return hasOllamaBinary();\n}\n\n/** Unload a running model to free memory. Returns true on success. */\nexport function stopModel(name: string): boolean {\n const ollama = resolveOllamaBinary();\n if (!ollama) return false;\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 ollama = resolveOllamaBinary();\n if (!ollama) {\n resolve(false);\n return;\n }\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"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { listHostSessions, hostSessionPoolSize, acquireHostSession, evictIdleSessions, clearHostSessionPool, dropHostSession, generateOnSession } from './chunk-3LOWJSAF.js';
|
|
2
2
|
import { vgdSocketPath, vgdPidPath } from './chunk-RBIRXQR6.js';
|
|
3
3
|
import { resolveOne } from './chunk-J7LKEB2R.js';
|
|
4
|
-
import { impactOf, queryGraph } from './chunk-
|
|
5
|
-
import { loadGraph } from './chunk-
|
|
4
|
+
import { impactOf, queryGraph } from './chunk-Q4G2BWE3.js';
|
|
5
|
+
import { loadGraph } from './chunk-3FMRFECC.js';
|
|
6
|
+
import { VERSION } from './chunk-PRG2ULPK.js';
|
|
6
7
|
import { repositoryIdFromRoot, globalGraphPathForRef, globalGraphPath } from './chunk-BWPBB45M.js';
|
|
7
8
|
import { activeGraphSlotKey, detectGitRef } from './chunk-BPF3YX2U.js';
|
|
8
9
|
import * as path from 'path';
|
|
@@ -1005,13 +1006,14 @@ async function handleLine(line, ctx) {
|
|
|
1005
1006
|
workspaces: ctx.registry.size(),
|
|
1006
1007
|
graphSlots: ctx.registry.graphs.size(),
|
|
1007
1008
|
version: VGD_PROTOCOL_VERSION,
|
|
1008
|
-
socketPath: ctx.socketPath
|
|
1009
|
+
socketPath: ctx.socketPath,
|
|
1010
|
+
cliVersion: VERSION
|
|
1009
1011
|
};
|
|
1010
1012
|
case "shutdown": {
|
|
1011
1013
|
if (!ctx.onShutdownRequest) {
|
|
1012
1014
|
return {
|
|
1013
1015
|
ok: false,
|
|
1014
|
-
error: "this vgd
|
|
1016
|
+
error: "this vgd cannot be stopped remotely \u2014 it is running inside another process; stop that process instead",
|
|
1015
1017
|
code: "shutdown_unsupported"
|
|
1016
1018
|
};
|
|
1017
1019
|
}
|
|
@@ -1314,5 +1316,5 @@ var BranchGraphSession = class {
|
|
|
1314
1316
|
};
|
|
1315
1317
|
|
|
1316
1318
|
export { ActiveGraphCache, BranchGraphSession, DEFAULT_ACTIVE_GRAPH_IDLE_MS, VGD_PROTOCOL_VERSION, WorkspaceRegistry, parseRequest, startVgdServer };
|
|
1317
|
-
//# sourceMappingURL=chunk-
|
|
1318
|
-
//# sourceMappingURL=chunk-
|
|
1319
|
+
//# sourceMappingURL=chunk-GOGMS3ST.js.map
|
|
1320
|
+
//# sourceMappingURL=chunk-GOGMS3ST.js.map
|