brainbank 0.9.0 → 0.9.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/dist/{chunk-Z54MHEYW.js → chunk-6NM6WRDX.js} +6 -1
- package/dist/chunk-6NM6WRDX.js.map +1 -0
- package/dist/cli.js +203 -63
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/commands/help.ts +3 -0
- package/src/cli/commands/index.ts +37 -6
- package/src/cli/commands/mcp-export.ts +163 -0
- package/src/cli/index.ts +7 -0
- package/src/constants.ts +8 -0
- package/dist/chunk-Z54MHEYW.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SUPPORTED_EXTENSIONS,
|
|
4
|
+
VERSION,
|
|
4
5
|
args,
|
|
5
6
|
c,
|
|
6
7
|
createBrain,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
printResults,
|
|
16
17
|
registerConfigCollections,
|
|
17
18
|
stripFlags
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-6NM6WRDX.js";
|
|
19
20
|
import {
|
|
20
21
|
DEFAULT_PORT,
|
|
21
22
|
isServerRunning,
|
|
@@ -28,15 +29,121 @@ import {
|
|
|
28
29
|
} from "./chunk-7QVYU63E.js";
|
|
29
30
|
|
|
30
31
|
// src/cli/commands/index.ts
|
|
31
|
-
import * as
|
|
32
|
-
import * as
|
|
32
|
+
import * as fs3 from "fs";
|
|
33
|
+
import * as path3 from "path";
|
|
33
34
|
|
|
34
|
-
// src/cli/commands/
|
|
35
|
+
// src/cli/commands/mcp-export.ts
|
|
35
36
|
import * as fs from "fs";
|
|
36
37
|
import * as path from "path";
|
|
38
|
+
import { fileURLToPath } from "url";
|
|
39
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
40
|
+
var __dirname = path.dirname(__filename);
|
|
41
|
+
var TARGETS = {
|
|
42
|
+
antigravity: {
|
|
43
|
+
configPath: path.join(process.env.HOME ?? "~", ".gemini", "antigravity", "mcp_config.json"),
|
|
44
|
+
label: "Gemini Antigravity"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
function buildBrainbankMcpBlock(config) {
|
|
48
|
+
const nodeBin = process.execPath;
|
|
49
|
+
const globalCliJs = path.join(path.dirname(nodeBin), "..", "lib", "node_modules", "brainbank", "dist", "cli.js");
|
|
50
|
+
const localCliJs = path.resolve(__dirname, "..", "..", "dist", "cli.js");
|
|
51
|
+
const resolvedCliJs = fs.existsSync(globalCliJs) ? globalCliJs : localCliJs;
|
|
52
|
+
const env = {};
|
|
53
|
+
const keys = config?.keys;
|
|
54
|
+
const perplexityKey = keys?.perplexity ?? process.env.PERPLEXITY_API_KEY;
|
|
55
|
+
const anthropicKey = keys?.anthropic ?? process.env.ANTHROPIC_API_KEY;
|
|
56
|
+
const openaiKey = keys?.openai ?? process.env.OPENAI_API_KEY;
|
|
57
|
+
if (perplexityKey) env.PERPLEXITY_API_KEY = perplexityKey;
|
|
58
|
+
if (anthropicKey) env.ANTHROPIC_API_KEY = anthropicKey;
|
|
59
|
+
if (openaiKey) env.OPENAI_API_KEY = openaiKey;
|
|
60
|
+
const block = {
|
|
61
|
+
command: nodeBin,
|
|
62
|
+
args: [resolvedCliJs, "mcp"]
|
|
63
|
+
};
|
|
64
|
+
if (Object.keys(env).length > 0) {
|
|
65
|
+
block.env = env;
|
|
66
|
+
}
|
|
67
|
+
return block;
|
|
68
|
+
}
|
|
69
|
+
__name(buildBrainbankMcpBlock, "buildBrainbankMcpBlock");
|
|
70
|
+
function mergeAndWrite(targetPath, block) {
|
|
71
|
+
let existing = { mcpServers: {} };
|
|
72
|
+
const created = !fs.existsSync(targetPath);
|
|
73
|
+
if (!created) {
|
|
74
|
+
try {
|
|
75
|
+
const raw = fs.readFileSync(targetPath, "utf-8");
|
|
76
|
+
existing = JSON.parse(raw);
|
|
77
|
+
if (!existing.mcpServers) existing.mcpServers = {};
|
|
78
|
+
} catch {
|
|
79
|
+
existing = { mcpServers: {} };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
existing.mcpServers.brainbank = block;
|
|
83
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
84
|
+
fs.writeFileSync(targetPath, JSON.stringify(existing, null, 2) + "\n");
|
|
85
|
+
return { created };
|
|
86
|
+
}
|
|
87
|
+
__name(mergeAndWrite, "mergeAndWrite");
|
|
88
|
+
function hasBrainbankMcpEntry(targetPath) {
|
|
89
|
+
if (!fs.existsSync(targetPath)) return false;
|
|
90
|
+
try {
|
|
91
|
+
const raw = fs.readFileSync(targetPath, "utf-8");
|
|
92
|
+
const config = JSON.parse(raw);
|
|
93
|
+
return !!config.mcpServers?.brainbank;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
__name(hasBrainbankMcpEntry, "hasBrainbankMcpEntry");
|
|
99
|
+
async function autoExportMcp(repoPath) {
|
|
100
|
+
const target = TARGETS.antigravity;
|
|
101
|
+
if (!target) return;
|
|
102
|
+
const antigravityDir = path.dirname(target.configPath);
|
|
103
|
+
if (!fs.existsSync(antigravityDir)) return;
|
|
104
|
+
if (hasBrainbankMcpEntry(target.configPath)) return;
|
|
105
|
+
const config = await getConfig(repoPath);
|
|
106
|
+
const block = buildBrainbankMcpBlock(config);
|
|
107
|
+
mergeAndWrite(target.configPath, block);
|
|
108
|
+
console.log(` ${c.green("\u2713")} Exported MCP config to ${c.dim(path.relative(process.env.HOME ?? "", target.configPath))}`);
|
|
109
|
+
}
|
|
110
|
+
__name(autoExportMcp, "autoExportMcp");
|
|
111
|
+
async function cmdMcpExport() {
|
|
112
|
+
const targetName = args[1] || getFlag("target") || "antigravity";
|
|
113
|
+
const repoPath = getFlag("repo") || ".";
|
|
114
|
+
const target = TARGETS[targetName];
|
|
115
|
+
if (!target) {
|
|
116
|
+
console.error(c.red(`Unknown export target: ${targetName}`));
|
|
117
|
+
console.error(c.dim(` Available: ${Object.keys(TARGETS).join(", ")}`));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
const config = await getConfig(repoPath);
|
|
121
|
+
const block = buildBrainbankMcpBlock(config);
|
|
122
|
+
const { created } = mergeAndWrite(target.configPath, block);
|
|
123
|
+
console.log(c.bold(`
|
|
124
|
+
\u2501\u2501\u2501 MCP Export: ${target.label} \u2501\u2501\u2501
|
|
125
|
+
`));
|
|
126
|
+
console.log(` ${c.green("\u2713")} ${created ? "Created" : "Updated"} ${c.dim(target.configPath)}`);
|
|
127
|
+
console.log(` ${c.dim("Node:")} ${block.command}`);
|
|
128
|
+
console.log(` ${c.dim("CLI:")} ${block.args[0]}`);
|
|
129
|
+
const envKeys = block.env ? Object.keys(block.env) : [];
|
|
130
|
+
if (envKeys.length > 0) {
|
|
131
|
+
console.log(` ${c.dim("Keys:")} ${envKeys.join(", ")}`);
|
|
132
|
+
} else {
|
|
133
|
+
console.log(` ${c.yellow("\u26A0")} No API keys found. Set env vars or add keys to .brainbank/config.json`);
|
|
134
|
+
}
|
|
135
|
+
console.log(`
|
|
136
|
+
${c.dim("Restart your IDE to apply changes.")}
|
|
137
|
+
`);
|
|
138
|
+
}
|
|
139
|
+
__name(cmdMcpExport, "cmdMcpExport");
|
|
140
|
+
|
|
141
|
+
// src/cli/commands/scan.ts
|
|
142
|
+
import * as fs2 from "fs";
|
|
143
|
+
import * as path2 from "path";
|
|
37
144
|
import { execSync } from "child_process";
|
|
38
145
|
function scanRepo(repoPath) {
|
|
39
|
-
const resolved =
|
|
146
|
+
const resolved = path2.resolve(repoPath);
|
|
40
147
|
const gitSubdirs = scanGitSubdirs(resolved);
|
|
41
148
|
return {
|
|
42
149
|
repoPath: resolved,
|
|
@@ -61,15 +168,15 @@ function scanCodeModule(repoPath) {
|
|
|
61
168
|
function walk(dir) {
|
|
62
169
|
let entries;
|
|
63
170
|
try {
|
|
64
|
-
entries =
|
|
171
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
65
172
|
} catch {
|
|
66
173
|
return;
|
|
67
174
|
}
|
|
68
175
|
for (const entry of entries) {
|
|
69
|
-
const fullPath =
|
|
176
|
+
const fullPath = path2.join(dir, entry.name);
|
|
70
177
|
const isDir = entry.isDirectory() || entry.isSymbolicLink() && (() => {
|
|
71
178
|
try {
|
|
72
|
-
return
|
|
179
|
+
return fs2.statSync(fullPath).isDirectory();
|
|
73
180
|
} catch {
|
|
74
181
|
return false;
|
|
75
182
|
}
|
|
@@ -79,7 +186,7 @@ function scanCodeModule(repoPath) {
|
|
|
79
186
|
walk(fullPath);
|
|
80
187
|
} else if (entry.isFile()) {
|
|
81
188
|
if (isIgnoredFile(entry.name)) continue;
|
|
82
|
-
const ext =
|
|
189
|
+
const ext = path2.extname(entry.name).toLowerCase();
|
|
83
190
|
const lang = SUPPORTED_EXTENSIONS[ext];
|
|
84
191
|
if (!lang) continue;
|
|
85
192
|
byLanguage.set(lang, (byLanguage.get(lang) ?? 0) + 1);
|
|
@@ -158,7 +265,7 @@ function scanDocsModule(repoPath) {
|
|
|
158
265
|
}
|
|
159
266
|
__name(scanDocsModule, "scanDocsModule");
|
|
160
267
|
function scanGitStats(repoPath, gitSubdirs) {
|
|
161
|
-
if (
|
|
268
|
+
if (fs2.existsSync(path2.join(repoPath, ".git"))) {
|
|
162
269
|
return gitStats(repoPath);
|
|
163
270
|
}
|
|
164
271
|
if (gitSubdirs.length === 0) return null;
|
|
@@ -166,7 +273,7 @@ function scanGitStats(repoPath, gitSubdirs) {
|
|
|
166
273
|
let latestMessage = "";
|
|
167
274
|
let latestDate = "";
|
|
168
275
|
for (const sub of gitSubdirs) {
|
|
169
|
-
const stats = gitStats(
|
|
276
|
+
const stats = gitStats(path2.join(repoPath, sub.name));
|
|
170
277
|
if (stats) {
|
|
171
278
|
totalCommits += stats.commitCount;
|
|
172
279
|
if (!latestMessage) {
|
|
@@ -192,15 +299,15 @@ __name(gitStats, "gitStats");
|
|
|
192
299
|
function scanDocsCollections(repoPath) {
|
|
193
300
|
const results = [];
|
|
194
301
|
const seen = /* @__PURE__ */ new Set();
|
|
195
|
-
const configPath =
|
|
302
|
+
const configPath = path2.join(repoPath, ".brainbank", "config.json");
|
|
196
303
|
try {
|
|
197
|
-
if (
|
|
198
|
-
const config = JSON.parse(
|
|
304
|
+
if (fs2.existsSync(configPath)) {
|
|
305
|
+
const config = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
199
306
|
const docsCfg = config?.docs;
|
|
200
307
|
const collections = docsCfg?.collections;
|
|
201
308
|
if (collections) {
|
|
202
309
|
for (const coll of collections) {
|
|
203
|
-
const absPath =
|
|
310
|
+
const absPath = path2.resolve(repoPath, coll.path);
|
|
204
311
|
results.push({ name: coll.name, path: coll.path, fileCount: countDocs(absPath) });
|
|
205
312
|
seen.add(absPath);
|
|
206
313
|
}
|
|
@@ -213,11 +320,11 @@ function scanDocsCollections(repoPath) {
|
|
|
213
320
|
results.push({ name: "(root)", path: ".", fileCount: rootDocs });
|
|
214
321
|
}
|
|
215
322
|
try {
|
|
216
|
-
for (const entry of
|
|
323
|
+
for (const entry of fs2.readdirSync(repoPath, { withFileTypes: true })) {
|
|
217
324
|
if (!entry.isDirectory()) continue;
|
|
218
325
|
if (isIgnoredDir(entry.name)) continue;
|
|
219
326
|
if (entry.name.startsWith(".")) continue;
|
|
220
|
-
const dirPath =
|
|
327
|
+
const dirPath = path2.join(repoPath, entry.name);
|
|
221
328
|
if (seen.has(dirPath)) continue;
|
|
222
329
|
const count = countDocs(dirPath);
|
|
223
330
|
if (count > 0) {
|
|
@@ -232,11 +339,11 @@ __name(scanDocsCollections, "scanDocsCollections");
|
|
|
232
339
|
function countDocs(dir) {
|
|
233
340
|
let count = 0;
|
|
234
341
|
try {
|
|
235
|
-
for (const e of
|
|
236
|
-
const ePath =
|
|
342
|
+
for (const e of fs2.readdirSync(dir, { withFileTypes: true })) {
|
|
343
|
+
const ePath = path2.join(dir, e.name);
|
|
237
344
|
const isDir = e.isDirectory() || e.isSymbolicLink() && (() => {
|
|
238
345
|
try {
|
|
239
|
-
return
|
|
346
|
+
return fs2.statSync(ePath).isDirectory();
|
|
240
347
|
} catch {
|
|
241
348
|
return false;
|
|
242
349
|
}
|
|
@@ -256,7 +363,7 @@ __name(countDocs, "countDocs");
|
|
|
256
363
|
function countDocsShallow(dir) {
|
|
257
364
|
let count = 0;
|
|
258
365
|
try {
|
|
259
|
-
for (const e of
|
|
366
|
+
for (const e of fs2.readdirSync(dir, { withFileTypes: true })) {
|
|
260
367
|
if (e.isFile() && /\.mdx?$/i.test(e.name)) count++;
|
|
261
368
|
}
|
|
262
369
|
} catch {
|
|
@@ -265,10 +372,10 @@ function countDocsShallow(dir) {
|
|
|
265
372
|
}
|
|
266
373
|
__name(countDocsShallow, "countDocsShallow");
|
|
267
374
|
function scanConfig(repoPath) {
|
|
268
|
-
const configPath =
|
|
269
|
-
if (!
|
|
375
|
+
const configPath = path2.join(repoPath, ".brainbank", "config.json");
|
|
376
|
+
if (!fs2.existsSync(configPath)) return { exists: false };
|
|
270
377
|
try {
|
|
271
|
-
const config = JSON.parse(
|
|
378
|
+
const config = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
272
379
|
const codeCfg = config?.code;
|
|
273
380
|
return {
|
|
274
381
|
exists: true,
|
|
@@ -281,10 +388,10 @@ function scanConfig(repoPath) {
|
|
|
281
388
|
}
|
|
282
389
|
__name(scanConfig, "scanConfig");
|
|
283
390
|
function scanDb(repoPath) {
|
|
284
|
-
const dbPath =
|
|
285
|
-
if (!
|
|
391
|
+
const dbPath = path2.join(repoPath, ".brainbank", "data", "brainbank.db");
|
|
392
|
+
if (!fs2.existsSync(dbPath)) return { exists: false, sizeMB: 0 };
|
|
286
393
|
try {
|
|
287
|
-
const stat =
|
|
394
|
+
const stat = fs2.statSync(dbPath);
|
|
288
395
|
return {
|
|
289
396
|
exists: true,
|
|
290
397
|
sizeMB: Math.round(stat.size / 1024 / 1024 * 10) / 10,
|
|
@@ -296,19 +403,19 @@ function scanDb(repoPath) {
|
|
|
296
403
|
}
|
|
297
404
|
__name(scanDb, "scanDb");
|
|
298
405
|
function scanGitSubdirs(repoPath) {
|
|
299
|
-
if (
|
|
406
|
+
if (fs2.existsSync(path2.join(repoPath, ".git"))) return [];
|
|
300
407
|
try {
|
|
301
|
-
let subdirs =
|
|
408
|
+
let subdirs = fs2.readdirSync(repoPath, { withFileTypes: true }).filter((e) => {
|
|
302
409
|
if (e.name.startsWith(".")) return false;
|
|
303
410
|
const isDir = e.isDirectory() || e.isSymbolicLink() && (() => {
|
|
304
411
|
try {
|
|
305
|
-
return
|
|
412
|
+
return fs2.statSync(path2.join(repoPath, e.name)).isDirectory();
|
|
306
413
|
} catch {
|
|
307
414
|
return false;
|
|
308
415
|
}
|
|
309
416
|
})();
|
|
310
417
|
return isDir;
|
|
311
|
-
}).filter((e) =>
|
|
418
|
+
}).filter((e) => fs2.existsSync(path2.join(repoPath, e.name, ".git"))).map((e) => ({ name: e.name }));
|
|
312
419
|
const configRepos = readReposFromConfig(repoPath);
|
|
313
420
|
if (configRepos) {
|
|
314
421
|
subdirs = subdirs.filter((s) => configRepos.includes(s.name));
|
|
@@ -320,10 +427,10 @@ function scanGitSubdirs(repoPath) {
|
|
|
320
427
|
}
|
|
321
428
|
__name(scanGitSubdirs, "scanGitSubdirs");
|
|
322
429
|
function readReposFromConfig(repoPath) {
|
|
323
|
-
const configPath =
|
|
430
|
+
const configPath = path2.join(repoPath, ".brainbank", "config.json");
|
|
324
431
|
try {
|
|
325
|
-
if (!
|
|
326
|
-
const config = JSON.parse(
|
|
432
|
+
if (!fs2.existsSync(configPath)) return null;
|
|
433
|
+
const config = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
327
434
|
const repos = config.repos;
|
|
328
435
|
if (Array.isArray(repos) && repos.every((r) => typeof r === "string")) {
|
|
329
436
|
return repos;
|
|
@@ -383,8 +490,8 @@ async function cmdIndex() {
|
|
|
383
490
|
const config = await getConfig(repoPath);
|
|
384
491
|
await registerConfigCollections(brain, repoPath, config);
|
|
385
492
|
if (docsPath) {
|
|
386
|
-
const absDocsPath =
|
|
387
|
-
const collName =
|
|
493
|
+
const absDocsPath = path3.resolve(docsPath);
|
|
494
|
+
const collName = path3.basename(absDocsPath);
|
|
388
495
|
try {
|
|
389
496
|
const docsPlugin = findDocsPlugin(brain);
|
|
390
497
|
await docsPlugin?.addCollection({
|
|
@@ -428,6 +535,7 @@ async function cmdIndex() {
|
|
|
428
535
|
console.log(` ${name}: ${entries}`);
|
|
429
536
|
}
|
|
430
537
|
brain.close();
|
|
538
|
+
await autoExportMcp(repoPath);
|
|
431
539
|
}
|
|
432
540
|
__name(cmdIndex, "cmdIndex");
|
|
433
541
|
function printScanTree(scan, depth) {
|
|
@@ -506,7 +614,7 @@ function capitalizeFirst(s) {
|
|
|
506
614
|
}
|
|
507
615
|
__name(capitalizeFirst, "capitalizeFirst");
|
|
508
616
|
async function saveConfig(repoPath, modules) {
|
|
509
|
-
const { select } = await import("@inquirer/prompts");
|
|
617
|
+
const { select, confirm } = await import("@inquirer/prompts");
|
|
510
618
|
const envEmbedding = process.env.BRAINBANK_EMBEDDING;
|
|
511
619
|
const embedding = await select({
|
|
512
620
|
message: "Embedding provider:",
|
|
@@ -534,18 +642,18 @@ async function saveConfig(repoPath, modules) {
|
|
|
534
642
|
message: "Noise pruner:",
|
|
535
643
|
choices: [
|
|
536
644
|
{
|
|
537
|
-
name: "
|
|
538
|
-
value: "
|
|
645
|
+
name: "haiku \u2014 AI-powered noise filter (recommended)",
|
|
646
|
+
value: "haiku"
|
|
539
647
|
},
|
|
540
648
|
{
|
|
541
|
-
name: "
|
|
542
|
-
value: "
|
|
649
|
+
name: "none \u2014 no pruning",
|
|
650
|
+
value: "none"
|
|
543
651
|
}
|
|
544
652
|
],
|
|
545
|
-
default: "
|
|
653
|
+
default: "haiku"
|
|
546
654
|
});
|
|
547
|
-
const configDir =
|
|
548
|
-
const configPath =
|
|
655
|
+
const configDir = path3.join(repoPath, ".brainbank");
|
|
656
|
+
const configPath = path3.join(configDir, "config.json");
|
|
549
657
|
const config = {
|
|
550
658
|
plugins: modules,
|
|
551
659
|
embedding
|
|
@@ -553,9 +661,32 @@ async function saveConfig(repoPath, modules) {
|
|
|
553
661
|
if (pruner !== "none") {
|
|
554
662
|
config.pruner = pruner;
|
|
555
663
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
664
|
+
const detectedKeys = {};
|
|
665
|
+
const needsPerplexity = embedding.startsWith("perplexity");
|
|
666
|
+
const needsAnthropic = pruner === "haiku";
|
|
667
|
+
const needsOpenai = embedding === "openai";
|
|
668
|
+
if (needsPerplexity && process.env.PERPLEXITY_API_KEY) {
|
|
669
|
+
detectedKeys.perplexity = process.env.PERPLEXITY_API_KEY;
|
|
670
|
+
}
|
|
671
|
+
if (needsAnthropic && process.env.ANTHROPIC_API_KEY) {
|
|
672
|
+
detectedKeys.anthropic = process.env.ANTHROPIC_API_KEY;
|
|
673
|
+
}
|
|
674
|
+
if (needsOpenai && process.env.OPENAI_API_KEY) {
|
|
675
|
+
detectedKeys.openai = process.env.OPENAI_API_KEY;
|
|
676
|
+
}
|
|
677
|
+
if (Object.keys(detectedKeys).length > 0) {
|
|
678
|
+
const keyNames = Object.keys(detectedKeys).join(", ");
|
|
679
|
+
const saveKeys = await confirm({
|
|
680
|
+
message: `Save API keys (${keyNames}) to config.json? (portable, no env vars needed)`,
|
|
681
|
+
default: true
|
|
682
|
+
});
|
|
683
|
+
if (saveKeys) {
|
|
684
|
+
config.keys = detectedKeys;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
fs3.mkdirSync(configDir, { recursive: true });
|
|
688
|
+
fs3.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
689
|
+
console.log(c.green(` \u2713 Saved ${path3.relative(process.cwd(), configPath)}`));
|
|
559
690
|
}
|
|
560
691
|
__name(saveConfig, "saveConfig");
|
|
561
692
|
|
|
@@ -564,12 +695,12 @@ async function cmdCollection() {
|
|
|
564
695
|
const pos = stripFlags(args);
|
|
565
696
|
const sub = pos[1];
|
|
566
697
|
if (sub === "add") {
|
|
567
|
-
const
|
|
698
|
+
const path4 = pos[2];
|
|
568
699
|
const name = getFlag("name");
|
|
569
700
|
const pattern = getFlag("pattern") ?? "**/*.md";
|
|
570
701
|
const context = getFlag("context");
|
|
571
702
|
const ignoreRaw = getFlag("ignore");
|
|
572
|
-
if (!
|
|
703
|
+
if (!path4 || !name) {
|
|
573
704
|
console.log(c.red('Usage: brainbank collection add <path> --name <name> [--pattern "**/*.md"] [--ignore "glob"] [--context "description"]'));
|
|
574
705
|
process.exit(1);
|
|
575
706
|
}
|
|
@@ -581,12 +712,12 @@ async function cmdCollection() {
|
|
|
581
712
|
}
|
|
582
713
|
await docsPlugin.addCollection({
|
|
583
714
|
name,
|
|
584
|
-
path:
|
|
715
|
+
path: path4,
|
|
585
716
|
pattern,
|
|
586
717
|
ignore: ignoreRaw ? ignoreRaw.split(",") : [],
|
|
587
718
|
context: context ?? void 0
|
|
588
719
|
});
|
|
589
|
-
console.log(c.green(`\u2713 Collection '${name}' added: ${
|
|
720
|
+
console.log(c.green(`\u2713 Collection '${name}' added: ${path4} (${pattern})`));
|
|
590
721
|
if (context) console.log(c.dim(` Context: ${context}`));
|
|
591
722
|
brain.close();
|
|
592
723
|
return;
|
|
@@ -964,12 +1095,12 @@ async function serverHealth() {
|
|
|
964
1095
|
}
|
|
965
1096
|
}
|
|
966
1097
|
__name(serverHealth, "serverHealth");
|
|
967
|
-
function httpPost(port,
|
|
968
|
-
return new Promise((
|
|
1098
|
+
function httpPost(port, path4, body) {
|
|
1099
|
+
return new Promise((resolve4, reject) => {
|
|
969
1100
|
const req = http.request({
|
|
970
1101
|
hostname: "127.0.0.1",
|
|
971
1102
|
port,
|
|
972
|
-
path:
|
|
1103
|
+
path: path4,
|
|
973
1104
|
method: "POST",
|
|
974
1105
|
headers: {
|
|
975
1106
|
"Content-Type": "application/json",
|
|
@@ -980,7 +1111,7 @@ function httpPost(port, path3, body) {
|
|
|
980
1111
|
}, (res) => {
|
|
981
1112
|
const chunks = [];
|
|
982
1113
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
983
|
-
res.on("end", () =>
|
|
1114
|
+
res.on("end", () => resolve4(Buffer.concat(chunks).toString("utf8")));
|
|
984
1115
|
});
|
|
985
1116
|
req.on("error", reject);
|
|
986
1117
|
req.on("timeout", () => {
|
|
@@ -992,18 +1123,18 @@ function httpPost(port, path3, body) {
|
|
|
992
1123
|
});
|
|
993
1124
|
}
|
|
994
1125
|
__name(httpPost, "httpPost");
|
|
995
|
-
function httpGet(port,
|
|
996
|
-
return new Promise((
|
|
1126
|
+
function httpGet(port, path4) {
|
|
1127
|
+
return new Promise((resolve4, reject) => {
|
|
997
1128
|
const req = http.request({
|
|
998
1129
|
hostname: "127.0.0.1",
|
|
999
1130
|
port,
|
|
1000
|
-
path:
|
|
1131
|
+
path: path4,
|
|
1001
1132
|
method: "GET",
|
|
1002
1133
|
timeout: 5e3
|
|
1003
1134
|
}, (res) => {
|
|
1004
1135
|
const chunks = [];
|
|
1005
1136
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
1006
|
-
res.on("end", () =>
|
|
1137
|
+
res.on("end", () => resolve4(Buffer.concat(chunks).toString("utf8")));
|
|
1007
1138
|
});
|
|
1008
1139
|
req.on("error", reject);
|
|
1009
1140
|
req.on("timeout", () => {
|
|
@@ -1062,9 +1193,9 @@ async function cmdContext() {
|
|
|
1062
1193
|
const sub = pos[1];
|
|
1063
1194
|
if (sub === "add") {
|
|
1064
1195
|
const collection = pos[2];
|
|
1065
|
-
const
|
|
1196
|
+
const path4 = pos[3];
|
|
1066
1197
|
const desc = pos.slice(4).join(" ");
|
|
1067
|
-
if (!collection || !
|
|
1198
|
+
if (!collection || !path4 || !desc) {
|
|
1068
1199
|
console.log(c.red("Usage: brainbank context add <collection> <path> <description>"));
|
|
1069
1200
|
process.exit(1);
|
|
1070
1201
|
}
|
|
@@ -1075,8 +1206,8 @@ async function cmdContext() {
|
|
|
1075
1206
|
console.log(c.red("Docs plugin not loaded."));
|
|
1076
1207
|
process.exit(1);
|
|
1077
1208
|
}
|
|
1078
|
-
docsPlugin.addContext(collection,
|
|
1079
|
-
console.log(c.green(`\u2713 Context added: ${collection}:${
|
|
1209
|
+
docsPlugin.addContext(collection, path4, desc);
|
|
1210
|
+
console.log(c.green(`\u2713 Context added: ${collection}:${path4} \u2192 "${desc}"`));
|
|
1080
1211
|
brain2.close();
|
|
1081
1212
|
return;
|
|
1082
1213
|
}
|
|
@@ -1482,11 +1613,13 @@ function showHelp() {
|
|
|
1482
1613
|
console.log(` ${c.cyan("reembed")} Re-embed all vectors`);
|
|
1483
1614
|
console.log(` ${c.cyan("watch")} Watch files, auto-re-index`);
|
|
1484
1615
|
console.log(` ${c.cyan("mcp")} Start MCP server (stdio)`);
|
|
1616
|
+
console.log(` ${c.cyan("mcp:export")} [target] Export MCP config (antigravity)`);
|
|
1485
1617
|
console.log(` ${c.cyan("daemon")} Start HTTP daemon (foreground)`);
|
|
1486
1618
|
console.log(` ${c.cyan("daemon start")} Start HTTP daemon (background)`);
|
|
1487
1619
|
console.log(` ${c.cyan("daemon stop")} Stop background daemon`);
|
|
1488
1620
|
console.log(` ${c.cyan("daemon restart")} Restart background daemon`);
|
|
1489
1621
|
console.log(` ${c.cyan("status")} Show daemon status`);
|
|
1622
|
+
console.log(` ${c.cyan("--version")} ${c.dim("(-v)")} Show version`);
|
|
1490
1623
|
console.log("");
|
|
1491
1624
|
console.log(c.bold("Options:"));
|
|
1492
1625
|
console.log(` ${c.dim("--repo <path>")} Repository path (default: .)`);
|
|
@@ -1515,6 +1648,7 @@ function showHelp() {
|
|
|
1515
1648
|
console.log(c.dim(' brainbank context "auth flow" | pbcopy # \u2192 clipboard'));
|
|
1516
1649
|
console.log(c.dim(" brainbank daemon start # background HTTP"));
|
|
1517
1650
|
console.log(c.dim(" brainbank mcp # MCP stdio"));
|
|
1651
|
+
console.log(c.dim(" brainbank mcp:export antigravity # export MCP config"));
|
|
1518
1652
|
}
|
|
1519
1653
|
__name(showHelp, "showHelp");
|
|
1520
1654
|
|
|
@@ -1522,6 +1656,10 @@ __name(showHelp, "showHelp");
|
|
|
1522
1656
|
var command = args[0];
|
|
1523
1657
|
async function main() {
|
|
1524
1658
|
switch (command) {
|
|
1659
|
+
case "--version":
|
|
1660
|
+
case "-v":
|
|
1661
|
+
console.log(`brainbank v${VERSION}`);
|
|
1662
|
+
break;
|
|
1525
1663
|
case "i":
|
|
1526
1664
|
case "index":
|
|
1527
1665
|
return cmdIndex();
|
|
@@ -1551,6 +1689,8 @@ async function main() {
|
|
|
1551
1689
|
return cmdWatch();
|
|
1552
1690
|
case "mcp":
|
|
1553
1691
|
return cmdMcp();
|
|
1692
|
+
case "mcp:export":
|
|
1693
|
+
return cmdMcpExport();
|
|
1554
1694
|
case "serve":
|
|
1555
1695
|
return cmdMcp();
|
|
1556
1696
|
// backward compat
|