@vibgrate/cli 2026.722.2 → 2026.727.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/DOCS.md +418 -213
  2. package/README.md +34 -8
  3. package/dist/baseline-TG4ATZGZ.js +8 -0
  4. package/dist/{baseline-BD3A7EXD.js.map → baseline-TG4ATZGZ.js.map} +1 -1
  5. package/dist/chunk-2MBL43EJ.js +82 -0
  6. package/dist/chunk-2MBL43EJ.js.map +1 -0
  7. package/dist/chunk-2XQDMLKB.js +465 -0
  8. package/dist/chunk-2XQDMLKB.js.map +1 -0
  9. package/dist/{chunk-PY3DNX5H.js → chunk-3Q7QBWFW.js} +13 -2
  10. package/dist/chunk-3Q7QBWFW.js.map +1 -0
  11. package/dist/chunk-3V24O47U.js +478 -0
  12. package/dist/chunk-3V24O47U.js.map +1 -0
  13. package/dist/chunk-5I4VSBWQ.js +764 -0
  14. package/dist/chunk-5I4VSBWQ.js.map +1 -0
  15. package/dist/{chunk-WNIIKCNF.js → chunk-6ABXHZRN.js} +59 -311
  16. package/dist/chunk-6ABXHZRN.js.map +1 -0
  17. package/dist/chunk-6AYDFFP5.js +136 -0
  18. package/dist/chunk-6AYDFFP5.js.map +1 -0
  19. package/dist/chunk-6UQMXIAG.js +122 -0
  20. package/dist/chunk-6UQMXIAG.js.map +1 -0
  21. package/dist/chunk-7N4Y3E47.js +108 -0
  22. package/dist/chunk-7N4Y3E47.js.map +1 -0
  23. package/dist/chunk-BPF3YX2U.js +64 -0
  24. package/dist/chunk-BPF3YX2U.js.map +1 -0
  25. package/dist/chunk-BWPBB45M.js +88 -0
  26. package/dist/chunk-BWPBB45M.js.map +1 -0
  27. package/dist/{chunk-6CXTPC74.js → chunk-CY4WKXB2.js} +27 -6
  28. package/dist/chunk-CY4WKXB2.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +10 -0
  30. package/dist/chunk-DGUM43GV.js.map +1 -0
  31. package/dist/{chunk-NONYJLOJ.js → chunk-EX4PQT6W.js} +3 -3
  32. package/dist/{chunk-NONYJLOJ.js.map → chunk-EX4PQT6W.js.map} +1 -1
  33. package/dist/chunk-IS7VTH2Q.js +627 -0
  34. package/dist/chunk-IS7VTH2Q.js.map +1 -0
  35. package/dist/chunk-IZDH67DX.js +289 -0
  36. package/dist/chunk-IZDH67DX.js.map +1 -0
  37. package/dist/chunk-J4RFRKZH.js +2496 -0
  38. package/dist/chunk-J4RFRKZH.js.map +1 -0
  39. package/dist/chunk-J7LKEB2R.js +51 -0
  40. package/dist/chunk-J7LKEB2R.js.map +1 -0
  41. package/dist/chunk-JIBOJTGS.js +313 -0
  42. package/dist/chunk-JIBOJTGS.js.map +1 -0
  43. package/dist/chunk-K3MZIVZW.js +88 -0
  44. package/dist/chunk-K3MZIVZW.js.map +1 -0
  45. package/dist/chunk-K7REHDQS.js +776 -0
  46. package/dist/chunk-K7REHDQS.js.map +1 -0
  47. package/dist/{chunk-2O5YZVZV.js → chunk-KCKYKDMS.js} +23 -19
  48. package/dist/chunk-KCKYKDMS.js.map +1 -0
  49. package/dist/{chunk-3MXNNBLI.js → chunk-KNELIQJO.js} +1647 -2042
  50. package/dist/chunk-KNELIQJO.js.map +1 -0
  51. package/dist/chunk-KSBHGWRV.js +613 -0
  52. package/dist/chunk-KSBHGWRV.js.map +1 -0
  53. package/dist/chunk-LKVMI67M.js +1695 -0
  54. package/dist/chunk-LKVMI67M.js.map +1 -0
  55. package/dist/chunk-NDMDSPFX.js +69 -0
  56. package/dist/chunk-NDMDSPFX.js.map +1 -0
  57. package/dist/{chunk-CS37OBE3.js → chunk-OFUC6RYN.js} +791 -783
  58. package/dist/chunk-OFUC6RYN.js.map +1 -0
  59. package/dist/chunk-OOIG3RUM.js +276 -0
  60. package/dist/chunk-OOIG3RUM.js.map +1 -0
  61. package/dist/chunk-PMYWZRRS.js +62 -0
  62. package/dist/chunk-PMYWZRRS.js.map +1 -0
  63. package/dist/chunk-PXHNTC6D.js +382 -0
  64. package/dist/chunk-PXHNTC6D.js.map +1 -0
  65. package/dist/{chunk-I7GY7MVN.js → chunk-RNP3SMTV.js} +60 -12
  66. package/dist/chunk-RNP3SMTV.js.map +1 -0
  67. package/dist/chunk-TCDAZZNP.js +843 -0
  68. package/dist/chunk-TCDAZZNP.js.map +1 -0
  69. package/dist/{chunk-5BDHQ7DD.js → chunk-WGUL45AV.js} +24 -17
  70. package/dist/chunk-WGUL45AV.js.map +1 -0
  71. package/dist/cli.d.ts +3 -0
  72. package/dist/cli.js +3373 -617
  73. package/dist/cli.js.map +1 -1
  74. package/dist/execution-env-ZU45JZ4G.js +4 -0
  75. package/dist/execution-env-ZU45JZ4G.js.map +1 -0
  76. package/dist/federation-SZWZIFZ7.js +7 -0
  77. package/dist/federation-SZWZIFZ7.js.map +1 -0
  78. package/dist/{fs-IPY4FJKH.js → fs-B5HZ2MIU.js} +3 -2
  79. package/dist/fs-B5HZ2MIU.js.map +1 -0
  80. package/dist/{fs-KCABDURV.js → fs-O5IQYXHO.js} +3 -2
  81. package/dist/fs-O5IQYXHO.js.map +1 -0
  82. package/dist/git-ref-XDXB6JP5.js +4 -0
  83. package/dist/git-ref-XDXB6JP5.js.map +1 -0
  84. package/dist/graph-backend-73URGTFY.js +11 -0
  85. package/dist/graph-backend-73URGTFY.js.map +1 -0
  86. package/dist/index.d.ts +472 -137
  87. package/dist/index.js +15 -7
  88. package/dist/index.js.map +1 -1
  89. package/dist/{interactive-A4DISSIW.js → interactive-372NLI5C.js} +186 -226
  90. package/dist/interactive-372NLI5C.js.map +1 -0
  91. package/dist/llm-host-7GWDO6IX.js +9 -0
  92. package/dist/llm-host-7GWDO6IX.js.map +1 -0
  93. package/dist/load-I333TGNI.js +8 -0
  94. package/dist/load-I333TGNI.js.map +1 -0
  95. package/dist/local-runtime-5O2NN3GA.js +5 -0
  96. package/dist/local-runtime-5O2NN3GA.js.map +1 -0
  97. package/dist/mcp-tools-I7JK3S2M.js +4 -0
  98. package/dist/{mcp-tools-I6PME3AV.js.map → mcp-tools-I7JK3S2M.js.map} +1 -1
  99. package/dist/model-execution-profile-TFBKCNJG.js +4 -0
  100. package/dist/model-execution-profile-TFBKCNJG.js.map +1 -0
  101. package/dist/model-orchestrator-TVONAUPS.js +9 -0
  102. package/dist/model-orchestrator-TVONAUPS.js.map +1 -0
  103. package/dist/parse-worker.d.ts +1 -1
  104. package/dist/parse-worker.js +2 -1
  105. package/dist/parse-worker.js.map +1 -1
  106. package/dist/paths-2RAH3GME.js +6 -0
  107. package/dist/paths-2RAH3GME.js.map +1 -0
  108. package/dist/resolve-gguf-VPL4YQ6J.js +8 -0
  109. package/dist/resolve-gguf-VPL4YQ6J.js.map +1 -0
  110. package/dist/runtime-session-JRKCQUHY.js +18 -0
  111. package/dist/runtime-session-JRKCQUHY.js.map +1 -0
  112. package/dist/session-ITPYQ5XI.js +11 -0
  113. package/dist/{session-POJUDFPH.js.map → session-ITPYQ5XI.js.map} +1 -1
  114. package/dist/session-store-WFBX7HXL.js +4 -0
  115. package/dist/{session-store-W5RZZHA3.js.map → session-store-WFBX7HXL.js.map} +1 -1
  116. package/dist/{stream-json-Q2JGWPHB.js → stream-json-SLMDKLXP.js} +17 -6
  117. package/dist/stream-json-SLMDKLXP.js.map +1 -0
  118. package/dist/{types-Jl6RJ175.d.ts → types-7AHBUbFm.d.ts} +8 -2
  119. package/dist/ui-Q6DJ3GCU.js +5 -0
  120. package/dist/ui-Q6DJ3GCU.js.map +1 -0
  121. package/dist/vgd-7JV5KCNJ.js +17 -0
  122. package/dist/vgd-7JV5KCNJ.js.map +1 -0
  123. package/package.json +9 -6
  124. package/dist/baseline-BD3A7EXD.js +0 -7
  125. package/dist/chunk-2O5YZVZV.js.map +0 -1
  126. package/dist/chunk-3MXNNBLI.js.map +0 -1
  127. package/dist/chunk-5BDHQ7DD.js.map +0 -1
  128. package/dist/chunk-6CXTPC74.js.map +0 -1
  129. package/dist/chunk-CS37OBE3.js.map +0 -1
  130. package/dist/chunk-GGJZA3Q6.js +0 -961
  131. package/dist/chunk-GGJZA3Q6.js.map +0 -1
  132. package/dist/chunk-I7GY7MVN.js.map +0 -1
  133. package/dist/chunk-JBXNQCGE.js +0 -484
  134. package/dist/chunk-JBXNQCGE.js.map +0 -1
  135. package/dist/chunk-PY3DNX5H.js.map +0 -1
  136. package/dist/chunk-WNIIKCNF.js.map +0 -1
  137. package/dist/fs-IPY4FJKH.js.map +0 -1
  138. package/dist/fs-KCABDURV.js.map +0 -1
  139. package/dist/interactive-A4DISSIW.js.map +0 -1
  140. package/dist/mcp-tools-I6PME3AV.js +0 -3
  141. package/dist/session-POJUDFPH.js +0 -6
  142. package/dist/session-store-W5RZZHA3.js +0 -3
  143. package/dist/stream-json-Q2JGWPHB.js.map +0 -1
  144. package/dist/ui-HOVOPWMX.js +0 -4
  145. package/dist/ui-HOVOPWMX.js.map +0 -1
