@vibgrate/cli 2026.727.1 → 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 (124) hide show
  1. package/DOCS.md +0 -17
  2. package/README.md +0 -1
  3. package/dist/baseline-TG4ATZGZ.js +8 -0
  4. package/dist/{baseline-K7YBFKZI.js.map → baseline-TG4ATZGZ.js.map} +1 -1
  5. package/dist/{chunk-JZYGEZTU.js → chunk-2MBL43EJ.js} +3 -3
  6. package/dist/{chunk-JZYGEZTU.js.map → chunk-2MBL43EJ.js.map} +1 -1
  7. package/dist/{chunk-HABUT7HW.js → chunk-2XQDMLKB.js} +240 -8
  8. package/dist/chunk-2XQDMLKB.js.map +1 -0
  9. package/dist/{chunk-VXGV6NTD.js → chunk-3V24O47U.js} +11 -9
  10. package/dist/chunk-3V24O47U.js.map +1 -0
  11. package/dist/{chunk-6IOQJGFT.js → chunk-6ABXHZRN.js} +34 -77
  12. package/dist/chunk-6ABXHZRN.js.map +1 -0
  13. package/dist/{chunk-4CQ3MGNN.js → chunk-6AYDFFP5.js} +3 -3
  14. package/dist/{chunk-4CQ3MGNN.js.map → chunk-6AYDFFP5.js.map} +1 -1
  15. package/dist/chunk-6UQMXIAG.js +122 -0
  16. package/dist/chunk-6UQMXIAG.js.map +1 -0
  17. package/dist/{chunk-KHJO4D5N.js → chunk-7N4Y3E47.js} +2 -2
  18. package/dist/{chunk-KHJO4D5N.js.map → chunk-7N4Y3E47.js.map} +1 -1
  19. package/dist/{chunk-OXQNQW5J.js → chunk-CY4WKXB2.js} +4 -4
  20. package/dist/{chunk-OXQNQW5J.js.map → chunk-CY4WKXB2.js.map} +1 -1
  21. package/dist/chunk-DGUM43GV.js +10 -0
  22. package/dist/chunk-DGUM43GV.js.map +1 -0
  23. package/dist/{chunk-HYZVHJ3Q.js → chunk-EX4PQT6W.js} +3 -3
  24. package/dist/{chunk-HYZVHJ3Q.js.map → chunk-EX4PQT6W.js.map} +1 -1
  25. package/dist/{chunk-3BVSDMHV.js → chunk-J4RFRKZH.js} +7 -7
  26. package/dist/{chunk-3BVSDMHV.js.map → chunk-J4RFRKZH.js.map} +1 -1
  27. package/dist/chunk-K3MZIVZW.js +88 -0
  28. package/dist/chunk-K3MZIVZW.js.map +1 -0
  29. package/dist/{chunk-65MEOA4E.js → chunk-KCKYKDMS.js} +9 -8
  30. package/dist/chunk-KCKYKDMS.js.map +1 -0
  31. package/dist/{chunk-S6CYDZEW.js → chunk-KNELIQJO.js} +364 -179
  32. package/dist/chunk-KNELIQJO.js.map +1 -0
  33. package/dist/{chunk-EDAAG7BL.js → chunk-KSBHGWRV.js} +4 -3
  34. package/dist/chunk-KSBHGWRV.js.map +1 -0
  35. package/dist/{chunk-C4CKTAZP.js → chunk-LKVMI67M.js} +4 -4
  36. package/dist/chunk-LKVMI67M.js.map +1 -0
  37. package/dist/{chunk-7JHPQ6WF.js → chunk-OFUC6RYN.js} +3 -3
  38. package/dist/{chunk-7JHPQ6WF.js.map → chunk-OFUC6RYN.js.map} +1 -1
  39. package/dist/{chunk-YDAT7LD2.js → chunk-RNP3SMTV.js} +17 -9
  40. package/dist/chunk-RNP3SMTV.js.map +1 -0
  41. package/dist/{chunk-SZLF66FJ.js → chunk-TCDAZZNP.js} +5 -5
  42. package/dist/{chunk-SZLF66FJ.js.map → chunk-TCDAZZNP.js.map} +1 -1
  43. package/dist/{chunk-WLETRGAC.js → chunk-WGUL45AV.js} +11 -11
  44. package/dist/{chunk-WLETRGAC.js.map → chunk-WGUL45AV.js.map} +1 -1
  45. package/dist/cli.d.ts +3 -0
  46. package/dist/cli.js +97 -240
  47. package/dist/cli.js.map +1 -1
  48. package/dist/{execution-env-3BN7Z737.js → execution-env-ZU45JZ4G.js} +3 -2
  49. package/dist/{execution-env-3BN7Z737.js.map → execution-env-ZU45JZ4G.js.map} +1 -1
  50. package/dist/{federation-EPZDUWCK.js → federation-SZWZIFZ7.js} +3 -2
  51. package/dist/{federation-EPZDUWCK.js.map → federation-SZWZIFZ7.js.map} +1 -1
  52. package/dist/{fs-IPY4FJKH.js → fs-B5HZ2MIU.js} +3 -2
  53. package/dist/fs-B5HZ2MIU.js.map +1 -0
  54. package/dist/{fs-KCABDURV.js → fs-O5IQYXHO.js} +3 -2
  55. package/dist/fs-O5IQYXHO.js.map +1 -0
  56. package/dist/{git-ref-HPRLUFFW.js → git-ref-XDXB6JP5.js} +3 -2
  57. package/dist/{git-ref-HPRLUFFW.js.map → git-ref-XDXB6JP5.js.map} +1 -1
  58. package/dist/graph-backend-73URGTFY.js +11 -0
  59. package/dist/{graph-backend-ZMSYOZMW.js.map → graph-backend-73URGTFY.js.map} +1 -1
  60. package/dist/index.d.ts +44 -15
  61. package/dist/index.js +9 -8
  62. package/dist/index.js.map +1 -1
  63. package/dist/{interactive-ICL7D7LO.js → interactive-372NLI5C.js} +19 -18
  64. package/dist/interactive-372NLI5C.js.map +1 -0
  65. package/dist/{llm-host-2RAYQSDQ.js → llm-host-7GWDO6IX.js} +3 -2
  66. package/dist/{llm-host-2RAYQSDQ.js.map → llm-host-7GWDO6IX.js.map} +1 -1
  67. package/dist/load-I333TGNI.js +8 -0
  68. package/dist/{load-OHVKDX4R.js.map → load-I333TGNI.js.map} +1 -1
  69. package/dist/local-runtime-5O2NN3GA.js +5 -0
  70. package/dist/{local-runtime-OJFLX2HI.js.map → local-runtime-5O2NN3GA.js.map} +1 -1
  71. package/dist/mcp-tools-I7JK3S2M.js +4 -0
  72. package/dist/{mcp-tools-I6PME3AV.js.map → mcp-tools-I7JK3S2M.js.map} +1 -1
  73. package/dist/{model-execution-profile-MQ2QCP24.js → model-execution-profile-TFBKCNJG.js} +3 -2
  74. package/dist/{model-execution-profile-MQ2QCP24.js.map → model-execution-profile-TFBKCNJG.js.map} +1 -1
  75. package/dist/{model-orchestrator-FFTZI3U2.js → model-orchestrator-TVONAUPS.js} +5 -4
  76. package/dist/{model-orchestrator-FFTZI3U2.js.map → model-orchestrator-TVONAUPS.js.map} +1 -1
  77. package/dist/parse-worker.d.ts +1 -1
  78. package/dist/parse-worker.js +1 -0
  79. package/dist/parse-worker.js.map +1 -1
  80. package/dist/{paths-MCH75O3G.js → paths-2RAH3GME.js} +3 -2
  81. package/dist/{paths-MCH75O3G.js.map → paths-2RAH3GME.js.map} +1 -1
  82. package/dist/{resolve-gguf-4UPIGPEE.js → resolve-gguf-VPL4YQ6J.js} +3 -2
  83. package/dist/{resolve-gguf-4UPIGPEE.js.map → resolve-gguf-VPL4YQ6J.js.map} +1 -1
  84. package/dist/runtime-session-JRKCQUHY.js +18 -0
  85. package/dist/{runtime-session-IDU5BDUJ.js.map → runtime-session-JRKCQUHY.js.map} +1 -1
  86. package/dist/session-ITPYQ5XI.js +11 -0
  87. package/dist/{session-L2OSDRPI.js.map → session-ITPYQ5XI.js.map} +1 -1
  88. package/dist/session-store-WFBX7HXL.js +4 -0
  89. package/dist/{session-store-W5RZZHA3.js.map → session-store-WFBX7HXL.js.map} +1 -1
  90. package/dist/{stream-json-F74W5FCK.js → stream-json-SLMDKLXP.js} +10 -9
  91. package/dist/stream-json-SLMDKLXP.js.map +1 -0
  92. package/dist/{types-ZMg1mSuu.d.ts → types-7AHBUbFm.d.ts} +5 -1
  93. package/dist/ui-Q6DJ3GCU.js +5 -0
  94. package/dist/ui-Q6DJ3GCU.js.map +1 -0
  95. package/dist/{vgd-EGBQD7BW.js → vgd-7JV5KCNJ.js} +7 -6
  96. package/dist/vgd-7JV5KCNJ.js.map +1 -0
  97. package/package.json +1 -1
  98. package/dist/baseline-K7YBFKZI.js +0 -7
  99. package/dist/chunk-5Q54GEHM.js +0 -29
  100. package/dist/chunk-5Q54GEHM.js.map +0 -1
  101. package/dist/chunk-65MEOA4E.js.map +0 -1
  102. package/dist/chunk-6IOQJGFT.js.map +0 -1
  103. package/dist/chunk-C4CKTAZP.js.map +0 -1
  104. package/dist/chunk-EDAAG7BL.js.map +0 -1
  105. package/dist/chunk-EDBV33B7.js +0 -57
  106. package/dist/chunk-EDBV33B7.js.map +0 -1
  107. package/dist/chunk-HABUT7HW.js.map +0 -1
  108. package/dist/chunk-S6CYDZEW.js.map +0 -1
  109. package/dist/chunk-VXGV6NTD.js.map +0 -1
  110. package/dist/chunk-YDAT7LD2.js.map +0 -1
  111. package/dist/fs-IPY4FJKH.js.map +0 -1
  112. package/dist/fs-KCABDURV.js.map +0 -1
  113. package/dist/graph-backend-ZMSYOZMW.js +0 -10
  114. package/dist/interactive-ICL7D7LO.js.map +0 -1
  115. package/dist/load-OHVKDX4R.js +0 -7
  116. package/dist/local-runtime-OJFLX2HI.js +0 -4
  117. package/dist/mcp-tools-I6PME3AV.js +0 -3
  118. package/dist/runtime-session-IDU5BDUJ.js +0 -17
  119. package/dist/session-L2OSDRPI.js +0 -10
  120. package/dist/session-store-W5RZZHA3.js +0 -3
  121. package/dist/stream-json-F74W5FCK.js.map +0 -1
  122. package/dist/ui-HOVOPWMX.js +0 -4
  123. package/dist/ui-HOVOPWMX.js.map +0 -1
  124. package/dist/vgd-EGBQD7BW.js.map +0 -1
