@vibgrate/cli 2026.721.2 → 2026.722.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +185 -0
- package/README.md +2 -1
- package/dist/baseline-J44M7MWP.js +7 -0
- package/dist/{baseline-KK7ZLRZB.js.map → baseline-J44M7MWP.js.map} +1 -1
- package/dist/chunk-2EVQKZTO.js +696 -0
- package/dist/chunk-2EVQKZTO.js.map +1 -0
- package/dist/chunk-6CXTPC74.js +234 -0
- package/dist/chunk-6CXTPC74.js.map +1 -0
- package/dist/chunk-CRAMOEBE.js +675 -0
- package/dist/chunk-CRAMOEBE.js.map +1 -0
- package/dist/chunk-CS37OBE3.js +861 -0
- package/dist/chunk-CS37OBE3.js.map +1 -0
- package/dist/chunk-CT5BS56U.js +23 -0
- package/dist/chunk-CT5BS56U.js.map +1 -0
- package/dist/{chunk-MUMBLIDO.js → chunk-EXQV26MF.js} +4 -3
- package/dist/chunk-EXQV26MF.js.map +1 -0
- package/dist/chunk-GGJZA3Q6.js +961 -0
- package/dist/chunk-GGJZA3Q6.js.map +1 -0
- package/dist/chunk-JBXNQCGE.js +484 -0
- package/dist/chunk-JBXNQCGE.js.map +1 -0
- package/dist/chunk-JFGYT6BI.js +32 -0
- package/dist/chunk-JFGYT6BI.js.map +1 -0
- package/dist/{chunk-NHLSAZ6N.js → chunk-JSNHZCIV.js} +42 -71
- package/dist/chunk-JSNHZCIV.js.map +1 -0
- package/dist/chunk-JYS4OBN2.js +148 -0
- package/dist/chunk-JYS4OBN2.js.map +1 -0
- package/dist/chunk-K3SLGULW.js +50 -0
- package/dist/chunk-K3SLGULW.js.map +1 -0
- package/dist/chunk-LEPTUB4H.js +108 -0
- package/dist/chunk-LEPTUB4H.js.map +1 -0
- package/dist/{chunk-JWBS5GS6.js → chunk-PY3DNX5H.js} +94 -34
- package/dist/chunk-PY3DNX5H.js.map +1 -0
- package/dist/{chunk-3DPZQS2Q.js → chunk-VXT6LUGP.js} +356 -2532
- package/dist/chunk-VXT6LUGP.js.map +1 -0
- package/dist/chunk-WNIIKCNF.js +972 -0
- package/dist/chunk-WNIIKCNF.js.map +1 -0
- package/dist/chunk-XKXKWYJF.js +417 -0
- package/dist/chunk-XKXKWYJF.js.map +1 -0
- package/dist/cli.js +2479 -1234
- package/dist/cli.js.map +1 -1
- package/dist/fs-KCABDURV.js +3 -0
- package/dist/fs-KCABDURV.js.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/interactive-736PBC7J.js +820 -0
- package/dist/interactive-736PBC7J.js.map +1 -0
- package/dist/mcp-tools-I6PME3AV.js +3 -0
- package/dist/mcp-tools-I6PME3AV.js.map +1 -0
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +2 -1
- package/dist/parse-worker.js.map +1 -1
- package/dist/session-POJUDFPH.js +6 -0
- package/dist/session-POJUDFPH.js.map +1 -0
- package/dist/session-store-W5RZZHA3.js +3 -0
- package/dist/session-store-W5RZZHA3.js.map +1 -0
- package/dist/stream-json-Q2JGWPHB.js +65 -0
- package/dist/stream-json-Q2JGWPHB.js.map +1 -0
- package/dist/{types-BgNa-FZQ.d.ts → types-Jl6RJ175.d.ts} +8 -0
- package/dist/ui-HOVOPWMX.js +4 -0
- package/dist/ui-HOVOPWMX.js.map +1 -0
- package/package.json +3 -2
- package/dist/baseline-KK7ZLRZB.js +0 -6
- package/dist/chunk-3DPZQS2Q.js.map +0 -1
- package/dist/chunk-JWBS5GS6.js.map +0 -1
- package/dist/chunk-MUMBLIDO.js.map +0 -1
- package/dist/chunk-NHLSAZ6N.js.map +0 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { c } from './chunk-CT5BS56U.js';
|
|
2
|
+
import * as readline from 'readline';
|
|
3
|
+
|
|
4
|
+
var PromptCancelled = class extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("cancelled");
|
|
7
|
+
this.name = "PromptCancelled";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var teal = (s) => c.hex("#3FB0A4")(s);
|
|
11
|
+
var mint = (s) => c.hex("#4FE3C1")(s);
|
|
12
|
+
var err = (s) => {
|
|
13
|
+
process.stderr.write(s);
|
|
14
|
+
};
|
|
15
|
+
var TtyPrompter = class {
|
|
16
|
+
intro(message) {
|
|
17
|
+
err(`
|
|
18
|
+
${mint("\u25C6")} ${c.bold(message)}
|
|
19
|
+
`);
|
|
20
|
+
}
|
|
21
|
+
outro(message) {
|
|
22
|
+
err(`${mint("\u25C7")} ${message}
|
|
23
|
+
|
|
24
|
+
`);
|
|
25
|
+
}
|
|
26
|
+
note(message) {
|
|
27
|
+
err(`${c.dim("\u2502")} ${message}
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
async select(message, choices) {
|
|
31
|
+
if (choices.length === 0) throw new Error("select called with no choices");
|
|
32
|
+
err(`${teal("?")} ${c.bold(message)} ${c.dim("(\u2191/\u2193, Enter)")}
|
|
33
|
+
`);
|
|
34
|
+
const stdin = process.stdin;
|
|
35
|
+
const canRaw = typeof stdin.setRawMode === "function" && stdin.isTTY;
|
|
36
|
+
if (!canRaw) return this.numberedSelect(message, choices);
|
|
37
|
+
readline.emitKeypressEvents(stdin);
|
|
38
|
+
stdin.setRawMode(true);
|
|
39
|
+
stdin.resume();
|
|
40
|
+
let index = 0;
|
|
41
|
+
const render = (first = false) => {
|
|
42
|
+
if (!first) err(`\x1B[${choices.length}A`);
|
|
43
|
+
for (let i = 0; i < choices.length; i++) {
|
|
44
|
+
const active = i === index;
|
|
45
|
+
const pointer = active ? mint("\u276F") : " ";
|
|
46
|
+
const label = active ? c.bold(choices[i].label) : choices[i].label;
|
|
47
|
+
const hint = choices[i].hint ? c.dim(` ${choices[i].hint}`) : "";
|
|
48
|
+
err(`\x1B[2K${pointer} ${label}${hint}
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
render(true);
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const onKey = (_str, key) => {
|
|
55
|
+
if (!key) return;
|
|
56
|
+
if (key.name === "up" || key.name === "k" && !key.ctrl) {
|
|
57
|
+
index = (index - 1 + choices.length) % choices.length;
|
|
58
|
+
render();
|
|
59
|
+
} else if (key.name === "down" || key.name === "j" && !key.ctrl) {
|
|
60
|
+
index = (index + 1) % choices.length;
|
|
61
|
+
render();
|
|
62
|
+
} else if (key.name === "return" || key.name === "enter") {
|
|
63
|
+
cleanup();
|
|
64
|
+
err(`${teal("\u2714")} ${c.dim(choices[index].label)}
|
|
65
|
+
`);
|
|
66
|
+
resolve(choices[index].value);
|
|
67
|
+
} else if (key.name === "escape" || key.ctrl && key.name === "c") {
|
|
68
|
+
cleanup();
|
|
69
|
+
reject(new PromptCancelled());
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const cleanup = () => {
|
|
73
|
+
stdin.removeListener("keypress", onKey);
|
|
74
|
+
if (typeof stdin.setRawMode === "function") stdin.setRawMode(false);
|
|
75
|
+
stdin.pause();
|
|
76
|
+
};
|
|
77
|
+
stdin.on("keypress", onKey);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Numbered fallback when raw mode isn't available (e.g. a dumb terminal). */
|
|
81
|
+
async numberedSelect(message, choices) {
|
|
82
|
+
for (let i = 0; i < choices.length; i++) {
|
|
83
|
+
err(` ${c.bold(String(i + 1))}. ${choices[i].label}${choices[i].hint ? c.dim(` ${choices[i].hint}`) : ""}
|
|
84
|
+
`);
|
|
85
|
+
}
|
|
86
|
+
for (; ; ) {
|
|
87
|
+
const answer = await this.input(`${message} \u2014 number`);
|
|
88
|
+
const n = Number(answer);
|
|
89
|
+
if (Number.isInteger(n) && n >= 1 && n <= choices.length) return choices[n - 1].value;
|
|
90
|
+
this.note(c.yellow(`enter 1\u2013${choices.length}`));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
input(message, opts = {}) {
|
|
94
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
95
|
+
const suffix = opts.default ? c.dim(` (${opts.default})`) : opts.placeholder ? c.dim(` (${opts.placeholder})`) : "";
|
|
96
|
+
return new Promise((resolve) => {
|
|
97
|
+
rl.question(`${teal("?")} ${c.bold(message)}${suffix} `, (answer) => {
|
|
98
|
+
rl.close();
|
|
99
|
+
const trimmed = answer.trim();
|
|
100
|
+
resolve(trimmed || opts.default || "");
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async confirm(message, def = false) {
|
|
105
|
+
const answer = await this.input(`${message} ${c.dim(def ? "[Y/n]" : "[y/N]")}`);
|
|
106
|
+
if (!answer) return def;
|
|
107
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
108
|
+
}
|
|
109
|
+
spinner(message) {
|
|
110
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
111
|
+
let i = 0;
|
|
112
|
+
let current = message;
|
|
113
|
+
const active = process.stderr.isTTY;
|
|
114
|
+
let timer;
|
|
115
|
+
if (active) {
|
|
116
|
+
timer = setInterval(() => {
|
|
117
|
+
err(`\x1B[2K\r${teal(frames[i = (i + 1) % frames.length])} ${current}`);
|
|
118
|
+
}, 80);
|
|
119
|
+
timer.unref?.();
|
|
120
|
+
} else {
|
|
121
|
+
err(`${current}
|
|
122
|
+
`);
|
|
123
|
+
}
|
|
124
|
+
const clear = () => {
|
|
125
|
+
if (timer) clearInterval(timer);
|
|
126
|
+
if (active) err(`\x1B[2K\r`);
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
update(m) {
|
|
130
|
+
current = m;
|
|
131
|
+
},
|
|
132
|
+
stop(finalMessage) {
|
|
133
|
+
clear();
|
|
134
|
+
if (finalMessage) err(`${teal("\u2714")} ${finalMessage}
|
|
135
|
+
`);
|
|
136
|
+
},
|
|
137
|
+
fail(m) {
|
|
138
|
+
clear();
|
|
139
|
+
err(`${c.red("\u2717")} ${m}
|
|
140
|
+
`);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export { PromptCancelled, TtyPrompter };
|
|
147
|
+
//# sourceMappingURL=chunk-JYS4OBN2.js.map
|
|
148
|
+
//# sourceMappingURL=chunk-JYS4OBN2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/code/ui.ts"],"names":[],"mappings":";;;AAmBO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EACzC,WAAA,GAAc;AACZ,IAAA,KAAA,CAAM,WAAW,CAAA;AACjB,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AAAA,EACd;AACF;AAyBA,IAAM,OAAO,CAAC,CAAA,KAAsB,EAAE,GAAA,CAAI,SAAS,EAAE,CAAC,CAAA;AACtD,IAAM,OAAO,CAAC,CAAA,KAAsB,EAAE,GAAA,CAAI,SAAS,EAAE,CAAC,CAAA;AACtD,IAAM,GAAA,GAAM,CAAC,CAAA,KAAoB;AAC/B,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAC,CAAA;AACxB,CAAA;AAGO,IAAM,cAAN,MAAsC;AAAA,EAC3C,MAAM,OAAA,EAAuB;AAC3B,IAAA,GAAA,CAAI;AAAA,EAAK,KAAK,QAAG,CAAC,IAAI,CAAA,CAAE,IAAA,CAAK,OAAO,CAAC;AAAA,CAAI,CAAA;AAAA,EAC3C;AAAA,EACA,MAAM,OAAA,EAAuB;AAC3B,IAAA,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,QAAG,CAAC,IAAI,OAAO;;AAAA,CAAM,CAAA;AAAA,EACnC;AAAA,EACA,KAAK,OAAA,EAAuB;AAC1B,IAAA,GAAA,CAAI,GAAG,CAAA,CAAE,GAAA,CAAI,QAAG,CAAC,IAAI,OAAO;AAAA,CAAI,CAAA;AAAA,EAClC;AAAA,EAEA,MAAM,MAAA,CAAU,OAAA,EAAiB,OAAA,EAAwC;AACvE,IAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,+BAA+B,CAAA;AACzE,IAAA,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,OAAO,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,GAAA,CAAI,wBAAc,CAAC;AAAA,CAAI,CAAA;AAChE,IAAA,MAAM,QAAQ,OAAA,CAAQ,KAAA;AACtB,IAAA,MAAM,MAAA,GAAS,OAAO,KAAA,CAAM,UAAA,KAAe,cAAc,KAAA,CAAM,KAAA;AAE/D,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,IAAA,CAAK,cAAA,CAAe,SAAS,OAAO,CAAA;AAExD,IAAS,4BAAmB,KAAK,CAAA;AACjC,IAAA,KAAA,CAAM,WAAW,IAAI,CAAA;AACrB,IAAA,KAAA,CAAM,MAAA,EAAO;AACb,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,MAAM,MAAA,GAAS,CAAC,KAAA,GAAQ,KAAA,KAAgB;AACtC,MAAA,IAAI,CAAC,KAAA,EAAO,GAAA,CAAI,CAAA,KAAA,EAAQ,OAAA,CAAQ,MAAM,CAAA,CAAA,CAAG,CAAA;AACzC,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,QAAA,MAAM,SAAS,CAAA,KAAM,KAAA;AACrB,QAAA,MAAM,OAAA,GAAU,MAAA,GAAS,IAAA,CAAK,QAAG,CAAA,GAAI,GAAA;AACrC,QAAA,MAAM,KAAA,GAAQ,MAAA,GAAS,CAAA,CAAE,IAAA,CAAK,OAAA,CAAQ,CAAC,CAAA,CAAE,KAAK,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA,CAAE,KAAA;AAC7D,QAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,CAAC,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,GAAA,CAAI,CAAA,EAAA,EAAK,OAAA,CAAQ,CAAC,CAAA,CAAE,IAAI,EAAE,CAAA,GAAI,EAAA;AAC/D,QAAA,GAAA,CAAI,CAAA,OAAA,EAAU,OAAO,CAAA,CAAA,EAAI,KAAK,GAAG,IAAI;AAAA,CAAI,CAAA;AAAA,MAC3C;AAAA,IACF,CAAA;AACA,IAAA,MAAA,CAAO,IAAI,CAAA;AACX,IAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AACzC,MAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,EAAc,GAAA,KAA4B;AACvD,QAAA,IAAI,CAAC,GAAA,EAAK;AACV,QAAA,IAAI,GAAA,CAAI,SAAS,IAAA,IAAS,GAAA,CAAI,SAAS,GAAA,IAAO,CAAC,IAAI,IAAA,EAAO;AACxD,UAAA,KAAA,GAAA,CAAS,KAAA,GAAQ,CAAA,GAAI,OAAA,CAAQ,MAAA,IAAU,OAAA,CAAQ,MAAA;AAC/C,UAAA,MAAA,EAAO;AAAA,QACT,CAAA,MAAA,IAAW,IAAI,IAAA,KAAS,MAAA,IAAW,IAAI,IAAA,KAAS,GAAA,IAAO,CAAC,GAAA,CAAI,IAAA,EAAO;AACjE,UAAA,KAAA,GAAA,CAAS,KAAA,GAAQ,KAAK,OAAA,CAAQ,MAAA;AAC9B,UAAA,MAAA,EAAO;AAAA,QACT,WAAW,GAAA,CAAI,IAAA,KAAS,QAAA,IAAY,GAAA,CAAI,SAAS,OAAA,EAAS;AACxD,UAAA,OAAA,EAAQ;AACR,UAAA,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,QAAG,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,GAAA,CAAI,OAAA,CAAQ,KAAK,CAAA,CAAE,KAAK,CAAC;AAAA,CAAI,CAAA;AACnD,UAAA,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA,CAAE,KAAK,CAAA;AAAA,QAC9B,CAAA,MAAA,IAAW,IAAI,IAAA,KAAS,QAAA,IAAa,IAAI,IAAA,IAAQ,GAAA,CAAI,SAAS,GAAA,EAAM;AAClE,UAAA,OAAA,EAAQ;AACR,UAAA,MAAA,CAAO,IAAI,iBAAiB,CAAA;AAAA,QAC9B;AAAA,MACF,CAAA;AACA,MAAA,MAAM,UAAU,MAAY;AAC1B,QAAA,KAAA,CAAM,cAAA,CAAe,YAAY,KAAK,CAAA;AACtC,QAAA,IAAI,OAAO,KAAA,CAAM,UAAA,KAAe,UAAA,EAAY,KAAA,CAAM,WAAW,KAAK,CAAA;AAClE,QAAA,KAAA,CAAM,KAAA,EAAM;AAAA,MACd,CAAA;AACA,MAAA,KAAA,CAAM,EAAA,CAAG,YAAY,KAAK,CAAA;AAAA,IAC5B,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAc,cAAA,CAAkB,OAAA,EAAiB,OAAA,EAAwC;AACvF,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,MAAA,GAAA,CAAI,CAAA,EAAA,EAAK,CAAA,CAAE,IAAA,CAAK,MAAA,CAAO,CAAA,GAAI,CAAC,CAAC,CAAC,CAAA,EAAA,EAAK,OAAA,CAAQ,CAAC,CAAA,CAAE,KAAK,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,GAAA,CAAI,CAAA,EAAA,EAAK,OAAA,CAAQ,CAAC,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,GAAI,EAAE;AAAA,CAAI,CAAA;AAAA,IAChH;AACA,IAAA,WAAS;AACP,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,cAAA,CAAW,CAAA;AACrD,MAAA,MAAM,CAAA,GAAI,OAAO,MAAM,CAAA;AACvB,MAAA,IAAI,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,IAAK,CAAA,IAAK,OAAA,CAAQ,MAAA,EAAQ,OAAO,OAAA,CAAQ,CAAA,GAAI,CAAC,CAAA,CAAE,KAAA;AAChF,MAAA,IAAA,CAAK,KAAK,CAAA,CAAE,MAAA,CAAO,gBAAW,OAAA,CAAQ,MAAM,EAAE,CAAC,CAAA;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,KAAA,CAAM,OAAA,EAAiB,IAAA,GAAmD,EAAC,EAAoB;AAC7F,IAAA,MAAM,EAAA,GAAc,yBAAgB,EAAE,KAAA,EAAO,QAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AACpF,IAAA,MAAM,SAAS,IAAA,CAAK,OAAA,GAAU,EAAE,GAAA,CAAI,CAAA,EAAA,EAAK,KAAK,OAAO,CAAA,CAAA,CAAG,CAAA,GAAI,IAAA,CAAK,cAAc,CAAA,CAAE,GAAA,CAAI,KAAK,IAAA,CAAK,WAAW,GAAG,CAAA,GAAI,EAAA;AACjH,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,EAAA,CAAG,QAAA,CAAS,CAAA,EAAG,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,IAAA,CAAK,OAAO,CAAC,CAAA,EAAG,MAAM,CAAA,CAAA,CAAA,EAAK,CAAC,MAAA,KAAW;AACnE,QAAA,EAAA,CAAG,KAAA,EAAM;AACT,QAAA,MAAM,OAAA,GAAU,OAAO,IAAA,EAAK;AAC5B,QAAA,OAAA,CAAQ,OAAA,IAAW,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAAA,MACvC,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,OAAA,CAAQ,OAAA,EAAiB,GAAA,GAAM,KAAA,EAAyB;AAC5D,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,CAAA,CAAE,GAAA,CAAI,GAAA,GAAM,OAAA,GAAU,OAAO,CAAC,CAAA,CAAE,CAAA;AAC9E,IAAA,IAAI,CAAC,QAAQ,OAAO,GAAA;AACpB,IAAA,OAAO,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,IAAA,EAAM,CAAA;AAAA,EACvC;AAAA,EAEA,QAAQ,OAAA,EAA0B;AAChC,IAAA,MAAM,MAAA,GAAS,CAAC,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAA,EAAK,QAAG,CAAA;AAChE,IAAA,IAAI,CAAA,GAAI,CAAA;AACR,IAAA,IAAI,OAAA,GAAU,OAAA;AACd,IAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,CAAO,KAAA;AAC9B,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,KAAA,GAAQ,YAAY,MAAM;AACxB,QAAA,GAAA,CAAI,CAAA,SAAA,EAAY,IAAA,CAAK,MAAA,CAAQ,CAAA,GAAA,CAAK,CAAA,GAAI,CAAA,IAAK,MAAA,CAAO,MAAO,CAAC,CAAC,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAA;AAAA,MAC1E,GAAG,EAAE,CAAA;AACL,MAAA,KAAA,CAAM,KAAA,IAAQ;AAAA,IAChB,CAAA,MAAO;AACL,MAAA,GAAA,CAAI,GAAG,OAAO;AAAA,CAAI,CAAA;AAAA,IACpB;AACA,IAAA,MAAM,QAAQ,MAAY;AACxB,MAAA,IAAI,KAAA,gBAAqB,KAAK,CAAA;AAC9B,MAAA,IAAI,MAAA,MAAY,CAAA,SAAA,CAAW,CAAA;AAAA,IAC7B,CAAA;AACA,IAAA,OAAO;AAAA,MACL,OAAO,CAAA,EAAG;AACR,QAAA,OAAA,GAAU,CAAA;AAAA,MACZ,CAAA;AAAA,MACA,KAAK,YAAA,EAAc;AACjB,QAAA,KAAA,EAAM;AACN,QAAA,IAAI,cAAc,GAAA,CAAI,CAAA,EAAG,KAAK,QAAG,CAAC,IAAI,YAAY;AAAA,CAAI,CAAA;AAAA,MACxD,CAAA;AAAA,MACA,KAAK,CAAA,EAAG;AACN,QAAA,KAAA,EAAM;AACN,QAAA,GAAA,CAAI,GAAG,CAAA,CAAE,GAAA,CAAI,QAAG,CAAC,IAAI,CAAC;AAAA,CAAI,CAAA;AAAA,MAC5B;AAAA,KACF;AAAA,EACF;AACF","file":"chunk-JYS4OBN2.js","sourcesContent":["/**\n * Zero-dependency interactive UI for the `vg code` guided flow (VG-CLI-CODE §9).\n *\n * We keep the published CLI lean and install-free, so rather than pull an\n * interactive-prompt dependency we ship a small, focused prompter built on\n * `node:readline` + raw-mode keypresses: an arrow-key `select`, a text `input`,\n * a `confirm`, notes, and a `spinner` that wraps noisy child-process output\n * (e.g. an `ollama pull`) behind a single clean status line.\n *\n * Everything is behind the {@link Prompter} interface so the wizard/REPL logic\n * is driven by a scripted fake in tests — no TTY, no raw mode, fully\n * deterministic. All UI writes go to stderr, leaving stdout clean for piped\n * JSON.\n */\n\nimport * as readline from 'node:readline';\nimport { c } from '../util/output.js';\n\n/** Thrown when the user cancels (Esc / Ctrl-C) so callers can exit gracefully. */\nexport class PromptCancelled extends Error {\n constructor() {\n super('cancelled');\n this.name = 'PromptCancelled';\n }\n}\n\nexport interface SelectChoice<T> {\n label: string;\n value: T;\n hint?: string;\n}\n\nexport interface Spinner {\n update(message: string): void;\n stop(finalMessage?: string): void;\n fail(message: string): void;\n}\n\n/** The interactive surface the wizard/REPL depend on (injectable for tests). */\nexport interface Prompter {\n intro(message: string): void;\n outro(message: string): void;\n note(message: string): void;\n select<T>(message: string, choices: SelectChoice<T>[]): Promise<T>;\n input(message: string, opts?: { default?: string; placeholder?: string }): Promise<string>;\n confirm(message: string, def?: boolean): Promise<boolean>;\n spinner(message: string): Spinner;\n}\n\nconst teal = (s: string): string => c.hex('#3FB0A4')(s);\nconst mint = (s: string): string => c.hex('#4FE3C1')(s);\nconst err = (s: string): void => {\n process.stderr.write(s);\n};\n\n/** The real terminal prompter. Only used at an interactive TTY. */\nexport class TtyPrompter implements Prompter {\n intro(message: string): void {\n err(`\\n${mint('◆')} ${c.bold(message)}\\n`);\n }\n outro(message: string): void {\n err(`${mint('◇')} ${message}\\n\\n`);\n }\n note(message: string): void {\n err(`${c.dim('│')} ${message}\\n`);\n }\n\n async select<T>(message: string, choices: SelectChoice<T>[]): Promise<T> {\n if (choices.length === 0) throw new Error('select called with no choices');\n err(`${teal('?')} ${c.bold(message)} ${c.dim('(↑/↓, Enter)')}\\n`);\n const stdin = process.stdin;\n const canRaw = typeof stdin.setRawMode === 'function' && stdin.isTTY;\n // Without a raw-capable TTY, fall back to a numbered prompt.\n if (!canRaw) return this.numberedSelect(message, choices);\n\n readline.emitKeypressEvents(stdin);\n stdin.setRawMode(true);\n stdin.resume();\n let index = 0;\n const render = (first = false): void => {\n if (!first) err(`\\x1b[${choices.length}A`); // cursor up N lines\n for (let i = 0; i < choices.length; i++) {\n const active = i === index;\n const pointer = active ? mint('❯') : ' ';\n const label = active ? c.bold(choices[i].label) : choices[i].label;\n const hint = choices[i].hint ? c.dim(` ${choices[i].hint}`) : '';\n err(`\\x1b[2K${pointer} ${label}${hint}\\n`);\n }\n };\n render(true);\n return new Promise<T>((resolve, reject) => {\n const onKey = (_str: string, key: readline.Key): void => {\n if (!key) return;\n if (key.name === 'up' || (key.name === 'k' && !key.ctrl)) {\n index = (index - 1 + choices.length) % choices.length;\n render();\n } else if (key.name === 'down' || (key.name === 'j' && !key.ctrl)) {\n index = (index + 1) % choices.length;\n render();\n } else if (key.name === 'return' || key.name === 'enter') {\n cleanup();\n err(`${teal('✔')} ${c.dim(choices[index].label)}\\n`);\n resolve(choices[index].value);\n } else if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {\n cleanup();\n reject(new PromptCancelled());\n }\n };\n const cleanup = (): void => {\n stdin.removeListener('keypress', onKey);\n if (typeof stdin.setRawMode === 'function') stdin.setRawMode(false);\n stdin.pause();\n };\n stdin.on('keypress', onKey);\n });\n }\n\n /** Numbered fallback when raw mode isn't available (e.g. a dumb terminal). */\n private async numberedSelect<T>(message: string, choices: SelectChoice<T>[]): Promise<T> {\n for (let i = 0; i < choices.length; i++) {\n err(` ${c.bold(String(i + 1))}. ${choices[i].label}${choices[i].hint ? c.dim(` ${choices[i].hint}`) : ''}\\n`);\n }\n for (;;) {\n const answer = await this.input(`${message} — number`);\n const n = Number(answer);\n if (Number.isInteger(n) && n >= 1 && n <= choices.length) return choices[n - 1].value;\n this.note(c.yellow(`enter 1–${choices.length}`));\n }\n }\n\n input(message: string, opts: { default?: string; placeholder?: string } = {}): Promise<string> {\n const rl = readline.createInterface({ input: process.stdin, output: process.stderr });\n const suffix = opts.default ? c.dim(` (${opts.default})`) : opts.placeholder ? c.dim(` (${opts.placeholder})`) : '';\n return new Promise((resolve) => {\n rl.question(`${teal('?')} ${c.bold(message)}${suffix} `, (answer) => {\n rl.close();\n const trimmed = answer.trim();\n resolve(trimmed || opts.default || '');\n });\n });\n }\n\n async confirm(message: string, def = false): Promise<boolean> {\n const answer = await this.input(`${message} ${c.dim(def ? '[Y/n]' : '[y/N]')}`);\n if (!answer) return def;\n return /^y(es)?$/i.test(answer.trim());\n }\n\n spinner(message: string): Spinner {\n const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n let i = 0;\n let current = message;\n const active = process.stderr.isTTY;\n let timer: ReturnType<typeof setInterval> | undefined;\n if (active) {\n timer = setInterval(() => {\n err(`\\x1b[2K\\r${teal(frames[(i = (i + 1) % frames.length)])} ${current}`);\n }, 80);\n timer.unref?.();\n } else {\n err(`${current}\\n`);\n }\n const clear = (): void => {\n if (timer) clearInterval(timer);\n if (active) err(`\\x1b[2K\\r`);\n };\n return {\n update(m) {\n current = m;\n },\n stop(finalMessage) {\n clear();\n if (finalMessage) err(`${teal('✔')} ${finalMessage}\\n`);\n },\n fail(m) {\n clear();\n err(`${c.red('✗')} ${m}\\n`);\n },\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
// src/code/session-store.ts
|
|
5
|
+
function sessionsDir(root) {
|
|
6
|
+
return path.join(root, ".vibgrate", "code-sessions");
|
|
7
|
+
}
|
|
8
|
+
function latestPointer(root) {
|
|
9
|
+
return path.join(sessionsDir(root), "latest.json");
|
|
10
|
+
}
|
|
11
|
+
function saveSession(root, session) {
|
|
12
|
+
try {
|
|
13
|
+
const dir = sessionsDir(root);
|
|
14
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
15
|
+
fs.writeFileSync(path.join(dir, `${session.id}.json`), JSON.stringify(session, null, 2));
|
|
16
|
+
fs.writeFileSync(latestPointer(root), JSON.stringify({ id: session.id }));
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function loadLatestSession(root) {
|
|
21
|
+
try {
|
|
22
|
+
const { id } = JSON.parse(fs.readFileSync(latestPointer(root), "utf8"));
|
|
23
|
+
const raw = JSON.parse(fs.readFileSync(path.join(sessionsDir(root), `${id}.json`), "utf8"));
|
|
24
|
+
if (Array.isArray(raw.tasks)) return raw;
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
function summarizeSession(session) {
|
|
30
|
+
if (session.tasks.length === 0) return "";
|
|
31
|
+
const lines = session.tasks.slice(-8).map((t, i) => `${i + 1}. ${t.instruction} \u2014 ${t.summary}${t.files.length ? ` (${t.files.join(", ")})` : ""}`);
|
|
32
|
+
return `Earlier in this session (${session.provider}/${session.model}) you did:
|
|
33
|
+
${lines.join("\n")}`;
|
|
34
|
+
}
|
|
35
|
+
function newSession(id, provider, model, now) {
|
|
36
|
+
return { id, provider, model, startedAt: now, updatedAt: now, tasks: [], lastChanges: [] };
|
|
37
|
+
}
|
|
38
|
+
function recordTask(session, task, now) {
|
|
39
|
+
const files = [...new Set(task.changes.map((c) => c.file))];
|
|
40
|
+
return {
|
|
41
|
+
...session,
|
|
42
|
+
updatedAt: now,
|
|
43
|
+
tasks: [...session.tasks, { instruction: task.instruction.slice(0, 300), summary: task.summary.slice(0, 300), files, stopped: task.stopped, ts: now }],
|
|
44
|
+
lastChanges: task.changes.length ? task.changes : session.lastChanges
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { loadLatestSession, newSession, recordTask, saveSession, sessionsDir, summarizeSession };
|
|
49
|
+
//# sourceMappingURL=chunk-K3SLGULW.js.map
|
|
50
|
+
//# sourceMappingURL=chunk-K3SLGULW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/code/session-store.ts"],"names":[],"mappings":"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","file":"chunk-K3SLGULW.js","sourcesContent":["/**\n * Session persistence for VG Code (VG-CLI-CODE §16) — `vg code --continue`.\n *\n * A coding session is a series of tasks; this stores a compact record of them\n * (what you asked, a one-line outcome, which files changed) plus the last\n * change-set so `/undo` survives a restart. `--continue` reloads the most recent\n * session and hands the model a short summary of what was already done, so you\n * can pick a conversation back up instead of re-explaining. We persist a\n * *summary*, never raw file contents or tool transcripts — small, private, and\n * safe to keep on disk.\n *\n * Pure over an injected clock; the store is JSON under `.vibgrate/code-sessions/`.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { FileChange } from './types.js';\n\nexport interface SessionTask {\n instruction: string;\n summary: string;\n files: string[];\n stopped: string;\n ts: number;\n}\n\nexport interface StoredSession {\n id: string;\n provider: string;\n model: string;\n startedAt: number;\n updatedAt: number;\n tasks: SessionTask[];\n /** The most recent change-set, so `/undo` works after `--continue`. */\n lastChanges: FileChange[];\n}\n\nexport function sessionsDir(root: string): string {\n return path.join(root, '.vibgrate', 'code-sessions');\n}\nfunction latestPointer(root: string): string {\n return path.join(sessionsDir(root), 'latest.json');\n}\n\n/** Write a session and update the `latest` pointer. Best-effort; never throws. */\nexport function saveSession(root: string, session: StoredSession): void {\n try {\n const dir = sessionsDir(root);\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(path.join(dir, `${session.id}.json`), JSON.stringify(session, null, 2));\n fs.writeFileSync(latestPointer(root), JSON.stringify({ id: session.id }));\n } catch {\n /* persistence is best-effort */\n }\n}\n\n/** Load the most recent session, or undefined if none/there was a read error. */\nexport function loadLatestSession(root: string): StoredSession | undefined {\n try {\n const { id } = JSON.parse(fs.readFileSync(latestPointer(root), 'utf8')) as { id: string };\n const raw = JSON.parse(fs.readFileSync(path.join(sessionsDir(root), `${id}.json`), 'utf8')) as StoredSession;\n if (Array.isArray(raw.tasks)) return raw;\n } catch {\n /* no session */\n }\n return undefined;\n}\n\n/** A short natural-language recap of a session to seed a continued run's context. */\nexport function summarizeSession(session: StoredSession): string {\n if (session.tasks.length === 0) return '';\n const lines = session.tasks.slice(-8).map((t, i) => `${i + 1}. ${t.instruction} — ${t.summary}${t.files.length ? ` (${t.files.join(', ')})` : ''}`);\n return `Earlier in this session (${session.provider}/${session.model}) you did:\\n${lines.join('\\n')}`;\n}\n\n/** A fresh session record. `id` and `now` are injected so this stays deterministic. */\nexport function newSession(id: string, provider: string, model: string, now: number): StoredSession {\n return { id, provider, model, startedAt: now, updatedAt: now, tasks: [], lastChanges: [] };\n}\n\n/** Append a completed task (immutably updating the record's timestamps). */\nexport function recordTask(\n session: StoredSession,\n task: { instruction: string; summary: string; changes: FileChange[]; stopped: string },\n now: number,\n): StoredSession {\n const files = [...new Set(task.changes.map((c) => c.file))];\n return {\n ...session,\n updatedAt: now,\n tasks: [...session.tasks, { instruction: task.instruction.slice(0, 300), summary: task.summary.slice(0, 300), files, stopped: task.stopped, ts: now }],\n lastChanges: task.changes.length ? task.changes : session.lastChanges,\n };\n}\n"]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/code/mcp-tools.ts
|
|
2
|
+
var NS = "mcp__";
|
|
3
|
+
var sep = "__";
|
|
4
|
+
var McpToolset = class _McpToolset {
|
|
5
|
+
constructor(clients, tools) {
|
|
6
|
+
this.clients = clients;
|
|
7
|
+
this.tools = tools;
|
|
8
|
+
}
|
|
9
|
+
clients;
|
|
10
|
+
tools;
|
|
11
|
+
/**
|
|
12
|
+
* Connect to every configured server and enumerate its tools. A server that
|
|
13
|
+
* fails to connect or list is skipped with a note in `warnings` — one broken
|
|
14
|
+
* server never sinks the session.
|
|
15
|
+
*/
|
|
16
|
+
static async connect(servers, connect) {
|
|
17
|
+
const clients = /* @__PURE__ */ new Map();
|
|
18
|
+
const tools = /* @__PURE__ */ new Map();
|
|
19
|
+
const warnings = [];
|
|
20
|
+
for (const [server, config] of Object.entries(servers)) {
|
|
21
|
+
try {
|
|
22
|
+
const client = await connect(server, config);
|
|
23
|
+
const listed = await client.listTools();
|
|
24
|
+
clients.set(server, client);
|
|
25
|
+
for (const t of listed.tools) {
|
|
26
|
+
const name = `${NS}${server}${sep}${t.name}`;
|
|
27
|
+
tools.set(name, {
|
|
28
|
+
server,
|
|
29
|
+
toolName: t.name,
|
|
30
|
+
readOnly: t.annotations?.readOnlyHint === true,
|
|
31
|
+
spec: {
|
|
32
|
+
name,
|
|
33
|
+
description: `[${server}] ${t.description ?? t.name}`,
|
|
34
|
+
parameters: t.inputSchema && typeof t.inputSchema === "object" ? t.inputSchema : { type: "object", properties: {} }
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
} catch (e) {
|
|
39
|
+
warnings.push(`MCP server "${server}" unavailable: ${e.message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { toolset: new _McpToolset(clients, tools), warnings };
|
|
43
|
+
}
|
|
44
|
+
/** The tool specs to advertise to the model. */
|
|
45
|
+
specs() {
|
|
46
|
+
return [...this.tools.values()].map((t) => t.spec).sort((a, b) => a.name.localeCompare(b.name));
|
|
47
|
+
}
|
|
48
|
+
/** Whether a tool call name belongs to this toolset. */
|
|
49
|
+
owns(name) {
|
|
50
|
+
return this.tools.has(name);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Execute an external tool call. A non-read-only tool is gated through
|
|
54
|
+
* `approve` first (default-deny if declined). Never throws — errors come back
|
|
55
|
+
* as tool content for the model to read.
|
|
56
|
+
*/
|
|
57
|
+
async execute(call, approve) {
|
|
58
|
+
const owned = this.tools.get(call.name);
|
|
59
|
+
if (!owned) return { content: `unknown MCP tool ${call.name}`, mutated: false };
|
|
60
|
+
if (!owned.readOnly) {
|
|
61
|
+
if (!await approve({ kind: "tool", name: call.name, args: call.arguments })) {
|
|
62
|
+
return { content: `calling ${call.name} was declined by the user`, mutated: false };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const client = this.clients.get(owned.server);
|
|
66
|
+
if (!client) return { content: `MCP server ${owned.server} is not connected`, mutated: false };
|
|
67
|
+
try {
|
|
68
|
+
const res = await client.callTool({ name: owned.toolName, arguments: call.arguments });
|
|
69
|
+
const text = (res.content ?? []).map((c) => c.type === "text" ? c.text ?? "" : `[${c.type}]`).join("\n") || "(no output)";
|
|
70
|
+
return { content: text.slice(0, 12e3), mutated: !owned.readOnly && !res.isError };
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return { content: `MCP tool ${call.name} failed: ${e.message}`, mutated: false };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async dispose() {
|
|
76
|
+
for (const client of this.clients.values()) {
|
|
77
|
+
try {
|
|
78
|
+
await client.close();
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var defaultMcpConnect = async (name, config) => {
|
|
85
|
+
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
86
|
+
const client = new Client({ name: `vg-code:${name}`, version: "1.0.0" }, { capabilities: {} });
|
|
87
|
+
if (config.url) {
|
|
88
|
+
const url = new URL(config.url);
|
|
89
|
+
const requestInit = config.headers ? { headers: config.headers } : void 0;
|
|
90
|
+
if (config.type === "sse") {
|
|
91
|
+
const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js');
|
|
92
|
+
await client.connect(new SSEClientTransport(url, requestInit ? { requestInit } : void 0));
|
|
93
|
+
} else {
|
|
94
|
+
const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
95
|
+
await client.connect(new StreamableHTTPClientTransport(url, requestInit ? { requestInit } : void 0));
|
|
96
|
+
}
|
|
97
|
+
} else if (config.command) {
|
|
98
|
+
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
|
|
99
|
+
await client.connect(new StdioClientTransport({ command: config.command, args: config.args ?? [], env: config.env }));
|
|
100
|
+
} else {
|
|
101
|
+
throw new Error("server config has neither a command (stdio) nor a url (remote)");
|
|
102
|
+
}
|
|
103
|
+
return client;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export { McpToolset, defaultMcpConnect };
|
|
107
|
+
//# sourceMappingURL=chunk-LEPTUB4H.js.map
|
|
108
|
+
//# sourceMappingURL=chunk-LEPTUB4H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/code/mcp-tools.ts"],"names":[],"mappings":";AAoCA,IAAM,EAAA,GAAK,OAAA;AACX,IAAM,GAAA,GAAM,IAAA;AAUL,IAAM,UAAA,GAAN,MAAM,WAAA,CAAW;AAAA,EACd,WAAA,CACW,SACA,KAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA,EAChB;AAAA,EAFgB,OAAA;AAAA,EACA,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnB,aAAa,OAAA,CAAQ,OAAA,EAA0C,OAAA,EAA2E;AACxI,IAAA,MAAM,OAAA,uBAAc,GAAA,EAA2B;AAC/C,IAAA,MAAM,KAAA,uBAAY,GAAA,EAAuB;AACzC,IAAA,MAAM,WAAqB,EAAC;AAC5B,IAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,MAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AACtD,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,MAAA,EAAQ,MAAM,CAAA;AAC3C,QAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,SAAA,EAAU;AACtC,QAAA,OAAA,CAAQ,GAAA,CAAI,QAAQ,MAAM,CAAA;AAC1B,QAAA,KAAA,MAAW,CAAA,IAAK,OAAO,KAAA,EAAO;AAC5B,UAAA,MAAM,IAAA,GAAO,GAAG,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,CAAA;AAC1C,UAAA,KAAA,CAAM,IAAI,IAAA,EAAM;AAAA,YACd,MAAA;AAAA,YACA,UAAU,CAAA,CAAE,IAAA;AAAA,YACZ,QAAA,EAAU,CAAA,CAAE,WAAA,EAAa,YAAA,KAAiB,IAAA;AAAA,YAC1C,IAAA,EAAM;AAAA,cACJ,IAAA;AAAA,cACA,aAAa,CAAA,CAAA,EAAI,MAAM,KAAK,CAAA,CAAE,WAAA,IAAe,EAAE,IAAI,CAAA,CAAA;AAAA,cACnD,UAAA,EAAY,CAAA,CAAE,WAAA,IAAe,OAAO,EAAE,WAAA,KAAgB,QAAA,GAAW,CAAA,CAAE,WAAA,GAAc,EAAE,IAAA,EAAM,QAAA,EAAU,UAAA,EAAY,EAAC;AAAE;AACpH,WACD,CAAA;AAAA,QACH;AAAA,MACF,SAAS,CAAA,EAAG;AACV,QAAA,QAAA,CAAS,KAAK,CAAA,YAAA,EAAe,MAAM,CAAA,eAAA,EAAmB,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,MAC7E;AAAA,IACF;AACA,IAAA,OAAO,EAAE,OAAA,EAAS,IAAI,YAAW,OAAA,EAAS,KAAK,GAAG,QAAA,EAAS;AAAA,EAC7D;AAAA;AAAA,EAGA,KAAA,GAAoB;AAClB,IAAA,OAAO,CAAC,GAAG,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,IAAA,CAAK,aAAA,CAAc,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,EAChG;AAAA;AAAA,EAGA,KAAK,IAAA,EAAuB;AAC1B,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,IAAI,CAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAA,CAAQ,IAAA,EAAgB,OAAA,EAAuE;AACnG,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,KAAK,IAAI,CAAA;AACtC,IAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,OAAA,EAAS,oBAAoB,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,OAAA,EAAS,KAAA,EAAM;AAC9E,IAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AACnB,MAAA,IAAI,CAAE,MAAM,OAAA,CAAQ,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,IAAA,CAAK,SAAA,EAAW,CAAA,EAAI;AAC7E,QAAA,OAAO,EAAE,OAAA,EAAS,CAAA,QAAA,EAAW,KAAK,IAAI,CAAA,yBAAA,CAAA,EAA6B,SAAS,KAAA,EAAM;AAAA,MACpF;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,MAAM,MAAM,CAAA;AAC5C,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAE,OAAA,EAAS,cAAc,KAAA,CAAM,MAAM,CAAA,iBAAA,CAAA,EAAqB,OAAA,EAAS,KAAA,EAAM;AAC7F,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,QAAA,CAAS,EAAE,IAAA,EAAM,KAAA,CAAM,QAAA,EAAU,SAAA,EAAW,IAAA,CAAK,SAAA,EAAW,CAAA;AACrF,MAAA,MAAM,IAAA,GAAA,CAAQ,IAAI,OAAA,IAAW,IAAI,GAAA,CAAI,CAAC,MAAO,CAAA,CAAE,IAAA,KAAS,SAAU,CAAA,CAAE,IAAA,IAAQ,KAAM,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAA,CAAI,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,IAAK,aAAA;AAChH,MAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,IAAM,CAAA,EAAG,OAAA,EAAS,CAAC,KAAA,CAAM,QAAA,IAAY,CAAC,IAAI,OAAA,EAAQ;AAAA,IACpF,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,EAAE,OAAA,EAAS,CAAA,SAAA,EAAY,IAAA,CAAK,IAAI,YAAa,CAAA,CAAY,OAAO,CAAA,CAAA,EAAI,OAAA,EAAS,KAAA,EAAM;AAAA,IAC5F;AAAA,EACF;AAAA,EAEA,MAAM,OAAA,GAAyB;AAC7B,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,MAAA,IAAI;AACF,QAAA,MAAM,OAAO,KAAA,EAAM;AAAA,MACrB,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;AAOO,IAAM,iBAAA,GAAgC,OAAO,IAAA,EAAM,MAAA,KAAW;AACnE,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,OAAO,2CAA2C,CAAA;AAC3E,EAAA,MAAM,MAAA,GAAS,IAAI,MAAA,CAAO,EAAE,MAAM,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,OAAA,EAAS,SAAQ,EAAG,EAAE,YAAA,EAAc,IAAI,CAAA;AAC7F,EAAA,IAAI,OAAO,GAAA,EAAK;AACd,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA;AAC9B,IAAA,MAAM,cAAc,MAAA,CAAO,OAAA,GAAU,EAAE,OAAA,EAAS,MAAA,CAAO,SAAQ,GAAI,MAAA;AACnE,IAAA,IAAI,MAAA,CAAO,SAAS,KAAA,EAAO;AACzB,MAAA,MAAM,EAAE,kBAAA,EAAmB,GAAI,MAAM,OAAO,yCAAyC,CAAA;AACrF,MAAA,MAAM,MAAA,CAAO,OAAA,CAAQ,IAAI,kBAAA,CAAmB,GAAA,EAAK,cAAc,EAAE,WAAA,EAAY,GAAI,MAAS,CAAC,CAAA;AAAA,IAC7F,CAAA,MAAO;AACL,MAAA,MAAM,EAAE,6BAAA,EAA8B,GAAI,MAAM,OAAO,oDAAoD,CAAA;AAC3G,MAAA,MAAM,MAAA,CAAO,OAAA,CAAQ,IAAI,6BAAA,CAA8B,GAAA,EAAK,cAAc,EAAE,WAAA,EAAY,GAAI,MAAS,CAAC,CAAA;AAAA,IACxG;AAAA,EACF,CAAA,MAAA,IAAW,OAAO,OAAA,EAAS;AACzB,IAAA,MAAM,EAAE,oBAAA,EAAqB,GAAI,MAAM,OAAO,2CAA2C,CAAA;AACzF,IAAA,MAAM,OAAO,OAAA,CAAQ,IAAI,oBAAA,CAAqB,EAAE,SAAS,MAAA,CAAO,OAAA,EAAS,IAAA,EAAM,MAAA,CAAO,QAAQ,EAAC,EAAG,KAAK,MAAA,CAAO,GAAA,EAAK,CAAC,CAAA;AAAA,EACtH,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,MAAM,gEAAgE,CAAA;AAAA,EAClF;AACA,EAAA,OAAO,MAAA;AACT","file":"chunk-LEPTUB4H.js","sourcesContent":["/**\n * External MCP tools for the VG Code agent (VG-CLI-CODE §17).\n *\n * Like Claude Code, VG Code can use tools from external MCP servers you list in\n * `.vibgrate/code.json` (`mcpServers`). We connect to each server, list its\n * tools, expose them to the model namespaced as `mcp__<server>__<tool>`, and\n * route calls back. Read-only tools (per their `readOnlyHint`) run freely;\n * anything else goes through the same approval gate as a built-in mutating tool,\n * so an external server can't mutate or exfiltrate without consent.\n *\n * The transport is injectable, so namespacing, routing, the read-only/gated\n * split, and lifecycle are unit-tested with a fake client — no real server.\n */\n\nimport type { McpServerConfig } from './config.js';\nimport type { ToolResult } from './tools.js';\nimport type { MutatingAction } from './tools.js';\nimport type { ToolCall, ToolSpec } from './types.js';\n\n/** The subset of an MCP client we use — satisfied by the real SDK client and by test fakes. */\nexport interface McpClientLike {\n listTools(): Promise<{ tools: McpToolDef[] }>;\n callTool(args: { name: string; arguments: Record<string, unknown> }): Promise<{ content?: { type: string; text?: string }[]; isError?: boolean }>;\n close(): Promise<void>;\n}\n\nexport interface McpToolDef {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n annotations?: { readOnlyHint?: boolean; destructiveHint?: boolean };\n}\n\n/** How to open a connection to a configured server (injectable; default uses the SDK). */\nexport type McpConnect = (name: string, config: McpServerConfig) => Promise<McpClientLike>;\n\nconst NS = 'mcp__';\nconst sep = '__';\n\ninterface OwnedTool {\n server: string;\n toolName: string;\n spec: ToolSpec;\n readOnly: boolean;\n}\n\n/** A live set of external MCP tools, keyed by their namespaced name. */\nexport class McpToolset {\n private constructor(\n private readonly clients: Map<string, McpClientLike>,\n private readonly tools: Map<string, OwnedTool>,\n ) {}\n\n /**\n * Connect to every configured server and enumerate its tools. A server that\n * fails to connect or list is skipped with a note in `warnings` — one broken\n * server never sinks the session.\n */\n static async connect(servers: Record<string, McpServerConfig>, connect: McpConnect): Promise<{ toolset: McpToolset; warnings: string[] }> {\n const clients = new Map<string, McpClientLike>();\n const tools = new Map<string, OwnedTool>();\n const warnings: string[] = [];\n for (const [server, config] of Object.entries(servers)) {\n try {\n const client = await connect(server, config);\n const listed = await client.listTools();\n clients.set(server, client);\n for (const t of listed.tools) {\n const name = `${NS}${server}${sep}${t.name}`;\n tools.set(name, {\n server,\n toolName: t.name,\n readOnly: t.annotations?.readOnlyHint === true,\n spec: {\n name,\n description: `[${server}] ${t.description ?? t.name}`,\n parameters: t.inputSchema && typeof t.inputSchema === 'object' ? t.inputSchema : { type: 'object', properties: {} },\n },\n });\n }\n } catch (e) {\n warnings.push(`MCP server \"${server}\" unavailable: ${(e as Error).message}`);\n }\n }\n return { toolset: new McpToolset(clients, tools), warnings };\n }\n\n /** The tool specs to advertise to the model. */\n specs(): ToolSpec[] {\n return [...this.tools.values()].map((t) => t.spec).sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Whether a tool call name belongs to this toolset. */\n owns(name: string): boolean {\n return this.tools.has(name);\n }\n\n /**\n * Execute an external tool call. A non-read-only tool is gated through\n * `approve` first (default-deny if declined). Never throws — errors come back\n * as tool content for the model to read.\n */\n async execute(call: ToolCall, approve: (a: MutatingAction) => Promise<boolean>): Promise<ToolResult> {\n const owned = this.tools.get(call.name);\n if (!owned) return { content: `unknown MCP tool ${call.name}`, mutated: false };\n if (!owned.readOnly) {\n if (!(await approve({ kind: 'tool', name: call.name, args: call.arguments }))) {\n return { content: `calling ${call.name} was declined by the user`, mutated: false };\n }\n }\n const client = this.clients.get(owned.server);\n if (!client) return { content: `MCP server ${owned.server} is not connected`, mutated: false };\n try {\n const res = await client.callTool({ name: owned.toolName, arguments: call.arguments });\n const text = (res.content ?? []).map((c) => (c.type === 'text' ? (c.text ?? '') : `[${c.type}]`)).join('\\n') || '(no output)';\n return { content: text.slice(0, 12_000), mutated: !owned.readOnly && !res.isError };\n } catch (e) {\n return { content: `MCP tool ${call.name} failed: ${(e as Error).message}`, mutated: false };\n }\n }\n\n async dispose(): Promise<void> {\n for (const client of this.clients.values()) {\n try {\n await client.close();\n } catch {\n /* best-effort */\n }\n }\n }\n}\n\n/**\n * Default connect using the MCP SDK (loaded lazily). Handles both a local stdio\n * server (`command`) and a remote server (`url`, streamable-HTTP or SSE) — the\n * two shapes the standard config files use.\n */\nexport const defaultMcpConnect: McpConnect = async (name, config) => {\n const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');\n const client = new Client({ name: `vg-code:${name}`, version: '1.0.0' }, { capabilities: {} });\n if (config.url) {\n const url = new URL(config.url);\n const requestInit = config.headers ? { headers: config.headers } : undefined;\n if (config.type === 'sse') {\n const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js');\n await client.connect(new SSEClientTransport(url, requestInit ? { requestInit } : undefined));\n } else {\n const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js');\n await client.connect(new StreamableHTTPClientTransport(url, requestInit ? { requestInit } : undefined));\n }\n } else if (config.command) {\n const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');\n await client.connect(new StdioClientTransport({ command: config.command, args: config.args ?? [], env: config.env }));\n } else {\n throw new Error('server config has neither a command (stdio) nor a url (remote)');\n }\n return client as unknown as McpClientLike;\n};\n"]}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { redactSecrets } from './chunk-RXP66R2E.js';
|
|
2
|
+
import { hashString } from './chunk-JFGYT6BI.js';
|
|
2
3
|
import * as fs from 'fs';
|
|
3
4
|
import * as path from 'path';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
5
6
|
import { createRequire } from 'module';
|
|
6
7
|
import { Language, Parser, Query } from 'web-tree-sitter';
|
|
7
|
-
import { blake3 } from '@noble/hashes/blake3.js';
|
|
8
|
-
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
9
8
|
|
|
10
9
|
// src/engine/languages.ts
|
|
11
10
|
var LANGUAGES = [
|
|
@@ -318,7 +317,11 @@ var JAVA = {
|
|
|
318
317
|
typeRefs: [
|
|
319
318
|
"(constructor_declaration parameters: (formal_parameters (formal_parameter type: (type_identifier) @typeref)))",
|
|
320
319
|
"(field_declaration type: (type_identifier) @typeref)"
|
|
321
|
-
]
|
|
320
|
+
],
|
|
321
|
+
// A Java package is a directory, so cross-directory (cross-package) DI
|
|
322
|
+
// resolves through `import a.b.Foo`. Capturing the package lets the resolver
|
|
323
|
+
// reach the implementation in another package when the caller imports it.
|
|
324
|
+
namespaces: ["(package_declaration (scoped_identifier) @namespace)", "(package_declaration (identifier) @namespace)"]
|
|
322
325
|
};
|
|
323
326
|
var RUST = {
|
|
324
327
|
defs: [
|
|
@@ -349,9 +352,32 @@ var C_SHARP = {
|
|
|
349
352
|
{ kind: "class", query: "(enum_declaration name: (identifier) @name) @def" },
|
|
350
353
|
{ kind: "class", query: "(record_declaration name: (identifier) @name) @def" }
|
|
351
354
|
],
|
|
352
|
-
calls: [
|
|
355
|
+
calls: [
|
|
356
|
+
"(invocation_expression function: (member_access_expression name: (identifier) @callee))",
|
|
357
|
+
"(invocation_expression function: (identifier) @callee)",
|
|
358
|
+
// `new Foo(...)` is an instantiation dependency (the caller depends on Foo),
|
|
359
|
+
// and it is how a test most directly links to the class under test — without
|
|
360
|
+
// it a test that only constructs the service showed up as no coverage.
|
|
361
|
+
"(object_creation_expression type: (identifier) @callee)"
|
|
362
|
+
],
|
|
353
363
|
imports: ["(using_directive (qualified_name) @source)", "(using_directive (identifier) @source)"],
|
|
354
|
-
heritage: ["(base_list (identifier) @extends)"]
|
|
364
|
+
heritage: ["(base_list (identifier) @extends)"],
|
|
365
|
+
// Dependency-injection wiring: the interface a class depends on appears as a
|
|
366
|
+
// constructor-parameter type or a readonly field type, never as a call — so
|
|
367
|
+
// without these captures a controller/service injected through an interface
|
|
368
|
+
// looks like it references nothing. Simple (identifier) types only; generics/
|
|
369
|
+
// qualified names are left to a precise rung. Mirrors the Java DI captures.
|
|
370
|
+
typeRefs: [
|
|
371
|
+
"(constructor_declaration (parameter_list (parameter type: (identifier) @typeref)))",
|
|
372
|
+
"(field_declaration (variable_declaration type: (identifier) @typeref))"
|
|
373
|
+
],
|
|
374
|
+
// A namespace is decoupled from the directory in C#, so cross-namespace
|
|
375
|
+
// resolution needs to know which namespace a file declares. Both block-scoped
|
|
376
|
+
// (`namespace N { }`) and file-scoped (`namespace N;`) forms.
|
|
377
|
+
namespaces: [
|
|
378
|
+
"(namespace_declaration name: [(identifier) (qualified_name)] @namespace)",
|
|
379
|
+
"(file_scoped_namespace_declaration name: [(identifier) (qualified_name)] @namespace)"
|
|
380
|
+
]
|
|
355
381
|
};
|
|
356
382
|
var RUBY = {
|
|
357
383
|
defs: [
|
|
@@ -390,6 +416,15 @@ var PHP = {
|
|
|
390
416
|
"[(require_expression (string) @source) (require_once_expression (string) @source) (include_expression (string) @source) (include_once_expression (string) @source)]"
|
|
391
417
|
],
|
|
392
418
|
heritage: ["(base_clause (name) @extends)", "(class_interface_clause (name) @implements)"],
|
|
419
|
+
// PHP namespaces are decoupled from directories (PSR-4 maps them, but the
|
|
420
|
+
// resolver has no composer.json), so cross-namespace DI resolves through
|
|
421
|
+
// `use`. Constructor-parameter and typed-property types are the injection
|
|
422
|
+
// points.
|
|
423
|
+
namespaces: ["(namespace_definition name: (namespace_name) @namespace)"],
|
|
424
|
+
typeRefs: [
|
|
425
|
+
"(simple_parameter type: (named_type (name) @typeref))",
|
|
426
|
+
"(property_declaration type: (named_type (name) @typeref))"
|
|
427
|
+
],
|
|
393
428
|
guards: ['(function_call_expression function: (name) @_g (#eq? @_g "assert")) @guard']
|
|
394
429
|
};
|
|
395
430
|
var KOTLIN = {
|
|
@@ -404,6 +439,14 @@ var KOTLIN = {
|
|
|
404
439
|
"(call_expression (navigation_expression (navigation_suffix (simple_identifier) @callee)))"
|
|
405
440
|
],
|
|
406
441
|
imports: ["(import_header (identifier) @source)"],
|
|
442
|
+
// Kotlin: package for cross-package DI reachability; primary-constructor
|
|
443
|
+
// `val` params and property types are the injection points.
|
|
444
|
+
namespaces: ["(package_header (identifier) @namespace)"],
|
|
445
|
+
typeRefs: [
|
|
446
|
+
"(class_parameter (user_type (type_identifier) @typeref))",
|
|
447
|
+
"(property_declaration (variable_declaration (user_type (type_identifier) @typeref)))",
|
|
448
|
+
"(property_declaration (variable_declaration (nullable_type (user_type (type_identifier) @typeref))))"
|
|
449
|
+
],
|
|
407
450
|
heritage: [
|
|
408
451
|
"(delegation_specifier (constructor_invocation (user_type (type_identifier) @extends)))",
|
|
409
452
|
"(delegation_specifier (user_type (type_identifier) @implements))"
|
|
@@ -424,6 +467,13 @@ var SWIFT = {
|
|
|
424
467
|
],
|
|
425
468
|
imports: ["(import_declaration (identifier) @source)"],
|
|
426
469
|
heritage: ["(inheritance_specifier inherits_from: (user_type (type_identifier) @extends))"],
|
|
470
|
+
// Swift: init-parameter and stored-property types are the injection points
|
|
471
|
+
// (protocol-typed). Whole-module visibility (handled in resolve.ts) makes the
|
|
472
|
+
// conforming implementation reachable cross-file.
|
|
473
|
+
typeRefs: [
|
|
474
|
+
"(parameter (user_type (type_identifier) @typeref))",
|
|
475
|
+
"(type_annotation (user_type (type_identifier) @typeref))"
|
|
476
|
+
],
|
|
427
477
|
guards: [
|
|
428
478
|
'(call_expression (simple_identifier) @_g (#match? @_g "^(assert|precondition|assertionFailure|preconditionFailure)$")) @guard'
|
|
429
479
|
]
|
|
@@ -450,6 +500,13 @@ var SCALA = {
|
|
|
450
500
|
"(extends_clause type: (compound_type base: (type_identifier) @extends))",
|
|
451
501
|
"(extends_clause type: (compound_type extra: (type_identifier) @implements))"
|
|
452
502
|
],
|
|
503
|
+
// Scala: package for cross-package DI reachability; class-parameter and val
|
|
504
|
+
// types are the injection points.
|
|
505
|
+
namespaces: ["(package_clause name: (package_identifier) @namespace)"],
|
|
506
|
+
typeRefs: [
|
|
507
|
+
"(class_parameter type: (type_identifier) @typeref)",
|
|
508
|
+
"(val_definition type: (type_identifier) @typeref)"
|
|
509
|
+
],
|
|
453
510
|
guards: ['(call_expression function: (identifier) @_g (#match? @_g "^(require|assert|assume)$")) @guard']
|
|
454
511
|
};
|
|
455
512
|
var DART = {
|
|
@@ -466,6 +523,13 @@ var DART = {
|
|
|
466
523
|
"(cascade_section (cascade_selector (identifier) @callee) . (argument_part))"
|
|
467
524
|
],
|
|
468
525
|
imports: ["(import_specification (configurable_uri (uri (string_literal) @source)))"],
|
|
526
|
+
// Dart: constructor/method parameter types and typed field declarations are
|
|
527
|
+
// the injection points (Dart resolves cross-file via `import`, so no
|
|
528
|
+
// namespace query is needed — the import rung already reaches the impl).
|
|
529
|
+
typeRefs: [
|
|
530
|
+
"(formal_parameter (type_identifier) @typeref)",
|
|
531
|
+
"(declaration (type_identifier) @typeref)"
|
|
532
|
+
],
|
|
469
533
|
heritage: [
|
|
470
534
|
"(superclass (type_identifier) @extends)",
|
|
471
535
|
"(interfaces (type_identifier) @implements)",
|
|
@@ -609,7 +673,10 @@ var OBJC = {
|
|
|
609
673
|
// (param names sit inside method_parameter); the first segment names it.
|
|
610
674
|
{ kind: "method", query: "(method_definition (identifier) @name) @def" },
|
|
611
675
|
{ kind: "class", query: "(class_implementation . (identifier) @name) @def" },
|
|
612
|
-
{ kind: "interface", query: "(class_interface . (identifier) @name) @def" }
|
|
676
|
+
{ kind: "interface", query: "(class_interface . (identifier) @name) @def" },
|
|
677
|
+
// A @protocol is Objective-C's interface — without this it is not a node, so
|
|
678
|
+
// conformance and protocol-typed DI cannot resolve.
|
|
679
|
+
{ kind: "interface", query: "(protocol_declaration (identifier) @name) @def" }
|
|
613
680
|
],
|
|
614
681
|
calls: [
|
|
615
682
|
"(call_expression function: (identifier) @callee)",
|
|
@@ -619,7 +686,13 @@ var OBJC = {
|
|
|
619
686
|
"(preproc_include path: (string_literal) @source)",
|
|
620
687
|
"(preproc_include path: (system_lib_string) @source)"
|
|
621
688
|
],
|
|
622
|
-
|
|
689
|
+
// Superclass (`: NSObject`) is `extends`; adopted protocols (`<Servicing>`,
|
|
690
|
+
// captured as parameterized_arguments after the interface name) are the
|
|
691
|
+
// `implements` relationship a DI call disambiguates through.
|
|
692
|
+
heritage: [
|
|
693
|
+
"(class_interface superclass: (identifier) @extends)",
|
|
694
|
+
"(class_interface (parameterized_arguments (type_name (type_identifier) @implements)))"
|
|
695
|
+
],
|
|
623
696
|
guards: ASSERT_CALLS
|
|
624
697
|
};
|
|
625
698
|
var OCAML = {
|
|
@@ -764,30 +837,6 @@ function mask(source, ranges, opts = {}) {
|
|
|
764
837
|
}
|
|
765
838
|
return out.join("");
|
|
766
839
|
}
|
|
767
|
-
var encoder = new TextEncoder();
|
|
768
|
-
function hashString(input) {
|
|
769
|
-
return bytesToHex(blake3(encoder.encode(input)));
|
|
770
|
-
}
|
|
771
|
-
function hashBytes(input) {
|
|
772
|
-
return bytesToHex(blake3(input));
|
|
773
|
-
}
|
|
774
|
-
function shortId(input) {
|
|
775
|
-
return bytesToHex(blake3(encoder.encode(input), { dkLen: 16 }));
|
|
776
|
-
}
|
|
777
|
-
function canonicalize(value) {
|
|
778
|
-
return JSON.stringify(sortKeys(value));
|
|
779
|
-
}
|
|
780
|
-
function sortKeys(value) {
|
|
781
|
-
if (Array.isArray(value)) return value.map(sortKeys);
|
|
782
|
-
if (value && typeof value === "object") {
|
|
783
|
-
const out = {};
|
|
784
|
-
for (const key of Object.keys(value).sort()) {
|
|
785
|
-
out[key] = sortKeys(value[key]);
|
|
786
|
-
}
|
|
787
|
-
return out;
|
|
788
|
-
}
|
|
789
|
-
return value;
|
|
790
|
-
}
|
|
791
840
|
|
|
792
841
|
// src/engine/parse.ts
|
|
793
842
|
var compiledCache = /* @__PURE__ */ new Map();
|
|
@@ -1028,6 +1077,17 @@ async function parseSource(rel, langId, source) {
|
|
|
1028
1077
|
}
|
|
1029
1078
|
}
|
|
1030
1079
|
result.typeRefs = typeRefs.sort((a, b) => a.byte - b.byte || a.name.localeCompare(b.name));
|
|
1080
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
1081
|
+
for (const qsrc of langQueries.namespaces ?? []) {
|
|
1082
|
+
const q = compile(language, effLangId, qsrc);
|
|
1083
|
+
if (!q) continue;
|
|
1084
|
+
for (const cap of q.captures(root)) {
|
|
1085
|
+
if (cap.name !== "namespace") continue;
|
|
1086
|
+
const name = cap.node.text.trim();
|
|
1087
|
+
if (name) namespaces.add(name);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (namespaces.size) result.namespaces = [...namespaces].sort();
|
|
1031
1091
|
const guards = [];
|
|
1032
1092
|
for (const qsrc of langQueries.guards ?? []) {
|
|
1033
1093
|
const q = compile(language, effLangId, qsrc);
|
|
@@ -1102,6 +1162,6 @@ function dedupeImports(imports) {
|
|
|
1102
1162
|
return out;
|
|
1103
1163
|
}
|
|
1104
1164
|
|
|
1105
|
-
export { LANGUAGES, allLanguageIds,
|
|
1106
|
-
//# sourceMappingURL=chunk-
|
|
1107
|
-
//# sourceMappingURL=chunk-
|
|
1165
|
+
export { LANGUAGES, allLanguageIds, grammarSetVersion, grammarsSourceDir, langById, langForExtension, parseSource, resolvedGrammarFiles, setGrammarsOverride };
|
|
1166
|
+
//# sourceMappingURL=chunk-PY3DNX5H.js.map
|
|
1167
|
+
//# sourceMappingURL=chunk-PY3DNX5H.js.map
|