@@ -0,0 +1,51 @@
1
+ // src/engine/lookup.ts
2
+ function findNodes(graph, query) {
3
+ const q = query.trim();
4
+ if (!q) return [];
5
+ const byId = graph.nodes.filter((n) => n.id === q);
6
+ if (byId.length) return byId;
7
+ const fileLine = /^(.*):(\d+)$/.exec(q);
8
+ if (fileLine) {
9
+ const file = fileLine[1];
10
+ const line = Number(fileLine[2]);
11
+ const spanning = graph.nodes.filter((n) => n.file === file && n.span.start <= line && n.span.end >= line && n.kind !== "file").sort((a, b) => a.span.end - a.span.start - (b.span.end - b.span.start));
12
+ if (spanning.length) return spanning;
13
+ }
14
+ if (/[*?]/.test(q)) {
15
+ const re = globToRegExp(q);
16
+ return rank(graph.nodes.filter((n) => re.test(n.qualifiedName) || re.test(n.name) || re.test(n.file)));
17
+ }
18
+ const byQn = graph.nodes.filter((n) => n.qualifiedName === q);
19
+ if (byQn.length) return rank(byQn);
20
+ const byName = graph.nodes.filter((n) => n.name === q);
21
+ if (byName.length) return rank(byName);
22
+ const lower = q.toLowerCase();
23
+ const ci = graph.nodes.filter(
24
+ (n) => n.qualifiedName.toLowerCase() === lower || n.name.toLowerCase() === lower
25
+ );
26
+ if (ci.length) return rank(ci);
27
+ return rank(graph.nodes.filter((n) => n.qualifiedName.toLowerCase().includes(lower))).slice(0, 25);
28
+ }
29
+ function resolveOne(graph, query, pick) {
30
+ const candidates = findNodes(graph, query);
31
+ if (candidates.length === 0) return { candidates };
32
+ if (pick && pick >= 1 && pick <= candidates.length) return { node: candidates[pick - 1], candidates };
33
+ if (candidates.length === 1) return { node: candidates[0], candidates };
34
+ return { candidates };
35
+ }
36
+ function nodeById(graph, id) {
37
+ return graph.nodes.find((n) => n.id === id);
38
+ }
39
+ function rank(nodes) {
40
+ return [...nodes].sort(
41
+ (a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)
42
+ );
43
+ }
44
+ function globToRegExp(glob) {
45
+ const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
46
+ return new RegExp(`^${escaped}$`, "i");
47
+ }
48
+
49
+ export { findNodes, nodeById, resolveOne };
50
+ //# sourceMappingURL=chunk-J7LKEB2R.js.map
51
+ //# sourceMappingURL=chunk-J7LKEB2R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/lookup.ts"],"names":[],"mappings":"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","file":"chunk-J7LKEB2R.js","sourcesContent":["import type { GraphNode, VgGraph } from '../schema.js';\n\n/**\n * Lenient node resolution (VG-CLI-SPEC §3.3): resolve `<name>` by content-hash\n * id, qualified name, `file:line`, short name, or glob. Returns candidates\n * ranked by importance so the best match is first; ambiguity is surfaced (the\n * caller offers `--pick`). Deterministic ordering throughout.\n */\nexport function findNodes(graph: VgGraph, query: string): GraphNode[] {\n const q = query.trim();\n if (!q) return [];\n\n // 1. exact content-hash id\n const byId = graph.nodes.filter((n) => n.id === q);\n if (byId.length) return byId;\n\n // 2. file:line (e.g. src/order.ts:12) → smallest node spanning that line\n const fileLine = /^(.*):(\\d+)$/.exec(q);\n if (fileLine) {\n const file = fileLine[1];\n const line = Number(fileLine[2]);\n const spanning = graph.nodes\n .filter((n) => n.file === file && n.span.start <= line && n.span.end >= line && n.kind !== 'file')\n .sort((a, b) => a.span.end - a.span.start - (b.span.end - b.span.start));\n if (spanning.length) return spanning;\n }\n\n // 3. glob (contains * or ?)\n if (/[*?]/.test(q)) {\n const re = globToRegExp(q);\n return rank(graph.nodes.filter((n) => re.test(n.qualifiedName) || re.test(n.name) || re.test(n.file)));\n }\n\n // 4. exact qualified name, then short name, then case-insensitive\n const byQn = graph.nodes.filter((n) => n.qualifiedName === q);\n if (byQn.length) return rank(byQn);\n const byName = graph.nodes.filter((n) => n.name === q);\n if (byName.length) return rank(byName);\n\n const lower = q.toLowerCase();\n const ci = graph.nodes.filter(\n (n) => n.qualifiedName.toLowerCase() === lower || n.name.toLowerCase() === lower,\n );\n if (ci.length) return rank(ci);\n\n // 5. substring on qualified name (last resort, ranked)\n return rank(graph.nodes.filter((n) => n.qualifiedName.toLowerCase().includes(lower))).slice(0, 25);\n}\n\n/** Resolve to a single node, honoring a 1-based `--pick`. */\nexport function resolveOne(\n graph: VgGraph,\n query: string,\n pick?: number,\n): { node?: GraphNode; candidates: GraphNode[] } {\n const candidates = findNodes(graph, query);\n if (candidates.length === 0) return { candidates };\n if (pick && pick >= 1 && pick <= candidates.length) return { node: candidates[pick - 1], candidates };\n if (candidates.length === 1) return { node: candidates[0], candidates };\n return { candidates }; // ambiguous\n}\n\nexport function nodeById(graph: VgGraph, id: string): GraphNode | undefined {\n return graph.nodes.find((n) => n.id === id);\n}\n\nfunction rank(nodes: GraphNode[]): GraphNode[] {\n return [...nodes].sort(\n (a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName),\n );\n}\n\nfunction globToRegExp(glob: string): RegExp {\n const escaped = glob.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*').replace(/\\?/g, '.');\n return new RegExp(`^${escaped}$`, 'i');\n}\n"]}
@@ -0,0 +1,313 @@
1
+ import { createHash } from 'crypto';
2
+
3
+ // src/runtime/identifier-trie.ts
4
+ function createTrieNode() {
5
+ return { children: /* @__PURE__ */ new Map(), terminal: false };
6
+ }
7
+ function trieInsert(root, word) {
8
+ let node = root;
9
+ for (const ch of word) {
10
+ let next = node.children.get(ch);
11
+ if (!next) {
12
+ next = createTrieNode();
13
+ node.children.set(ch, next);
14
+ }
15
+ node = next;
16
+ }
17
+ node.terminal = true;
18
+ }
19
+ function trieHas(root, word) {
20
+ let node = root;
21
+ for (const ch of word) {
22
+ const next = node.children.get(ch);
23
+ if (!next) return false;
24
+ node = next;
25
+ }
26
+ return node.terminal;
27
+ }
28
+ function trieHasPrefix(root, prefix) {
29
+ let node = root;
30
+ for (const ch of prefix) {
31
+ const next = node.children.get(ch);
32
+ if (!next) return false;
33
+ node = next;
34
+ }
35
+ return true;
36
+ }
37
+ function buildIdentifierTrieFromGraph(graph) {
38
+ const root = createTrieNode();
39
+ const seen = /* @__PURE__ */ new Set();
40
+ const add = (s) => {
41
+ const t = (s ?? "").trim();
42
+ if (!t || seen.has(t)) return;
43
+ seen.add(t);
44
+ trieInsert(root, t);
45
+ for (const part of t.split(/[./:#]/)) {
46
+ const p = part.trim();
47
+ if (!p || seen.has(p)) continue;
48
+ seen.add(p);
49
+ trieInsert(root, p);
50
+ }
51
+ };
52
+ for (const n of graph.nodes) {
53
+ add(n.name);
54
+ add(n.qualifiedName);
55
+ add(n.id);
56
+ }
57
+ return root;
58
+ }
59
+ function trieAllowedNextChars(root, prefix) {
60
+ let node = root;
61
+ for (const ch of prefix) {
62
+ const next = node.children.get(ch);
63
+ if (!next) return [];
64
+ node = next;
65
+ }
66
+ return [...node.children.keys()].sort();
67
+ }
68
+ function trieEnumerateWords(root, limit = 4096) {
69
+ const out = [];
70
+ const walk = (n, acc) => {
71
+ if (out.length >= limit) return;
72
+ if (n.terminal && acc.length > 0) out.push(acc);
73
+ for (const [ch, child] of [...n.children.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
74
+ walk(child, acc + ch);
75
+ if (out.length >= limit) return;
76
+ }
77
+ };
78
+ walk(root, "");
79
+ return out;
80
+ }
81
+
82
+ // src/runtime/identifier-mask.ts
83
+ var IDENT_RE = /\b[A-Za-z_][A-Za-z0-9_]{2,}\b/g;
84
+ var STOP = /* @__PURE__ */ new Set([
85
+ "the",
86
+ "and",
87
+ "for",
88
+ "var",
89
+ "let",
90
+ "const",
91
+ "function",
92
+ "class",
93
+ "return",
94
+ "import",
95
+ "export",
96
+ "from",
97
+ "async",
98
+ "await",
99
+ "true",
100
+ "false",
101
+ "null",
102
+ "undefined",
103
+ "this",
104
+ "new",
105
+ "typeof",
106
+ "interface",
107
+ "type",
108
+ "string",
109
+ "number",
110
+ "boolean",
111
+ "void",
112
+ "any",
113
+ "unknown",
114
+ "Promise",
115
+ "Array",
116
+ "Object",
117
+ "Error",
118
+ "console",
119
+ "process",
120
+ "require",
121
+ "module",
122
+ "exports",
123
+ "default",
124
+ "extends",
125
+ "implements",
126
+ "public",
127
+ "private",
128
+ "protected",
129
+ "static",
130
+ "readonly",
131
+ "if",
132
+ "else",
133
+ "while",
134
+ "switch",
135
+ "case",
136
+ "break",
137
+ "continue",
138
+ "try",
139
+ "catch",
140
+ "finally",
141
+ "throw",
142
+ "with",
143
+ "yield",
144
+ "of",
145
+ "in",
146
+ "as",
147
+ "is",
148
+ "get",
149
+ "set"
150
+ ]);
151
+ function extractIdentifiers(text) {
152
+ const out = /* @__PURE__ */ new Set();
153
+ for (const m of text.matchAll(IDENT_RE)) {
154
+ const t = m[0];
155
+ if (STOP.has(t) || STOP.has(t.toLowerCase())) continue;
156
+ out.add(t);
157
+ }
158
+ return [...out].sort();
159
+ }
160
+ function scanIdentifiersAgainstTrie(text, trie) {
161
+ const known = [];
162
+ const unknown = [];
163
+ for (const id of extractIdentifiers(text)) {
164
+ if (trieHas(trie, id) || trieHasPrefix(trie, id)) known.push(id);
165
+ else unknown.push(id);
166
+ }
167
+ return { known, unknown, clean: unknown.length === 0 };
168
+ }
169
+ function maskAllowedNextChars(trie, partialIdent) {
170
+ return trieAllowedNextChars(trie, partialIdent);
171
+ }
172
+ function annotateUnknownIdentifiers(text, trie) {
173
+ const scan = scanIdentifiersAgainstTrie(text, trie);
174
+ if (scan.clean) return { text, unknown: [] };
175
+ const note = `
176
+
177
+ /* vg: unknown identifiers vs graph (not rewritten): ${scan.unknown.slice(0, 12).join(", ")}${scan.unknown.length > 12 ? "\u2026" : ""} */`;
178
+ return { text: text + note, unknown: scan.unknown };
179
+ }
180
+ var KV_CACHE_SCHEMA = "kv-cache/0";
181
+ function contentHash(text) {
182
+ return createHash("sha256").update(text, "utf8").digest("hex");
183
+ }
184
+ function approxTokens(text) {
185
+ return Math.max(1, Math.ceil(text.length / 4));
186
+ }
187
+ function blockMeta(kind, text, now = Date.now()) {
188
+ return {
189
+ hash: contentHash(text),
190
+ kind,
191
+ bytes: Buffer.byteLength(text, "utf8"),
192
+ approxTokens: approxTokens(text),
193
+ createdAt: now
194
+ };
195
+ }
196
+ var KvBlockRegistry = class {
197
+ warm = /* @__PURE__ */ new Map();
198
+ markWarm(meta) {
199
+ this.warm.set(meta.hash, meta);
200
+ }
201
+ isWarm(hash) {
202
+ return this.warm.has(hash);
203
+ }
204
+ get(hash) {
205
+ return this.warm.get(hash);
206
+ }
207
+ clear() {
208
+ this.warm.clear();
209
+ }
210
+ size() {
211
+ return this.warm.size;
212
+ }
213
+ /**
214
+ * Plan assembly for ordered text segments. Hits reuse warm blocks; misses
215
+ * need prefill. After a successful forward pass, call {@link commit} on miss hashes.
216
+ */
217
+ plan(segments, cursor) {
218
+ const order = [];
219
+ const hit = [];
220
+ const miss = [];
221
+ let hitTokens = 0;
222
+ let totalTokens = 0;
223
+ for (const seg of segments) {
224
+ const meta = blockMeta(seg.kind, seg.text);
225
+ order.push(meta.hash);
226
+ totalTokens += meta.approxTokens;
227
+ if (this.isWarm(meta.hash)) {
228
+ hit.push(meta.hash);
229
+ hitTokens += meta.approxTokens;
230
+ } else {
231
+ miss.push({ hash: meta.hash, kind: meta.kind, approxTokens: meta.approxTokens });
232
+ }
233
+ }
234
+ let cursorSkipBlocks = 0;
235
+ let deltaTokens = totalTokens;
236
+ if (cursor) {
237
+ const d = cursor.delta(order, segments);
238
+ cursorSkipBlocks = d.skipBlocks;
239
+ deltaTokens = d.evaluateTokens;
240
+ }
241
+ return {
242
+ schemaVersion: KV_CACHE_SCHEMA,
243
+ hit,
244
+ miss,
245
+ order,
246
+ hitTokens,
247
+ totalTokens,
248
+ cursorSkipBlocks,
249
+ deltaTokens
250
+ };
251
+ }
252
+ /** After prefill, mark miss segments warm. */
253
+ commit(segments) {
254
+ for (const seg of segments) {
255
+ this.markWarm(blockMeta(seg.kind, seg.text));
256
+ }
257
+ }
258
+ };
259
+ var SessionPrefixCursor = class {
260
+ chain = [];
261
+ /** Hashes currently considered evaluated on the sequence. */
262
+ get evaluatedHashes() {
263
+ return this.chain;
264
+ }
265
+ /**
266
+ * Compute how many leading blocks match the previous chain and how many
267
+ * approx tokens still need evaluate (from the fork point).
268
+ */
269
+ delta(order, segments) {
270
+ let skip = 0;
271
+ while (skip < order.length && skip < this.chain.length && order[skip] === this.chain[skip]) {
272
+ skip++;
273
+ }
274
+ let evaluateTokens = 0;
275
+ const parts = [];
276
+ for (let i = skip; i < segments.length; i++) {
277
+ const meta = blockMeta(segments[i].kind, segments[i].text);
278
+ evaluateTokens += meta.approxTokens;
279
+ parts.push(segments[i].text);
280
+ }
281
+ return { skipBlocks: skip, evaluateTokens, evaluateText: parts.join("\n") };
282
+ }
283
+ /** After successful evaluate of full ordered hashes, advance the cursor. */
284
+ commit(order) {
285
+ this.chain = [...order];
286
+ }
287
+ /** Reset after sequence dispose / model reload. */
288
+ reset() {
289
+ this.chain = [];
290
+ }
291
+ };
292
+ function longestWarmPrefix(registry, segments) {
293
+ let count = 0;
294
+ let tokens = 0;
295
+ const hashes = [];
296
+ const parts = [];
297
+ for (const seg of segments) {
298
+ const meta = blockMeta(seg.kind, seg.text);
299
+ if (!registry.isWarm(meta.hash)) break;
300
+ count++;
301
+ tokens += meta.approxTokens;
302
+ hashes.push(meta.hash);
303
+ parts.push(seg.text);
304
+ }
305
+ return { count, tokens, text: parts.join("\n"), hashes };
306
+ }
307
+ function graphDraftCandidates(knownVerbatim, max = 8) {
308
+ return knownVerbatim.map((s) => s.trim()).filter((s) => s.length >= 8 && s.length <= 400).slice(0, max);
309
+ }
310
+
311
+ export { KvBlockRegistry, SessionPrefixCursor, annotateUnknownIdentifiers, buildIdentifierTrieFromGraph, contentHash, extractIdentifiers, graphDraftCandidates, longestWarmPrefix, maskAllowedNextChars, scanIdentifiersAgainstTrie, trieEnumerateWords, trieHas, trieHasPrefix };
312
+ //# sourceMappingURL=chunk-JIBOJTGS.js.map
313
+ //# sourceMappingURL=chunk-JIBOJTGS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/identifier-trie.ts","../src/runtime/identifier-mask.ts","../src/runtime/kv-cache.ts"],"names":[],"mappings":"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","file":"chunk-JIBOJTGS.js","sourcesContent":["/**\n * Identifier trie for future logit masking (Approach B sampler hooks).\n *\n * Built from ActiveGraph symbol short/qualified names so constrained generation\n * can refuse identifiers that do not exist in the repo. Pure data structure —\n * no model binding required to unit-test.\n */\n\nexport interface TrieNode {\n children: Map<string, TrieNode>;\n terminal: boolean;\n}\n\nexport function createTrieNode(): TrieNode {\n return { children: new Map(), terminal: false };\n}\n\nexport function trieInsert(root: TrieNode, word: string): void {\n let node = root;\n for (const ch of word) {\n let next = node.children.get(ch);\n if (!next) {\n next = createTrieNode();\n node.children.set(ch, next);\n }\n node = next;\n }\n node.terminal = true;\n}\n\nexport function trieHas(root: TrieNode, word: string): boolean {\n let node = root;\n for (const ch of word) {\n const next = node.children.get(ch);\n if (!next) return false;\n node = next;\n }\n return node.terminal;\n}\n\nexport function trieHasPrefix(root: TrieNode, prefix: string): boolean {\n let node = root;\n for (const ch of prefix) {\n const next = node.children.get(ch);\n if (!next) return false;\n node = next;\n }\n return true;\n}\n\n/** Completions that extend `prefix` (capped). */\nexport function trieComplete(root: TrieNode, prefix: string, limit = 32): string[] {\n let node = root;\n for (const ch of prefix) {\n const next = node.children.get(ch);\n if (!next) return [];\n node = next;\n }\n const out: string[] = [];\n const walk = (n: TrieNode, acc: string): void => {\n if (out.length >= limit) return;\n if (n.terminal) out.push(acc);\n for (const [ch, child] of [...n.children.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n walk(child, acc + ch);\n if (out.length >= limit) return;\n }\n };\n walk(node, prefix);\n return out;\n}\n\nexport interface GraphLikeForTrie {\n nodes: Array<{ name?: string; qualifiedName?: string; id?: string }>;\n}\n\n/**\n * Build a trie of symbol identifiers from a graph. Includes short names and\n * the last segment of qualified names (e.g. `Foo` from `pkg.Foo`).\n */\nexport function buildIdentifierTrieFromGraph(graph: GraphLikeForTrie): TrieNode {\n const root = createTrieNode();\n const seen = new Set<string>();\n const add = (s: string | undefined): void => {\n const t = (s ?? '').trim();\n if (!t || seen.has(t)) return;\n seen.add(t);\n trieInsert(root, t);\n // Path segments for dotted / slash-qualified names (e.g. pkg.util.Foo → util, Foo).\n for (const part of t.split(/[./:#]/)) {\n const p = part.trim();\n if (!p || seen.has(p)) continue;\n seen.add(p);\n trieInsert(root, p);\n }\n };\n for (const n of graph.nodes) {\n add(n.name);\n add(n.qualifiedName);\n add(n.id);\n }\n return root;\n}\n\n/** Characters allowed to continue after `prefix` under the trie (for logit mask). */\nexport function trieAllowedNextChars(root: TrieNode, prefix: string): string[] {\n let node = root;\n for (const ch of prefix) {\n const next = node.children.get(ch);\n if (!next) return [];\n node = next;\n }\n return [...node.children.keys()].sort();\n}\n\n/**\n * Enumerate terminal words in the trie (capped). Used to positively bias known\n * graph identifiers when building a TokenBias without scanning the full vocab.\n */\nexport function trieEnumerateWords(root: TrieNode, limit = 4096): string[] {\n const out: string[] = [];\n const walk = (n: TrieNode, acc: string): void => {\n if (out.length >= limit) return;\n if (n.terminal && acc.length > 0) out.push(acc);\n for (const [ch, child] of [...n.children.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {\n walk(child, acc + ch);\n if (out.length >= limit) return;\n }\n };\n walk(root, '');\n return out;\n}\n","/**\n * Identifier masking helpers for Approach B sampler integration.\n *\n * Full logit masking needs the llama.cpp binding's token callback. Until that\n * hook is universal across binding versions, we:\n * 1. Expose allowed-next-char sets from the trie (for native mask hooks)\n * 2. Post-validate free-text model output for repo identifiers\n * 3. Optionally rewrite / flag unknown identifiers in code-like spans\n */\n\nimport type { TrieNode } from './identifier-trie.js';\nimport { trieAllowedNextChars, trieHas, trieHasPrefix } from './identifier-trie.js';\n\n/** JS/TS-ish identifier token (conservative). */\nconst IDENT_RE = /\\b[A-Za-z_][A-Za-z0-9_]{2,}\\b/g;\n\n/** Tokens we never treat as \"must exist in the graph\". */\nconst STOP = new Set([\n 'the',\n 'and',\n 'for',\n 'var',\n 'let',\n 'const',\n 'function',\n 'class',\n 'return',\n 'import',\n 'export',\n 'from',\n 'async',\n 'await',\n 'true',\n 'false',\n 'null',\n 'undefined',\n 'this',\n 'new',\n 'typeof',\n 'interface',\n 'type',\n 'string',\n 'number',\n 'boolean',\n 'void',\n 'any',\n 'unknown',\n 'Promise',\n 'Array',\n 'Object',\n 'Error',\n 'console',\n 'process',\n 'require',\n 'module',\n 'exports',\n 'default',\n 'extends',\n 'implements',\n 'public',\n 'private',\n 'protected',\n 'static',\n 'readonly',\n 'if',\n 'else',\n 'while',\n 'switch',\n 'case',\n 'break',\n 'continue',\n 'try',\n 'catch',\n 'finally',\n 'throw',\n 'with',\n 'yield',\n 'of',\n 'in',\n 'as',\n 'is',\n 'get',\n 'set',\n]);\n\nexport interface IdentifierScanResult {\n /** Identifiers that appear in text and exist in the trie. */\n known: string[];\n /** Identifiers that appear in text but are absent from the trie. */\n unknown: string[];\n /** True when every scanned identifier is known (or stopword). */\n clean: boolean;\n}\n\n/** Extract candidate identifiers from model text. */\nexport function extractIdentifiers(text: string): string[] {\n const out = new Set<string>();\n for (const m of text.matchAll(IDENT_RE)) {\n const t = m[0];\n if (STOP.has(t) || STOP.has(t.toLowerCase())) continue;\n out.add(t);\n }\n return [...out].sort();\n}\n\nexport function scanIdentifiersAgainstTrie(text: string, trie: TrieNode): IdentifierScanResult {\n const known: string[] = [];\n const unknown: string[] = [];\n for (const id of extractIdentifiers(text)) {\n if (trieHas(trie, id) || trieHasPrefix(trie, id)) known.push(id);\n else unknown.push(id);\n }\n return { known, unknown, clean: unknown.length === 0 };\n}\n\n/**\n * Allowed next characters for a partial identifier under the trie — the hook\n * surface for real logit masks when the binding supports custom samplers.\n */\nexport function maskAllowedNextChars(trie: TrieNode, partialIdent: string): string[] {\n return trieAllowedNextChars(trie, partialIdent);\n}\n\n/**\n * Annotate model output when unknown identifiers appear (non-destructive).\n * Returns original text when clean; otherwise appends a short warning block the\n * agent/tools can surface without rewriting the patch body blindly.\n */\nexport function annotateUnknownIdentifiers(text: string, trie: TrieNode): { text: string; unknown: string[] } {\n const scan = scanIdentifiersAgainstTrie(text, trie);\n if (scan.clean) return { text, unknown: [] };\n const note = `\\n\\n/* vg: unknown identifiers vs graph (not rewritten): ${scan.unknown.slice(0, 12).join(', ')}${scan.unknown.length > 12 ? '…' : ''} */`;\n return { text: text + note, unknown: scan.unknown };\n}\n","/**\n * Block-level KV / prompt prefix cache keyed by content hash (Approach B).\n *\n * Pure planning layer + multi-turn prefix cursor (P1/P2). The warm host uses\n * {@link longestWarmPrefix} / {@link SessionPrefixCursor} and may call the\n * binding's `evaluateWithoutGeneratingNewTokens` so RoPE state for warm\n * system/capsule blocks is not rebuilt every turn.\n *\n * schemaVersion: kv-cache/0\n */\n\nimport { createHash } from 'node:crypto';\n\nexport const KV_CACHE_SCHEMA = 'kv-cache/0' as const;\n\nexport interface KvBlockMeta {\n /** Content hash (sha256 hex, truncated in keys for path safety). */\n hash: string;\n /** Human label (system, capsule, tools, …). */\n kind: string;\n /** UTF-8 byte length of the source text. */\n bytes: number;\n /** Approx token count (chars/4 heuristic when unknown). */\n approxTokens: number;\n /** When this block entered the registry. */\n createdAt: number;\n}\n\nexport interface KvAssemblyPlan {\n schemaVersion: typeof KV_CACHE_SCHEMA;\n /** Blocks to reuse from cache (hashes). */\n hit: string[];\n /** Blocks that must be prefilled (hash + kind). */\n miss: Array<{ hash: string; kind: string; approxTokens: number }>;\n /** Ordered sequence of block hashes for the full prompt. */\n order: string[];\n /** Estimated tokens already “warm” vs total. */\n hitTokens: number;\n totalTokens: number;\n /**\n * P2: tokens that must be re-evaluated because the multi-turn cursor\n * diverged (subset of miss + trailing hits after fork).\n */\n deltaTokens?: number;\n /** How many leading blocks the session cursor already has evaluated. */\n cursorSkipBlocks?: number;\n}\n\nexport function contentHash(text: string): string {\n return createHash('sha256').update(text, 'utf8').digest('hex');\n}\n\nexport function approxTokens(text: string): number {\n return Math.max(1, Math.ceil(text.length / 4));\n}\n\nexport function blockMeta(kind: string, text: string, now = Date.now()): KvBlockMeta {\n return {\n hash: contentHash(text),\n kind,\n bytes: Buffer.byteLength(text, 'utf8'),\n approxTokens: approxTokens(text),\n createdAt: now,\n };\n}\n\n/** In-memory registry of which content hashes are considered warm. */\nexport class KvBlockRegistry {\n private readonly warm = new Map<string, KvBlockMeta>();\n\n markWarm(meta: KvBlockMeta): void {\n this.warm.set(meta.hash, meta);\n }\n\n isWarm(hash: string): boolean {\n return this.warm.has(hash);\n }\n\n get(hash: string): KvBlockMeta | undefined {\n return this.warm.get(hash);\n }\n\n clear(): void {\n this.warm.clear();\n }\n\n size(): number {\n return this.warm.size;\n }\n\n /**\n * Plan assembly for ordered text segments. Hits reuse warm blocks; misses\n * need prefill. After a successful forward pass, call {@link commit} on miss hashes.\n */\n plan(segments: Array<{ kind: string; text: string }>, cursor?: SessionPrefixCursor): KvAssemblyPlan {\n const order: string[] = [];\n const hit: string[] = [];\n const miss: KvAssemblyPlan['miss'] = [];\n let hitTokens = 0;\n let totalTokens = 0;\n for (const seg of segments) {\n const meta = blockMeta(seg.kind, seg.text);\n order.push(meta.hash);\n totalTokens += meta.approxTokens;\n if (this.isWarm(meta.hash)) {\n hit.push(meta.hash);\n hitTokens += meta.approxTokens;\n } else {\n miss.push({ hash: meta.hash, kind: meta.kind, approxTokens: meta.approxTokens });\n }\n }\n let cursorSkipBlocks = 0;\n let deltaTokens = totalTokens;\n if (cursor) {\n const d = cursor.delta(order, segments);\n cursorSkipBlocks = d.skipBlocks;\n deltaTokens = d.evaluateTokens;\n }\n return {\n schemaVersion: KV_CACHE_SCHEMA,\n hit,\n miss,\n order,\n hitTokens,\n totalTokens,\n cursorSkipBlocks,\n deltaTokens,\n };\n }\n\n /** After prefill, mark miss segments warm. */\n commit(segments: Array<{ kind: string; text: string }>): void {\n for (const seg of segments) {\n this.markWarm(blockMeta(seg.kind, seg.text));\n }\n }\n}\n\n/**\n * Multi-turn cursor: remembers the hash chain last evaluated on the sequence\n * so we only re-evaluate from the first divergence (P2 RoPE-friendly delta).\n */\nexport class SessionPrefixCursor {\n private chain: string[] = [];\n\n /** Hashes currently considered evaluated on the sequence. */\n get evaluatedHashes(): readonly string[] {\n return this.chain;\n }\n\n /**\n * Compute how many leading blocks match the previous chain and how many\n * approx tokens still need evaluate (from the fork point).\n */\n delta(\n order: string[],\n segments: Array<{ kind: string; text: string }>,\n ): { skipBlocks: number; evaluateTokens: number; evaluateText: string } {\n let skip = 0;\n while (skip < order.length && skip < this.chain.length && order[skip] === this.chain[skip]) {\n skip++;\n }\n let evaluateTokens = 0;\n const parts: string[] = [];\n for (let i = skip; i < segments.length; i++) {\n const meta = blockMeta(segments[i].kind, segments[i].text);\n evaluateTokens += meta.approxTokens;\n parts.push(segments[i].text);\n }\n return { skipBlocks: skip, evaluateTokens, evaluateText: parts.join('\\n') };\n }\n\n /** After successful evaluate of full ordered hashes, advance the cursor. */\n commit(order: string[]): void {\n this.chain = [...order];\n }\n\n /** Reset after sequence dispose / model reload. */\n reset(): void {\n this.chain = [];\n }\n}\n\n/**\n * Longest leading run of warm segments (stable system/capsule prefix).\n * Host can skip re-prefilling these when the sequence API allows evaluate-only.\n */\nexport function longestWarmPrefix(\n registry: KvBlockRegistry,\n segments: Array<{ kind: string; text: string }>,\n): {\n count: number;\n tokens: number;\n text: string;\n hashes: string[];\n} {\n let count = 0;\n let tokens = 0;\n const hashes: string[] = [];\n const parts: string[] = [];\n for (const seg of segments) {\n const meta = blockMeta(seg.kind, seg.text);\n if (!registry.isWarm(meta.hash)) break;\n count++;\n tokens += meta.approxTokens;\n hashes.push(meta.hash);\n parts.push(seg.text);\n }\n return { count, tokens, text: parts.join('\\n'), hashes };\n}\n\n/**\n * Speculative draft tokens for quotational spans the graph already knows\n * verbatim (signatures / imports). The big model verifies; high acceptance\n * expected on code. Pure: returns candidate draft strings, does not call a model.\n */\nexport function graphDraftCandidates(\n knownVerbatim: string[],\n max = 8,\n): string[] {\n return knownVerbatim\n .map((s) => s.trim())\n .filter((s) => s.length >= 8 && s.length <= 400)\n .slice(0, max);\n}\n"]}
@@ -0,0 +1,88 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ // src/engine/serialize.ts
5
+ function serializeGraph(graph) {
6
+ return `${stableStringify(graph, 2)}
7
+ `;
8
+ }
9
+ function stableStringify(value, indent = 2) {
10
+ return JSON.stringify(sortKeys(value), null, indent);
11
+ }
12
+ function sortKeys(value) {
13
+ if (Array.isArray(value)) return value.map(sortKeys);
14
+ if (value && typeof value === "object") {
15
+ const input = value;
16
+ const out = {};
17
+ for (const key of Object.keys(input).sort()) {
18
+ const v = input[key];
19
+ if (v === void 0) continue;
20
+ out[key] = sortKeys(v);
21
+ }
22
+ return out;
23
+ }
24
+ return value;
25
+ }
26
+ function parseGraph(json) {
27
+ return JSON.parse(json);
28
+ }
29
+ var CACHE_VERSION = "vg-parse-cache/4";
30
+ function cacheDir(root) {
31
+ return path.join(root, ".vibgrate", "cache");
32
+ }
33
+ function cachePath(root) {
34
+ return path.join(cacheDir(root), "parse-cache.json");
35
+ }
36
+ function loadCache(root, opts) {
37
+ const file = cachePath(root);
38
+ let data = {
39
+ version: CACHE_VERSION,
40
+ toolVersion: opts.toolVersion,
41
+ grammars: opts.grammars,
42
+ entries: {}
43
+ };
44
+ if (!opts.disabled && fs.existsSync(file)) {
45
+ try {
46
+ const loaded = JSON.parse(fs.readFileSync(file, "utf8"));
47
+ if ((loaded.version === CACHE_VERSION || loaded.version === "vg-parse-cache/3") && loaded.toolVersion === opts.toolVersion && loaded.grammars === opts.grammars && loaded.entries) {
48
+ data = { ...loaded, version: CACHE_VERSION };
49
+ }
50
+ } catch {
51
+ }
52
+ }
53
+ return {
54
+ get(rel, hash) {
55
+ const entry = data.entries[rel];
56
+ return entry && entry.hash === hash ? entry.parse : void 0;
57
+ },
58
+ getByStat(rel, mtimeMs, size) {
59
+ const entry = data.entries[rel];
60
+ if (!entry) return void 0;
61
+ if (entry.mtimeMs === mtimeMs && entry.size === size && entry.parse) {
62
+ return { parse: entry.parse, hash: entry.hash };
63
+ }
64
+ return void 0;
65
+ },
66
+ set(rel, parse, stat) {
67
+ data.entries[rel] = {
68
+ hash: parse.hash,
69
+ parse,
70
+ mtimeMs: stat?.mtimeMs,
71
+ size: stat?.size
72
+ };
73
+ },
74
+ prune(currentRels) {
75
+ for (const rel of Object.keys(data.entries)) {
76
+ if (!currentRels.has(rel)) delete data.entries[rel];
77
+ }
78
+ },
79
+ save() {
80
+ fs.mkdirSync(cacheDir(root), { recursive: true });
81
+ fs.writeFileSync(file, stableStringify(data, 0));
82
+ }
83
+ };
84
+ }
85
+
86
+ export { cacheDir, loadCache, parseGraph, serializeGraph, stableStringify };
87
+ //# sourceMappingURL=chunk-K3MZIVZW.js.map
88
+ //# sourceMappingURL=chunk-K3MZIVZW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/serialize.ts","../src/engine/cache.ts"],"names":[],"mappings":"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","file":"chunk-K3MZIVZW.js","sourcesContent":["import type { VgGraph } from '../schema.js';\n\n/**\n * Deterministic serialization of `graph.json`.\n *\n * Object keys are sorted recursively and arrays are emitted in the (already\n * stable) order the engine produced them, so two runs over identical content\n * yield byte-identical output — the determinism contract (VG-CLI-SPEC §1.3).\n * Pretty-printed (2-space) and newline-terminated so the committed artifact is\n * human-diffable and plays well with the union merge driver.\n */\nexport function serializeGraph(graph: VgGraph): string {\n return `${stableStringify(graph, 2)}\\n`;\n}\n\nexport function stableStringify(value: unknown, indent = 2): string {\n return JSON.stringify(sortKeys(value), null, indent);\n}\n\nfunction sortKeys(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortKeys);\n if (value && typeof value === 'object') {\n const input = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(input).sort()) {\n const v = input[key];\n if (v === undefined) continue; // omit undefined for stable output\n out[key] = sortKeys(v);\n }\n return out;\n }\n return value;\n}\n\nexport function parseGraph(json: string): VgGraph {\n return JSON.parse(json) as VgGraph;\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { stableStringify } from './serialize.js';\nimport type { FileParse } from './types.js';\n\n/**\n * Incremental parse cache. Maps a file's content hash to its parsed\n * symbol/edge tables, so a rebuild re-parses only files whose content actually\n * changed (VG-DEVELOPMENT-PLAN Phase 0.4). Lives under `.vibgrate/cache/` and is\n * gitignored — never part of the committed artifact.\n *\n * The cache is a pure performance optimisation: a reused FileParse is identical\n * to a freshly-parsed one (parsing is pure over content), so the graph is\n * byte-identical whether or not the cache was warm. `--no-cache` / `vg verify`\n * prove this.\n */\n\n// Bumped to /4: optional mtime+size fingerprint for stat-skip fast path.\nconst CACHE_VERSION = 'vg-parse-cache/4';\n\ninterface CacheEntry {\n hash: string;\n mtimeMs?: number;\n size?: number;\n parse: FileParse;\n}\n\ninterface CacheFile {\n version: string;\n toolVersion: string;\n grammars: string;\n entries: Record<string, CacheEntry>;\n}\n\nexport interface ParseCache {\n get(rel: string, hash: string): FileParse | undefined;\n /** Fast path: mtime+size match → reuse parse without re-reading bytes. */\n getByStat(rel: string, mtimeMs: number, size: number): { parse: FileParse; hash: string } | undefined;\n set(rel: string, parse: FileParse, stat?: { mtimeMs: number; size: number }): void;\n /** Drop entries for files no longer present. */\n prune(currentRels: Set<string>): void;\n save(): void;\n}\n\nexport function cacheDir(root: string): string {\n return path.join(root, '.vibgrate', 'cache');\n}\n\nfunction cachePath(root: string): string {\n return path.join(cacheDir(root), 'parse-cache.json');\n}\n\nexport function loadCache(\n root: string,\n opts: { toolVersion: string; grammars: string; disabled?: boolean },\n): ParseCache {\n const file = cachePath(root);\n let data: CacheFile = {\n version: CACHE_VERSION,\n toolVersion: opts.toolVersion,\n grammars: opts.grammars,\n entries: {},\n };\n\n if (!opts.disabled && fs.existsSync(file)) {\n try {\n const loaded = JSON.parse(fs.readFileSync(file, 'utf8')) as CacheFile;\n // Accept v3 → v4 (stat fields optional).\n if (\n (loaded.version === CACHE_VERSION || loaded.version === 'vg-parse-cache/3') &&\n loaded.toolVersion === opts.toolVersion &&\n loaded.grammars === opts.grammars &&\n loaded.entries\n ) {\n data = { ...loaded, version: CACHE_VERSION };\n }\n } catch {\n /* corrupt cache — start fresh */\n }\n }\n\n return {\n get(rel, hash) {\n const entry = data.entries[rel];\n return entry && entry.hash === hash ? entry.parse : undefined;\n },\n getByStat(rel, mtimeMs, size) {\n const entry = data.entries[rel];\n if (!entry) return undefined;\n if (entry.mtimeMs === mtimeMs && entry.size === size && entry.parse) {\n return { parse: entry.parse, hash: entry.hash };\n }\n return undefined;\n },\n set(rel, parse, stat) {\n data.entries[rel] = {\n hash: parse.hash,\n parse,\n mtimeMs: stat?.mtimeMs,\n size: stat?.size,\n };\n },\n prune(currentRels) {\n for (const rel of Object.keys(data.entries)) {\n if (!currentRels.has(rel)) delete data.entries[rel];\n }\n },\n save() {\n fs.mkdirSync(cacheDir(root), { recursive: true });\n fs.writeFileSync(file, stableStringify(data, 0));\n },\n };\n}\n"]}