@@ -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"]}
@@ -104,5 +104,5 @@ function toBytes(n, unit) {
104
104
  }
105
105
 
106
106
  export { assessCapability, estimateModelBytes, fmt, parseNvidiaSmi, parseOllamaPs };
107
- //# sourceMappingURL=chunk-KHJO4D5N.js.map
108
- //# sourceMappingURL=chunk-KHJO4D5N.js.map
107
+ //# sourceMappingURL=chunk-7N4Y3E47.js.map
108
+ //# sourceMappingURL=chunk-7N4Y3E47.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/code/capability.ts"],"names":[],"mappings":"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","file":"chunk-KHJO4D5N.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 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"]}
1
+ {"version":3,"sources":["../src/code/capability.ts"],"names":[],"mappings":"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","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"]}
@@ -1,5 +1,5 @@
1
- import { buildMessages, parseEdits, applyEdits, unifiedDiff, redactSecrets } from './chunk-7JHPQ6WF.js';
2
- import { recordCliCall, CLI_TOOL_ALIASES, buildCodeContext, buildTaskCapsule, capsuleToCodeContext } from './chunk-EDAAG7BL.js';
1
+ import { buildMessages, parseEdits, applyEdits, unifiedDiff, redactSecrets } from './chunk-OFUC6RYN.js';
2
+ import { recordCliCall, CLI_TOOL_ALIASES, buildCodeContext, buildTaskCapsule, capsuleToCodeContext } from './chunk-KSBHGWRV.js';
3
3
  import { repositoryIdFromRoot } from './chunk-BWPBB45M.js';
