@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.
Files changed (67) hide show
  1. package/DOCS.md +185 -0
  2. package/README.md +2 -1
  3. package/dist/baseline-J44M7MWP.js +7 -0
  4. package/dist/{baseline-KK7ZLRZB.js.map → baseline-J44M7MWP.js.map} +1 -1
  5. package/dist/chunk-2EVQKZTO.js +696 -0
  6. package/dist/chunk-2EVQKZTO.js.map +1 -0
  7. package/dist/chunk-6CXTPC74.js +234 -0
  8. package/dist/chunk-6CXTPC74.js.map +1 -0
  9. package/dist/chunk-CRAMOEBE.js +675 -0
  10. package/dist/chunk-CRAMOEBE.js.map +1 -0
  11. package/dist/chunk-CS37OBE3.js +861 -0
  12. package/dist/chunk-CS37OBE3.js.map +1 -0
  13. package/dist/chunk-CT5BS56U.js +23 -0
  14. package/dist/chunk-CT5BS56U.js.map +1 -0
  15. package/dist/{chunk-MUMBLIDO.js → chunk-EXQV26MF.js} +4 -3
  16. package/dist/chunk-EXQV26MF.js.map +1 -0
  17. package/dist/chunk-GGJZA3Q6.js +961 -0
  18. package/dist/chunk-GGJZA3Q6.js.map +1 -0
  19. package/dist/chunk-JBXNQCGE.js +484 -0
  20. package/dist/chunk-JBXNQCGE.js.map +1 -0
  21. package/dist/chunk-JFGYT6BI.js +32 -0
  22. package/dist/chunk-JFGYT6BI.js.map +1 -0
  23. package/dist/{chunk-NHLSAZ6N.js → chunk-JSNHZCIV.js} +42 -71
  24. package/dist/chunk-JSNHZCIV.js.map +1 -0
  25. package/dist/chunk-JYS4OBN2.js +148 -0
  26. package/dist/chunk-JYS4OBN2.js.map +1 -0
  27. package/dist/chunk-K3SLGULW.js +50 -0
  28. package/dist/chunk-K3SLGULW.js.map +1 -0
  29. package/dist/chunk-LEPTUB4H.js +108 -0
  30. package/dist/chunk-LEPTUB4H.js.map +1 -0
  31. package/dist/{chunk-JWBS5GS6.js → chunk-PY3DNX5H.js} +94 -34
  32. package/dist/chunk-PY3DNX5H.js.map +1 -0
  33. package/dist/{chunk-3DPZQS2Q.js → chunk-VXT6LUGP.js} +356 -2532
  34. package/dist/chunk-VXT6LUGP.js.map +1 -0
  35. package/dist/chunk-WNIIKCNF.js +972 -0
  36. package/dist/chunk-WNIIKCNF.js.map +1 -0
  37. package/dist/chunk-XKXKWYJF.js +417 -0
  38. package/dist/chunk-XKXKWYJF.js.map +1 -0
  39. package/dist/cli.js +2479 -1234
  40. package/dist/cli.js.map +1 -1
  41. package/dist/fs-KCABDURV.js +3 -0
  42. package/dist/fs-KCABDURV.js.map +1 -0
  43. package/dist/index.d.ts +5 -3
  44. package/dist/index.js +8 -3
  45. package/dist/index.js.map +1 -1
  46. package/dist/interactive-736PBC7J.js +820 -0
  47. package/dist/interactive-736PBC7J.js.map +1 -0
  48. package/dist/mcp-tools-I6PME3AV.js +3 -0
  49. package/dist/mcp-tools-I6PME3AV.js.map +1 -0
  50. package/dist/parse-worker.d.ts +1 -1
  51. package/dist/parse-worker.js +2 -1
  52. package/dist/parse-worker.js.map +1 -1
  53. package/dist/session-POJUDFPH.js +6 -0
  54. package/dist/session-POJUDFPH.js.map +1 -0
  55. package/dist/session-store-W5RZZHA3.js +3 -0
  56. package/dist/session-store-W5RZZHA3.js.map +1 -0
  57. package/dist/stream-json-Q2JGWPHB.js +65 -0
  58. package/dist/stream-json-Q2JGWPHB.js.map +1 -0
  59. package/dist/{types-BgNa-FZQ.d.ts → types-Jl6RJ175.d.ts} +8 -0
  60. package/dist/ui-HOVOPWMX.js +4 -0
  61. package/dist/ui-HOVOPWMX.js.map +1 -0
  62. package/package.json +3 -2
  63. package/dist/baseline-KK7ZLRZB.js +0 -6
  64. package/dist/chunk-3DPZQS2Q.js.map +0 -1
  65. package/dist/chunk-JWBS5GS6.js.map +0 -1
  66. package/dist/chunk-MUMBLIDO.js.map +0 -1
  67. 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":"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","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":"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","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: ["(invocation_expression function: (member_access_expression name: (identifier) @callee))", "(invocation_expression function: (identifier) @callee)"],
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
- heritage: ["(class_interface superclass: (identifier) @extends)"],
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, canonicalize, grammarSetVersion, grammarsSourceDir, hashBytes, hashString, langById, langForExtension, parseSource, resolvedGrammarFiles, setGrammarsOverride, shortId };
1106
- //# sourceMappingURL=chunk-JWBS5GS6.js.map
1107
- //# sourceMappingURL=chunk-JWBS5GS6.js.map
1165
+ export { LANGUAGES, allLanguageIds, grammarSetVersion, grammarsSourceDir, langById, langForExtension, parseSource, resolvedGrammarFiles, setGrammarsOverride };
1166
+ //# sourceMappingURL=chunk-PY3DNX5H.js.map
1167
+ //# sourceMappingURL=chunk-PY3DNX5H.js.map