4
4
  import * as fs from 'fs';
5
5
  import * as path from 'path';
@@ -251,5 +251,5 @@ function shortId() {
251
251
  }
252
252
 
253
253
  export { commitChanges, nodeCodeFs, runCodeSession, undoChanges };
254
- //# sourceMappingURL=chunk-OXQNQW5J.js.map
255
- //# sourceMappingURL=chunk-OXQNQW5J.js.map
254
+ //# sourceMappingURL=chunk-CY4WKXB2.js.map
255
+ //# sourceMappingURL=chunk-CY4WKXB2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/code/session.ts"],"names":["resolve"],"mappings":"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","file":"chunk-OXQNQW5J.js","sourcesContent":["/**\n * The `vg code` governance session (VG-CLI-CODE §7).\n *\n * This is the load-bearing rule the whole platform is built on, applied to code\n * edits: a state-altering change goes **through** the lifecycle, never around it\n * (GUARDRAILS §5). One run walks inspect → assess → dry-run → approve → execute\n * → verify → log:\n *\n * inspect build the graph-grounded context for the instruction\n * assess ask the routed model for a terse edit; apply it deterministically\n * (in memory); compute the diff and the blast radius\n * dry-run the DEFAULT terminal state — propose the change, write nothing\n * approve writing requires explicit consent; without it we stop at dry-run\n * execute write the approved changes to disk\n * verify confirm the files on disk match what was approved (+ optional cmd)\n * log append an immutable, secret-free audit record with a correlation id\n *\n * Everything is deterministic except the single model call, which is isolated\n * behind the provider list (tried in order, falling back on transport failure).\n * The filesystem and clock are injectable so the whole session is testable\n * offline with no writes escaping a temp dir.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { buildCodeContext } from './context.js';\nimport { buildTaskCapsule, capsuleToCodeContext } from './capsule.js';\nimport { recordCliCall, CLI_TOOL_ALIASES } from '../engine/savings.js';\nimport { repositoryIdFromRoot } from '../runtime/paths.js';\nimport { parseEdits, applyEdits, type SymbolSpan } from './apply.js';\nimport { unifiedDiff } from './diff.js';\nimport { buildMessages } from './prompt.js';\nimport { redactSecrets } from './providers.js';\nimport type { ChatOptions, CodeContext, CodeSessionResult, FileChange, LifecyclePhase, Provider, ProviderResult } from './types.js';\nimport type { VgGraph } from '../schema.js';\n\n/** Minimal filesystem seam so the session is testable without touching real disk. */\nexport interface CodeFs {\n read(file: string): string | null;\n write(file: string, content: string): void;\n remove(file: string): void;\n appendAudit(line: string): void;\n}\n\nexport interface RunSessionOptions {\n graph: VgGraph;\n root: string;\n instruction: string;\n /** Providers to try in order (from the router); the first that answers wins. */\n providers: Provider[];\n /** Write to disk? Default false — dry-run is the safe default (GUARDRAILS §3.2). */\n apply?: boolean;\n /** Explicit consent for the write (`--yes`); without it, a requested apply stops at dry-run. */\n consent?: boolean;\n /** Restrict the edit surface to these files. */\n files?: string[];\n /** Context token budget. */\n budget?: number;\n chatOptions?: ChatOptions;\n /** Injectable filesystem (defaults to a real, root-scoped fs). */\n fsImpl?: CodeFs;\n /** Injectable clock (ms) for the audit timestamp. */\n now?: () => number;\n /** Injectable correlation id (defaults to a random short id). */\n correlationId?: string;\n /** Progress callback per phase. */\n onPhase?: (phase: LifecyclePhase, detail: string) => void;\n /** Skip appending to the audit log (used by tests/dry programmatic calls). */\n noAudit?: boolean;\n /**\n * Who is making the graph-backed call, for per-model savings auditing. When\n * `client` is set, the context-assembly step (a `query_graph`-equivalent) is\n * recorded to the local savings ledger tagged with the provider + model, so\n * `vg savings` can break usage down per model. VG Code always sets this.\n */\n attribution?: { client: string; provider?: string; model?: string };\n /**\n * Use a source-bearing Task Capsule for the inspect context (Fusion Runtime\n * Phase 0 A/B). Default false keeps the metadata-only path.\n */\n capsule?: boolean;\n}\n\nexport async function runCodeSession(options: RunSessionOptions): Promise<CodeSessionResult> {\n const {\n graph,\n root,\n instruction,\n providers,\n apply = false,\n consent = false,\n files,\n budget,\n chatOptions,\n now = () => 0,\n onPhase = () => {},\n } = options;\n const fsImpl = options.fsImpl ?? nodeCodeFs(root);\n const correlationId = options.correlationId ?? shortId();\n const phasesRun: LifecyclePhase[] = [];\n const phase = (p: LifecyclePhase, detail: string): void => {\n phasesRun.push(p);\n onPhase(p, detail);\n };\n\n // ── inspect ──────────────────────────────────────────────────────────────\n phase('inspect', options.capsule ? 'building source-bearing task capsule' : 'building graph-grounded context');\n const context = buildSessionContext(graph, instruction, {\n budget,\n files,\n capsule: options.capsule,\n root,\n fsImpl,\n });\n\n // Per-model savings: the context build is VG Code's `query_graph`-equivalent.\n // Record it (counts only — never code or the instruction) tagged with the\n // model, so `vg savings` audits usage per model. Local-only, best-effort.\n if (options.attribution?.client) {\n const seedFiles = new Set(context.seeds.map((s) => s.node.file).filter(Boolean));\n recordCliCall(\n root,\n {\n tool: CLI_TOOL_ALIASES.ask,\n client: options.attribution.client,\n provider: options.attribution.provider,\n model: options.attribution.model,\n outcome: context.seeds.length ? 'complete' : 'miss',\n vgTokens: context.tokensEstimate,\n baselineFiles: seedFiles.size,\n },\n now(),\n );\n }\n\n // ── assess ──────────────────────────────────────────────────────────────\n phase('assess', 'asking the routed model for a minimal edit');\n const messages = buildMessages(context);\n const { result, provider, fellBack } = await complete(providers, messages, chatOptions, correlationId);\n\n const edits = parseEdits(result.text);\n const spans = spanIndex(graph);\n const applied = applyEdits(\n edits,\n (file) => fsImpl.read(file),\n (file) => spans.get(normalize(file)) ?? [],\n );\n\n const changes: FileChange[] = [];\n for (const [file, entry] of [...applied.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n changes.push({\n file,\n before: entry.before,\n after: entry.after,\n outcomes: entry.outcomes,\n diff: unifiedDiff(entry.before, entry.after, file),\n });\n }\n\n // ── dry-run (always produced) ─────────────────────────────────────────────\n phase('dry-run', `${changes.length} file(s) would change`);\n\n const anyApplicable = changes.some((c) => c.diff !== '' && c.outcomes.some((o) => o.status === 'applied'));\n const base: CodeSessionResult = {\n instruction,\n provider: { id: provider.id, model: provider.model, local: provider.local, fellBack },\n phasesRun,\n changes,\n applied: false,\n verification: { ran: false, ok: false, detail: 'dry-run — no changes written' },\n correlationId,\n };\n\n // ── approve ───────────────────────────────────────────────────────────────\n // Writing is opt-in AND consent-gated. A requested apply without consent is\n // not an error — it degrades to a dry-run so the caller can review, then\n // re-run with --yes. This is the \"never destructive-by-default\" guardrail.\n if (!apply) {\n if (!options.noAudit) writeAudit(fsImpl, base, now());\n return base;\n }\n if (!consent) {\n const stopped = { ...base, verification: { ran: false, ok: false, detail: 'apply requested without consent — re-run with --yes to write these changes' } };\n if (!options.noAudit) writeAudit(fsImpl, stopped, now());\n return stopped;\n }\n if (!anyApplicable) {\n const nothing = { ...base, verification: { ran: false, ok: false, detail: 'nothing to write — no edit applied cleanly' } };\n if (!options.noAudit) writeAudit(fsImpl, nothing, now());\n return nothing;\n }\n phase('approve', 'consent given (--yes)');\n\n // ── execute ───────────────────────────────────────────────────────────────\n phase('execute', 'writing approved changes');\n for (const change of changes) {\n if (change.diff === '') continue; // no-op file\n if (!change.outcomes.some((o) => o.status === 'applied')) continue; // nothing applied cleanly here\n if (change.after === null) fsImpl.remove(change.file);\n else fsImpl.write(change.file, change.after);\n }\n\n // ── verify ────────────────────────────────────────────────────────────────\n phase('verify', 'confirming on-disk content matches the approved change');\n const verification = verifyWrites(fsImpl, changes);\n\n // ── log ───────────────────────────────────────────────────────────────────\n phase('log', 'recording an audit entry');\n const final: CodeSessionResult = { ...base, applied: true, verification };\n if (!options.noAudit) writeAudit(fsImpl, final, now());\n return final;\n}\n\n/**\n * Commit an already-computed dry-run result: write the cleanly-applied changes,\n * verify them on disk, and append the audit record — the \"approve → execute →\n * verify → log\" tail of the lifecycle, run against a proposal the caller has\n * already shown and had approved (the interactive REPL uses this so it never\n * calls the model twice or writes something different from what was reviewed).\n */\nexport function commitChanges(result: CodeSessionResult, fsImpl: CodeFs, now: () => number = () => 0): CodeSessionResult {\n const anyApplicable = result.changes.some((c) => c.diff !== '' && c.outcomes.some((o) => o.status === 'applied'));\n if (!anyApplicable) {\n return { ...result, applied: false, verification: { ran: false, ok: false, detail: 'nothing to write — no edit applied cleanly' } };\n }\n for (const change of result.changes) {\n if (change.diff === '' || !change.outcomes.some((o) => o.status === 'applied')) continue;\n if (change.after === null) fsImpl.remove(change.file);\n else fsImpl.write(change.file, change.after);\n }\n const verification = verifyWrites(fsImpl, result.changes);\n const final: CodeSessionResult = { ...result, applied: true, verification, phasesRun: [...result.phasesRun, 'approve', 'execute', 'verify', 'log'] };\n writeAudit(fsImpl, final, now());\n return final;\n}\n\n/**\n * Undo a set of applied changes by restoring each file's prior content — the\n * `/undo` command. A created file (before === null) is removed; an edited or\n * deleted file is restored to its `before`. Only cleanly-applied changes are\n * reverted. Returns the files it restored.\n */\nexport function undoChanges(changes: FileChange[], fsImpl: CodeFs): string[] {\n const restored: string[] = [];\n for (const ch of changes) {\n if (!ch.outcomes.some((o) => o.status === 'applied')) continue;\n if (ch.before === null) fsImpl.remove(ch.file);\n else fsImpl.write(ch.file, ch.before);\n restored.push(ch.file);\n }\n return restored;\n}\n\nfunction buildSessionContext(\n graph: VgGraph,\n instruction: string,\n opts: { budget?: number; files?: string[]; capsule?: boolean; root: string; fsImpl: CodeFs },\n): CodeContext {\n const budget = opts.budget;\n const files = opts.files;\n if (!opts.capsule) {\n return buildCodeContext(graph, instruction, { budget, files });\n }\n const capsule = buildTaskCapsule(graph, instruction, {\n budget,\n files,\n readFile: (rel) => opts.fsImpl.read(rel),\n repositoryId: repositoryIdFromRoot(opts.root),\n });\n return capsuleToCodeContext(capsule);\n}\n\n/** Try each provider in order; fall back on transport failure. Throws the last actionable error. */\nasync function complete(\n providers: Provider[],\n messages: ReturnType<typeof buildMessages>,\n chatOptions: ChatOptions | undefined,\n correlationId: string,\n): Promise<{ result: ProviderResult; provider: Provider; fellBack: boolean }> {\n if (providers.length === 0) throw new Error(`no model provider available (ref ${correlationId})`);\n let lastErr: unknown;\n for (let i = 0; i < providers.length; i++) {\n const provider = providers[i];\n try {\n const result = await provider.chat(messages, { temperature: 0, ...chatOptions });\n return { result, provider, fellBack: i > 0 };\n } catch (e) {\n lastErr = e;\n }\n }\n const message = lastErr instanceof Error ? redactSecrets(lastErr.message) : String(lastErr);\n throw new Error(`${message} (ref ${correlationId})`);\n}\n\n/** Confirm each written file's on-disk content equals what we approved. */\nfunction verifyWrites(fsImpl: CodeFs, changes: FileChange[]): { ran: boolean; ok: boolean; detail: string } {\n let checked = 0;\n const mismatches: string[] = [];\n for (const change of changes) {\n if (change.diff === '' || !change.outcomes.some((o) => o.status === 'applied')) continue;\n checked++;\n const onDisk = fsImpl.read(change.file);\n if (onDisk !== change.after) mismatches.push(change.file);\n }\n if (mismatches.length) return { ran: true, ok: false, detail: `on-disk content differs for: ${mismatches.join(', ')}` };\n return { ran: true, ok: true, detail: `wrote and verified ${checked} file(s)` };\n}\n\n/** An append-only, secret-free audit record (GUARDRAILS §2.6 / §5). No file contents, no keys. */\nfunction writeAudit(fsImpl: CodeFs, r: CodeSessionResult, ts: number): void {\n const record = {\n ts,\n correlationId: r.correlationId,\n instruction: r.instruction.slice(0, 500),\n provider: r.provider.id,\n model: r.provider.model,\n local: r.provider.local,\n applied: r.applied,\n files: r.changes.map((c) => ({ file: c.file, statuses: c.outcomes.map((o) => o.status) })),\n verification: r.verification,\n phases: r.phasesRun,\n };\n try {\n fsImpl.appendAudit(JSON.stringify(record));\n } catch {\n /* audit is best-effort; never fail the run on a logging problem */\n }\n}\n\n/** Build a per-file map of symbol spans for graph-scoped edit disambiguation. */\nfunction spanIndex(graph: VgGraph): Map<string, SymbolSpan[]> {\n const map = new Map<string, SymbolSpan[]>();\n for (const n of graph.nodes) {\n if (n.kind === 'file' || n.kind === 'external') continue;\n const file = normalize(n.file);\n const list = map.get(file) ?? [];\n list.push({ qualifiedName: n.qualifiedName, file, start: n.span.start, end: n.span.end });\n map.set(file, list);\n }\n return map;\n}\n\nfunction normalize(file: string): string {\n return file.replace(/\\\\/g, '/').replace(/^\\.\\//, '');\n}\n\n/** Default filesystem impl, scoped to `root`. Refuses paths that escape the root. */\nexport function nodeCodeFs(root: string): CodeFs {\n const resolve = (file: string): string => {\n const abs = path.resolve(root, file);\n const rel = path.relative(root, abs);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`edit path escapes the project root: ${file} — refusing to touch files outside ${root}`);\n }\n return abs;\n };\n return {\n read(file) {\n try {\n return fs.readFileSync(resolve(file), 'utf8');\n } catch {\n return null;\n }\n },\n write(file, content) {\n const abs = resolve(file);\n fs.mkdirSync(path.dirname(abs), { recursive: true });\n fs.writeFileSync(abs, content);\n },\n remove(file) {\n try {\n fs.rmSync(resolve(file));\n } catch {\n /* already gone */\n }\n },\n appendAudit(line) {\n const dir = path.join(root, '.vibgrate');\n fs.mkdirSync(dir, { recursive: true });\n fs.appendFileSync(path.join(dir, 'code-audit.jsonl'), line + '\\n');\n },\n };\n}\n\n/** Short, URL-safe correlation id. Not a graph artifact, so runtime randomness is fine here. */\nfunction shortId(): string {\n let s = '';\n const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';\n for (let i = 0; i < 8; i++) s += alphabet[Math.floor(Math.random() * alphabet.length)];\n return s;\n}\n"]}
1
+ {"version":3,"sources":["../src/code/session.ts"],"names":["resolve"],"mappings":"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","file":"chunk-CY4WKXB2.js","sourcesContent":["/**\n * The `vg code` governance session (VG-CLI-CODE §7).\n *\n * This is the load-bearing rule the whole platform is built on, applied to code\n * edits: a state-altering change goes **through** the lifecycle, never around it\n * (GUARDRAILS §5). One run walks inspect → assess → dry-run → approve → execute\n * → verify → log:\n *\n * inspect build the graph-grounded context for the instruction\n * assess ask the routed model for a terse edit; apply it deterministically\n * (in memory); compute the diff and the blast radius\n * dry-run the DEFAULT terminal state — propose the change, write nothing\n * approve writing requires explicit consent; without it we stop at dry-run\n * execute write the approved changes to disk\n * verify confirm the files on disk match what was approved (+ optional cmd)\n * log append an immutable, secret-free audit record with a correlation id\n *\n * Everything is deterministic except the single model call, which is isolated\n * behind the provider list (tried in order, falling back on transport failure).\n * The filesystem and clock are injectable so the whole session is testable\n * offline with no writes escaping a temp dir.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { buildCodeContext } from './context.js';\nimport { buildTaskCapsule, capsuleToCodeContext } from './capsule.js';\nimport { recordCliCall, CLI_TOOL_ALIASES } from '../engine/savings.js';\nimport { repositoryIdFromRoot } from '../runtime/paths.js';\nimport { parseEdits, applyEdits, type SymbolSpan } from './apply.js';\nimport { unifiedDiff } from './diff.js';\nimport { buildMessages } from './prompt.js';\nimport { redactSecrets } from './providers.js';\nimport type { ChatOptions, CodeContext, CodeSessionResult, FileChange, LifecyclePhase, Provider, ProviderResult } from './types.js';\nimport type { VgGraph } from '../schema.js';\n\n/** Minimal filesystem seam so the session is testable without touching real disk. */\nexport interface CodeFs {\n read(file: string): string | null;\n write(file: string, content: string): void;\n remove(file: string): void;\n appendAudit(line: string): void;\n}\n\nexport interface RunSessionOptions {\n graph: VgGraph;\n root: string;\n instruction: string;\n /** Providers to try in order (from the router); the first that answers wins. */\n providers: Provider[];\n /** Write to disk? Default false — dry-run is the safe default (GUARDRAILS §3.2). */\n apply?: boolean;\n /** Explicit consent for the write (`--yes`); without it, a requested apply stops at dry-run. */\n consent?: boolean;\n /** Restrict the edit surface to these files. */\n files?: string[];\n /** Context token budget. */\n budget?: number;\n chatOptions?: ChatOptions;\n /** Injectable filesystem (defaults to a real, root-scoped fs). */\n fsImpl?: CodeFs;\n /** Injectable clock (ms) for the audit timestamp. */\n now?: () => number;\n /** Injectable correlation id (defaults to a random short id). */\n correlationId?: string;\n /** Progress callback per phase. */\n onPhase?: (phase: LifecyclePhase, detail: string) => void;\n /** Skip appending to the audit log (used by tests/dry programmatic calls). */\n noAudit?: boolean;\n /**\n * Who is making the graph-backed call, for per-model savings auditing. When\n * `client` is set, the context-assembly step (a `query_graph`-equivalent) is\n * recorded to the local savings ledger tagged with the provider + model, so\n * `vg savings` can break usage down per model. VG Code always sets this.\n */\n attribution?: { client: string; provider?: string; model?: string };\n /**\n * Use a source-bearing Task Capsule for the inspect context (Fusion Runtime\n * Phase 0 A/B). Default false keeps the metadata-only path.\n */\n capsule?: boolean;\n}\n\nexport async function runCodeSession(options: RunSessionOptions): Promise<CodeSessionResult> {\n const {\n graph,\n root,\n instruction,\n providers,\n apply = false,\n consent = false,\n files,\n budget,\n chatOptions,\n now = () => 0,\n onPhase = () => {},\n } = options;\n const fsImpl = options.fsImpl ?? nodeCodeFs(root);\n const correlationId = options.correlationId ?? shortId();\n const phasesRun: LifecyclePhase[] = [];\n const phase = (p: LifecyclePhase, detail: string): void => {\n phasesRun.push(p);\n onPhase(p, detail);\n };\n\n // ── inspect ──────────────────────────────────────────────────────────────\n phase('inspect', options.capsule ? 'building source-bearing task capsule' : 'building graph-grounded context');\n const context = buildSessionContext(graph, instruction, {\n budget,\n files,\n capsule: options.capsule,\n root,\n fsImpl,\n });\n\n // Per-model savings: the context build is VG Code's `query_graph`-equivalent.\n // Record it (counts only — never code or the instruction) tagged with the\n // model, so `vg savings` audits usage per model. Local-only, best-effort.\n if (options.attribution?.client) {\n const seedFiles = new Set(context.seeds.map((s) => s.node.file).filter(Boolean));\n recordCliCall(\n root,\n {\n tool: CLI_TOOL_ALIASES.ask,\n client: options.attribution.client,\n provider: options.attribution.provider,\n model: options.attribution.model,\n outcome: context.seeds.length ? 'complete' : 'miss',\n vgTokens: context.tokensEstimate,\n baselineFiles: seedFiles.size,\n },\n now(),\n );\n }\n\n // ── assess ──────────────────────────────────────────────────────────────\n phase('assess', 'asking the routed model for a minimal edit');\n const messages = buildMessages(context);\n const { result, provider, fellBack } = await complete(providers, messages, chatOptions, correlationId);\n\n const edits = parseEdits(result.text);\n const spans = spanIndex(graph);\n const applied = applyEdits(\n edits,\n (file) => fsImpl.read(file),\n (file) => spans.get(normalize(file)) ?? [],\n );\n\n const changes: FileChange[] = [];\n for (const [file, entry] of [...applied.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n changes.push({\n file,\n before: entry.before,\n after: entry.after,\n outcomes: entry.outcomes,\n diff: unifiedDiff(entry.before, entry.after, file),\n });\n }\n\n // ── dry-run (always produced) ─────────────────────────────────────────────\n phase('dry-run', `${changes.length} file(s) would change`);\n\n const anyApplicable = changes.some((c) => c.diff !== '' && c.outcomes.some((o) => o.status === 'applied'));\n const base: CodeSessionResult = {\n instruction,\n provider: { id: provider.id, model: provider.model, local: provider.local, fellBack },\n phasesRun,\n changes,\n applied: false,\n verification: { ran: false, ok: false, detail: 'dry-run — no changes written' },\n correlationId,\n };\n\n // ── approve ───────────────────────────────────────────────────────────────\n // Writing is opt-in AND consent-gated. A requested apply without consent is\n // not an error — it degrades to a dry-run so the caller can review, then\n // re-run with --yes. This is the \"never destructive-by-default\" guardrail.\n if (!apply) {\n if (!options.noAudit) writeAudit(fsImpl, base, now());\n return base;\n }\n if (!consent) {\n const stopped = { ...base, verification: { ran: false, ok: false, detail: 'apply requested without consent — re-run with --yes to write these changes' } };\n if (!options.noAudit) writeAudit(fsImpl, stopped, now());\n return stopped;\n }\n if (!anyApplicable) {\n const nothing = { ...base, verification: { ran: false, ok: false, detail: 'nothing to write — no edit applied cleanly' } };\n if (!options.noAudit) writeAudit(fsImpl, nothing, now());\n return nothing;\n }\n phase('approve', 'consent given (--yes)');\n\n // ── execute ───────────────────────────────────────────────────────────────\n phase('execute', 'writing approved changes');\n for (const change of changes) {\n if (change.diff === '') continue; // no-op file\n if (!change.outcomes.some((o) => o.status === 'applied')) continue; // nothing applied cleanly here\n if (change.after === null) fsImpl.remove(change.file);\n else fsImpl.write(change.file, change.after);\n }\n\n // ── verify ────────────────────────────────────────────────────────────────\n phase('verify', 'confirming on-disk content matches the approved change');\n const verification = verifyWrites(fsImpl, changes);\n\n // ── log ───────────────────────────────────────────────────────────────────\n phase('log', 'recording an audit entry');\n const final: CodeSessionResult = { ...base, applied: true, verification };\n if (!options.noAudit) writeAudit(fsImpl, final, now());\n return final;\n}\n\n/**\n * Commit an already-computed dry-run result: write the cleanly-applied changes,\n * verify them on disk, and append the audit record — the \"approve → execute →\n * verify → log\" tail of the lifecycle, run against a proposal the caller has\n * already shown and had approved (the interactive REPL uses this so it never\n * calls the model twice or writes something different from what was reviewed).\n */\nexport function commitChanges(result: CodeSessionResult, fsImpl: CodeFs, now: () => number = () => 0): CodeSessionResult {\n const anyApplicable = result.changes.some((c) => c.diff !== '' && c.outcomes.some((o) => o.status === 'applied'));\n if (!anyApplicable) {\n return { ...result, applied: false, verification: { ran: false, ok: false, detail: 'nothing to write — no edit applied cleanly' } };\n }\n for (const change of result.changes) {\n if (change.diff === '' || !change.outcomes.some((o) => o.status === 'applied')) continue;\n if (change.after === null) fsImpl.remove(change.file);\n else fsImpl.write(change.file, change.after);\n }\n const verification = verifyWrites(fsImpl, result.changes);\n const final: CodeSessionResult = { ...result, applied: true, verification, phasesRun: [...result.phasesRun, 'approve', 'execute', 'verify', 'log'] };\n writeAudit(fsImpl, final, now());\n return final;\n}\n\n/**\n * Undo a set of applied changes by restoring each file's prior content — the\n * `/undo` command. A created file (before === null) is removed; an edited or\n * deleted file is restored to its `before`. Only cleanly-applied changes are\n * reverted. Returns the files it restored.\n */\nexport function undoChanges(changes: FileChange[], fsImpl: CodeFs): string[] {\n const restored: string[] = [];\n for (const ch of changes) {\n if (!ch.outcomes.some((o) => o.status === 'applied')) continue;\n if (ch.before === null) fsImpl.remove(ch.file);\n else fsImpl.write(ch.file, ch.before);\n restored.push(ch.file);\n }\n return restored;\n}\n\nfunction buildSessionContext(\n graph: VgGraph,\n instruction: string,\n opts: { budget?: number; files?: string[]; capsule?: boolean; root: string; fsImpl: CodeFs },\n): CodeContext {\n const budget = opts.budget;\n const files = opts.files;\n if (!opts.capsule) {\n return buildCodeContext(graph, instruction, { budget, files });\n }\n const capsule = buildTaskCapsule(graph, instruction, {\n budget,\n files,\n readFile: (rel) => opts.fsImpl.read(rel),\n repositoryId: repositoryIdFromRoot(opts.root),\n });\n return capsuleToCodeContext(capsule);\n}\n\n/** Try each provider in order; fall back on transport failure. Throws the last actionable error. */\nasync function complete(\n providers: Provider[],\n messages: ReturnType<typeof buildMessages>,\n chatOptions: ChatOptions | undefined,\n correlationId: string,\n): Promise<{ result: ProviderResult; provider: Provider; fellBack: boolean }> {\n if (providers.length === 0) throw new Error(`no model provider available (ref ${correlationId})`);\n let lastErr: unknown;\n for (let i = 0; i < providers.length; i++) {\n const provider = providers[i];\n try {\n const result = await provider.chat(messages, { temperature: 0, ...chatOptions });\n return { result, provider, fellBack: i > 0 };\n } catch (e) {\n lastErr = e;\n }\n }\n const message = lastErr instanceof Error ? redactSecrets(lastErr.message) : String(lastErr);\n throw new Error(`${message} (ref ${correlationId})`);\n}\n\n/** Confirm each written file's on-disk content equals what we approved. */\nfunction verifyWrites(fsImpl: CodeFs, changes: FileChange[]): { ran: boolean; ok: boolean; detail: string } {\n let checked = 0;\n const mismatches: string[] = [];\n for (const change of changes) {\n if (change.diff === '' || !change.outcomes.some((o) => o.status === 'applied')) continue;\n checked++;\n const onDisk = fsImpl.read(change.file);\n if (onDisk !== change.after) mismatches.push(change.file);\n }\n if (mismatches.length) return { ran: true, ok: false, detail: `on-disk content differs for: ${mismatches.join(', ')}` };\n return { ran: true, ok: true, detail: `wrote and verified ${checked} file(s)` };\n}\n\n/** An append-only, secret-free audit record (GUARDRAILS §2.6 / §5). No file contents, no keys. */\nfunction writeAudit(fsImpl: CodeFs, r: CodeSessionResult, ts: number): void {\n const record = {\n ts,\n correlationId: r.correlationId,\n instruction: r.instruction.slice(0, 500),\n provider: r.provider.id,\n model: r.provider.model,\n local: r.provider.local,\n applied: r.applied,\n files: r.changes.map((c) => ({ file: c.file, statuses: c.outcomes.map((o) => o.status) })),\n verification: r.verification,\n phases: r.phasesRun,\n };\n try {\n fsImpl.appendAudit(JSON.stringify(record));\n } catch {\n /* audit is best-effort; never fail the run on a logging problem */\n }\n}\n\n/** Build a per-file map of symbol spans for graph-scoped edit disambiguation. */\nfunction spanIndex(graph: VgGraph): Map<string, SymbolSpan[]> {\n const map = new Map<string, SymbolSpan[]>();\n for (const n of graph.nodes) {\n if (n.kind === 'file' || n.kind === 'external') continue;\n const file = normalize(n.file);\n const list = map.get(file) ?? [];\n list.push({ qualifiedName: n.qualifiedName, file, start: n.span.start, end: n.span.end });\n map.set(file, list);\n }\n return map;\n}\n\nfunction normalize(file: string): string {\n return file.replace(/\\\\/g, '/').replace(/^\\.\\//, '');\n}\n\n/** Default filesystem impl, scoped to `root`. Refuses paths that escape the root. */\nexport function nodeCodeFs(root: string): CodeFs {\n const resolve = (file: string): string => {\n const abs = path.resolve(root, file);\n const rel = path.relative(root, abs);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`edit path escapes the project root: ${file} — refusing to touch files outside ${root}`);\n }\n return abs;\n };\n return {\n read(file) {\n try {\n return fs.readFileSync(resolve(file), 'utf8');\n } catch {\n return null;\n }\n },\n write(file, content) {\n const abs = resolve(file);\n fs.mkdirSync(path.dirname(abs), { recursive: true });\n fs.writeFileSync(abs, content);\n },\n remove(file) {\n try {\n fs.rmSync(resolve(file));\n } catch {\n /* already gone */\n }\n },\n appendAudit(line) {\n const dir = path.join(root, '.vibgrate');\n fs.mkdirSync(dir, { recursive: true });\n fs.appendFileSync(path.join(dir, 'code-audit.jsonl'), line + '\\n');\n },\n };\n}\n\n/** Short, URL-safe correlation id. Not a graph artifact, so runtime randomness is fine here. */\nfunction shortId(): string {\n let s = '';\n const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';\n for (let i = 0; i < 8; i++) s += alphabet[Math.floor(Math.random() * alphabet.length)];\n return s;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export { __require };
9
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
10
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-DGUM43GV.js"}
@@ -1,4 +1,4 @@
1
- import { runCoreScan, compactUiPurpose } from './chunk-WLETRGAC.js';
1
+ import { runCoreScan, compactUiPurpose } from './chunk-WGUL45AV.js';
2
2
  import { findPackageJsonFiles, readJsonFile, findFiles, readTextFile, pathExists } from './chunk-GI6W53LM.js';
3
3
  import { writeJsonFile } from './chunk-CRAMOEBE.js';
4
4
  import * as path3 from 'path';
@@ -4356,5 +4356,5 @@ var baselineCommand = new Command("baseline").description("Create a drift baseli
4356
4356
  });
4357
4357
 
4358
4358
  export { baselineCommand, loadAdvancedScanHook, runBaseline };
4359
- //# sourceMappingURL=chunk-HYZVHJ3Q.js.map
4360
- //# sourceMappingURL=chunk-HYZVHJ3Q.js.map
4359
+ //# sourceMappingURL=chunk-EX4PQT6W.js.map
4360
+ //# sourceMappingURL=chunk-EX4PQT6W.js.map