brainbank 0.1.0-beta.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 (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/assets/architecture.png +0 -0
  4. package/bin/brainbank +18 -0
  5. package/bin/brainbank-mcp +19 -0
  6. package/dist/chunk-3YBCD6DI.js +117 -0
  7. package/dist/chunk-3YBCD6DI.js.map +1 -0
  8. package/dist/chunk-63GBCDS5.js +3249 -0
  9. package/dist/chunk-63GBCDS5.js.map +1 -0
  10. package/dist/chunk-DMFMTOHF.js +123 -0
  11. package/dist/chunk-DMFMTOHF.js.map +1 -0
  12. package/dist/chunk-FQYKWB2Q.js +136 -0
  13. package/dist/chunk-FQYKWB2Q.js.map +1 -0
  14. package/dist/chunk-IMJJ2VEM.js +74 -0
  15. package/dist/chunk-IMJJ2VEM.js.map +1 -0
  16. package/dist/chunk-M744PCJQ.js +43 -0
  17. package/dist/chunk-M744PCJQ.js.map +1 -0
  18. package/dist/chunk-O3J6ZIXK.js +82 -0
  19. package/dist/chunk-O3J6ZIXK.js.map +1 -0
  20. package/dist/chunk-OPH7GZ7U.js +124 -0
  21. package/dist/chunk-OPH7GZ7U.js.map +1 -0
  22. package/dist/chunk-PXEWQMN7.js +89 -0
  23. package/dist/chunk-PXEWQMN7.js.map +1 -0
  24. package/dist/chunk-RDQYDLYZ.js +69 -0
  25. package/dist/chunk-RDQYDLYZ.js.map +1 -0
  26. package/dist/chunk-VIIHPCC4.js +254 -0
  27. package/dist/chunk-VIIHPCC4.js.map +1 -0
  28. package/dist/chunk-WCQVDF3K.js +14 -0
  29. package/dist/chunk-WCQVDF3K.js.map +1 -0
  30. package/dist/cli.d.ts +1 -0
  31. package/dist/cli.js +3076 -0
  32. package/dist/cli.js.map +1 -0
  33. package/dist/haiku-expander-YRSIPGKP.js +8 -0
  34. package/dist/haiku-expander-YRSIPGKP.js.map +1 -0
  35. package/dist/haiku-pruner-SHAXUPY6.js +8 -0
  36. package/dist/haiku-pruner-SHAXUPY6.js.map +1 -0
  37. package/dist/http-server-QUXHLWUM.js +9 -0
  38. package/dist/http-server-QUXHLWUM.js.map +1 -0
  39. package/dist/index.d.ts +2161 -0
  40. package/dist/index.js +357 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/local-embedding-NZQTILGV.js +8 -0
  43. package/dist/local-embedding-NZQTILGV.js.map +1 -0
  44. package/dist/mcp.d.ts +2 -0
  45. package/dist/mcp.js +334 -0
  46. package/dist/mcp.js.map +1 -0
  47. package/dist/openai-embedding-ZP5TSUJG.js +8 -0
  48. package/dist/openai-embedding-ZP5TSUJG.js.map +1 -0
  49. package/dist/perplexity-context-embedding-GI5PHE6X.js +9 -0
  50. package/dist/perplexity-context-embedding-GI5PHE6X.js.map +1 -0
  51. package/dist/perplexity-embedding-KZRYGJRC.js +10 -0
  52. package/dist/perplexity-embedding-KZRYGJRC.js.map +1 -0
  53. package/dist/plugin-IKQ6IRSJ.js +32 -0
  54. package/dist/plugin-IKQ6IRSJ.js.map +1 -0
  55. package/dist/resolve-ASGLBNUC.js +10 -0
  56. package/dist/resolve-ASGLBNUC.js.map +1 -0
  57. package/dist/stats-tui-ZY2NQSEA.js +1904 -0
  58. package/dist/stats-tui-ZY2NQSEA.js.map +1 -0
  59. package/package.json +96 -0
  60. package/src/brainbank.ts +617 -0
  61. package/src/cli/commands/collection.ts +77 -0
  62. package/src/cli/commands/context.ts +179 -0
  63. package/src/cli/commands/daemon.ts +100 -0
  64. package/src/cli/commands/docs.ts +71 -0
  65. package/src/cli/commands/files.ts +69 -0
  66. package/src/cli/commands/help.ts +77 -0
  67. package/src/cli/commands/index.ts +482 -0
  68. package/src/cli/commands/kv.ts +140 -0
  69. package/src/cli/commands/mcp-export.ts +273 -0
  70. package/src/cli/commands/mcp.ts +6 -0
  71. package/src/cli/commands/reembed.ts +30 -0
  72. package/src/cli/commands/scan.ts +336 -0
  73. package/src/cli/commands/search.ts +203 -0
  74. package/src/cli/commands/stats.ts +68 -0
  75. package/src/cli/commands/status.ts +47 -0
  76. package/src/cli/commands/watch.ts +47 -0
  77. package/src/cli/factory/brain-context.ts +43 -0
  78. package/src/cli/factory/builtin-registration.ts +87 -0
  79. package/src/cli/factory/config-loader.ts +77 -0
  80. package/src/cli/factory/index.ts +69 -0
  81. package/src/cli/factory/plugin-loader.ts +325 -0
  82. package/src/cli/index.ts +71 -0
  83. package/src/cli/server-client.ts +178 -0
  84. package/src/cli/tui/index-tui.tsx +667 -0
  85. package/src/cli/tui/stats-data.ts +523 -0
  86. package/src/cli/tui/stats-search.ts +262 -0
  87. package/src/cli/tui/stats-tui.tsx +1465 -0
  88. package/src/cli/tui/tree-scanner.ts +650 -0
  89. package/src/cli/utils.ts +137 -0
  90. package/src/config.ts +49 -0
  91. package/src/constants.ts +21 -0
  92. package/src/db/adapter.ts +112 -0
  93. package/src/db/metadata.ts +130 -0
  94. package/src/db/migrations.ts +66 -0
  95. package/src/db/sqlite-adapter.ts +218 -0
  96. package/src/db/tracker.ts +91 -0
  97. package/src/engine/index-api.ts +81 -0
  98. package/src/engine/reembed.ts +206 -0
  99. package/src/engine/search-api.ts +218 -0
  100. package/src/index.ts +154 -0
  101. package/src/lib/fts.ts +57 -0
  102. package/src/lib/languages.ts +180 -0
  103. package/src/lib/logger.ts +126 -0
  104. package/src/lib/math.ts +87 -0
  105. package/src/lib/provider-key.ts +20 -0
  106. package/src/lib/prune.ts +71 -0
  107. package/src/lib/rrf.ts +133 -0
  108. package/src/lib/write-lock.ts +108 -0
  109. package/src/mcp/mcp-server.ts +195 -0
  110. package/src/mcp/workspace-factory.ts +68 -0
  111. package/src/mcp/workspace-pool.ts +224 -0
  112. package/src/plugin.ts +381 -0
  113. package/src/providers/embeddings/embedding-worker-thread.ts +95 -0
  114. package/src/providers/embeddings/embedding-worker.ts +141 -0
  115. package/src/providers/embeddings/local-embedding.ts +115 -0
  116. package/src/providers/embeddings/openai-embedding.ts +167 -0
  117. package/src/providers/embeddings/perplexity-context-embedding.ts +195 -0
  118. package/src/providers/embeddings/perplexity-embedding.ts +165 -0
  119. package/src/providers/embeddings/resolve.ts +34 -0
  120. package/src/providers/pruners/haiku-expander.ts +166 -0
  121. package/src/providers/pruners/haiku-pruner.ts +112 -0
  122. package/src/providers/vector/hnsw-index.ts +174 -0
  123. package/src/providers/vector/hnsw-loader.ts +129 -0
  124. package/src/search/bm25-boost.ts +69 -0
  125. package/src/search/context-builder.ts +251 -0
  126. package/src/search/keyword/composite-bm25-search.ts +47 -0
  127. package/src/search/types.ts +37 -0
  128. package/src/search/vector/composite-vector-search.ts +61 -0
  129. package/src/search/vector/mmr.ts +64 -0
  130. package/src/services/collection.ts +384 -0
  131. package/src/services/daemon.ts +87 -0
  132. package/src/services/http-server.ts +336 -0
  133. package/src/services/kv-service.ts +64 -0
  134. package/src/services/plugin-registry.ts +77 -0
  135. package/src/services/watch.ts +340 -0
  136. package/src/services/webhook-server.ts +100 -0
  137. package/src/types.ts +493 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * brainbank context <task> — Get formatted context for a task
3
+ * brainbank context add <collection> <path> <description>
4
+ * brainbank context list
5
+ *
6
+ * Source filtering (same as search commands):
7
+ * --code 20 Max code results (default: 20)
8
+ * --git 5 Max git results
9
+ * --no-git Skip git results
10
+ * --no-code Skip code results
11
+ * --path <dir> Filter results to files under path prefix(es) (comma-separated for multiple)
12
+ * --ignore <paths> Exclude paths (comma-separated or repeated: --ignore a,b --ignore c)
13
+ */
14
+
15
+ import { c, args, stripFlags, getFlag, getFlagAll, findDocsPlugin } from '@/cli/utils.ts';
16
+ import { createBrain } from '@/cli/factory/index.ts';
17
+ import { tryServerContext } from '@/cli/server-client.ts';
18
+
19
+ /** Parse --code N, --git N, --no-git, --no-code flags into sources map. */
20
+ function parseContextFlags(): Record<string, number> {
21
+ const NON_SOURCE = new Set([
22
+ 'repo', 'depth', 'collection', 'pattern', 'context', 'name',
23
+ 'keep', 'pruner', 'only', 'docs-path', 'mode', 'limit',
24
+ 'ignore', 'meta', 'k', 'yes', 'y', 'force', 'verbose', 'path',
25
+ ]);
26
+ const sources: Record<string, number> = {};
27
+ for (let i = 0; i < args.length; i++) {
28
+ if (!args[i].startsWith('--')) continue;
29
+ const name = args[i].slice(2);
30
+ // --no-git, --no-code → set to 0
31
+ if (name.startsWith('no-')) {
32
+ sources[name.slice(3)] = 0;
33
+ continue;
34
+ }
35
+ // --code 20, --git 5
36
+ const next = args[i + 1];
37
+ if (next !== undefined && /^\d+$/.test(next) && !NON_SOURCE.has(name)) {
38
+ sources[name] = parseInt(next, 10);
39
+ i++;
40
+ }
41
+ }
42
+ return sources;
43
+ }
44
+
45
+ export async function cmdContext(): Promise<void> {
46
+ const pos = stripFlags(args);
47
+ const sub = pos[1];
48
+
49
+ // brainbank context add <collection> <path> <description>
50
+ if (sub === 'add') {
51
+ const collection = pos[2];
52
+ const path = pos[3];
53
+ const desc = pos.slice(4).join(' ');
54
+
55
+ if (!collection || !path || !desc) {
56
+ console.log(c.red('Usage: brainbank context add <collection> <path> <description>'));
57
+ process.exit(1);
58
+ }
59
+
60
+ const brain = await createBrain();
61
+ await brain.initialize();
62
+ const docsPlugin = findDocsPlugin(brain);
63
+ if (!docsPlugin) { console.log(c.red('Docs plugin not loaded.')); process.exit(1); }
64
+ docsPlugin.addContext(collection, path, desc);
65
+ console.log(c.green(`✓ Context added: ${collection}:${path} → "${desc}"`));
66
+ brain.close();
67
+ return;
68
+ }
69
+
70
+ // brainbank context list
71
+ if (sub === 'list') {
72
+ const brain = await createBrain();
73
+ await brain.initialize();
74
+ const docsPlugin = findDocsPlugin(brain);
75
+ if (!docsPlugin) { console.log(c.yellow(' Docs plugin not loaded.')); brain.close(); return; }
76
+ const contexts = docsPlugin.listContexts();
77
+ if (contexts.length === 0) {
78
+ console.log(c.yellow(' No contexts configured.'));
79
+ } else {
80
+ console.log(c.bold('\n━━━ Contexts ━━━\n'));
81
+ for (const ctx of contexts) {
82
+ console.log(` ${c.cyan(ctx.collection)}:${ctx.path} → ${c.dim(ctx.context)}`);
83
+ }
84
+ }
85
+ brain.close();
86
+ return;
87
+ }
88
+
89
+ // brainbank context <task> — get formatted context
90
+ const task = stripFlags(args).slice(1).join(' ');
91
+ if (!task) {
92
+ console.log(c.red('Usage: brainbank context <task description>'));
93
+ console.log(c.dim(' brainbank context add <collection> <path> <description>'));
94
+ console.log(c.dim(' brainbank context list'));
95
+ process.exit(1);
96
+ }
97
+
98
+ const sources = parseContextFlags();
99
+ const rawPath = getFlag('path');
100
+ const pathPrefix = rawPath
101
+ ? rawPath.split(',').map(p => p.trim()).filter(Boolean)
102
+ : undefined;
103
+ // Normalize single-element array to string
104
+ const normalizedPath = pathPrefix && pathPrefix.length === 1 ? pathPrefix[0] : pathPrefix;
105
+ const ignorePaths = getFlagAll('ignore');
106
+ const repo = getFlag('repo');
107
+
108
+ // Parse BrainBankQL field flags
109
+ const fields = parseFieldFlags();
110
+
111
+ // Try HTTP server delegation first
112
+ const serverResult = await tryServerContext({
113
+ task,
114
+ repo: repo ?? process.cwd(),
115
+ sources: Object.keys(sources).length > 0 ? sources : undefined,
116
+ pathPrefix: normalizedPath,
117
+ });
118
+
119
+ if (serverResult !== null) {
120
+ console.log(serverResult);
121
+ return;
122
+ }
123
+
124
+ // Fall back to local
125
+ const brain = await createBrain();
126
+ const context = await brain.getContext(task, {
127
+ sources: Object.keys(sources).length > 0 ? sources : undefined,
128
+ pathPrefix: normalizedPath,
129
+ ignorePaths: ignorePaths.length > 0 ? ignorePaths : undefined,
130
+ source: 'cli',
131
+ fields: Object.keys(fields).length > 0 ? fields : undefined,
132
+ });
133
+ console.log(context);
134
+ brain.close();
135
+ }
136
+
137
+ /** Parse BrainBankQL field flags: --lines, --symbols, --compact, --no-callTree, --callTree.depth=N, etc. */
138
+ function parseFieldFlags(): Record<string, unknown> {
139
+ const FIELD_BOOLEANS = new Set(['lines', 'symbols', 'compact', 'expander']);
140
+ const FIELD_NEGATABLE = new Set(['callTree', 'imports']);
141
+ const fields: Record<string, unknown> = {};
142
+
143
+ for (let i = 0; i < args.length; i++) {
144
+ if (!args[i].startsWith('--')) continue;
145
+ const raw = args[i].slice(2);
146
+
147
+ // --no-callTree, --no-imports → set to false
148
+ if (raw.startsWith('no-')) {
149
+ const name = raw.slice(3);
150
+ if (FIELD_NEGATABLE.has(name)) {
151
+ fields[name] = false;
152
+ }
153
+ continue;
154
+ }
155
+
156
+ // --callTree.depth=4 → { depth: 4 }
157
+ const dotIdx = raw.indexOf('.');
158
+ if (dotIdx > 0) {
159
+ const fieldName = raw.slice(0, dotIdx);
160
+ const rest = raw.slice(dotIdx + 1);
161
+ const eqIdx = rest.indexOf('=');
162
+ if (eqIdx > 0) {
163
+ const key = rest.slice(0, eqIdx);
164
+ const val = parseInt(rest.slice(eqIdx + 1), 10);
165
+ if (!isNaN(val)) {
166
+ fields[fieldName] = { [key]: val };
167
+ }
168
+ }
169
+ continue;
170
+ }
171
+
172
+ // --lines, --symbols, --compact, --expander → true
173
+ if (FIELD_BOOLEANS.has(raw)) {
174
+ fields[raw] = true;
175
+ }
176
+ }
177
+
178
+ return fields;
179
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * brainbank daemon — HTTP daemon for CLI delegation.
3
+ *
4
+ * brainbank daemon → Start foreground
5
+ * brainbank daemon start → Start background (fork + PID file)
6
+ * brainbank daemon stop → Stop background daemon
7
+ * brainbank daemon restart → Stop + start
8
+ */
9
+
10
+ import { c, args, getFlag, stripFlags } from '@/cli/utils.ts';
11
+ import { isServerRunning, removePid, DEFAULT_PORT } from '@/services/daemon.ts';
12
+ import { createBrain } from '@/cli/factory/index.ts';
13
+
14
+ export async function cmdDaemon(): Promise<void> {
15
+ const pos = stripFlags(args);
16
+ const sub = pos[1]; // start | stop | undefined
17
+
18
+ if (sub === 'stop') return stopDaemon();
19
+ if (sub === 'restart') { stopDaemon(); return forkDaemon(); }
20
+ if (sub === 'start') return forkDaemon();
21
+ return startForeground();
22
+ }
23
+
24
+ // ── Foreground ──────────────────────────────────
25
+
26
+ async function startForeground(): Promise<void> {
27
+ const port = parseInt(getFlag('port') ?? String(DEFAULT_PORT), 10);
28
+ const { HttpServer } = await import('@/services/http-server.ts');
29
+
30
+ const server = new HttpServer({
31
+ port,
32
+ factory: async (repoPath: string) => {
33
+ const brain = await createBrain(repoPath);
34
+ await brain.initialize();
35
+ return brain;
36
+ },
37
+ onError: (repo, err) => {
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ console.error(c.red(` Pool error [${repo}]: ${msg}`));
40
+ },
41
+ onLog: (msg) => console.log(c.dim(` ${msg}`)),
42
+ });
43
+
44
+ console.log(c.bold('\n━━━ BrainBank HTTP Daemon ━━━\n'));
45
+
46
+ await server.start();
47
+
48
+ console.log(c.dim(` Port: ${port}`));
49
+ console.log(c.dim(' Press Ctrl+C to stop.\n'));
50
+
51
+ const shutdown = () => {
52
+ console.log(c.dim('\n Shutting down...'));
53
+ server.close();
54
+ process.exit(0);
55
+ };
56
+ process.on('SIGINT', shutdown);
57
+ process.on('SIGTERM', shutdown);
58
+
59
+ await new Promise(() => {});
60
+ }
61
+
62
+ // ── Background ──────────────────────────────────
63
+
64
+ async function forkDaemon(): Promise<void> {
65
+ const port = parseInt(getFlag('port') ?? String(DEFAULT_PORT), 10);
66
+ const { fork } = await import('node:child_process');
67
+
68
+ const existing = isServerRunning();
69
+ if (existing) {
70
+ console.log(c.yellow(` Daemon already running (PID ${existing.pid}, port ${existing.port})`));
71
+ return;
72
+ }
73
+
74
+ const child = fork(process.argv[1], ['daemon', '--port', String(port)], {
75
+ detached: true,
76
+ stdio: 'ignore',
77
+ });
78
+
79
+ child.unref();
80
+
81
+ console.log(c.green(` ✓ Daemon started (PID ${child.pid}, port ${port})`));
82
+ console.log(c.dim(' Stop with: brainbank daemon stop'));
83
+ }
84
+
85
+ function stopDaemon(): void {
86
+ const info = isServerRunning();
87
+ if (!info) {
88
+ console.log(c.yellow(' No daemon running.'));
89
+ return;
90
+ }
91
+
92
+ try {
93
+ process.kill(info.pid, 'SIGTERM');
94
+ removePid();
95
+ console.log(c.green(` ✓ Daemon stopped (PID ${info.pid})`));
96
+ } catch {
97
+ removePid();
98
+ console.log(c.yellow(` PID ${info.pid} not found. Cleaned up stale PID file.`));
99
+ }
100
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * brainbank docs — Index document collections
3
+ * brainbank dsearch — Search documents only
4
+ */
5
+
6
+ import { c, args, getFlag, stripFlags, findDocsPlugin } from '@/cli/utils.ts';
7
+ import { createBrain } from '@/cli/factory/index.ts';
8
+
9
+ export async function cmdDocs(): Promise<void> {
10
+ const collection = getFlag('collection');
11
+ const brain = await createBrain();
12
+
13
+ console.log(c.bold('\n━━━ BrainBank Docs Index ━━━\n'));
14
+
15
+ const opts: { collections?: string[]; onProgress?: (collection: string, file: string, current: number, total: number) => void } = {};
16
+ if (collection) opts.collections = [collection];
17
+ opts.onProgress = (col: string, file: string, cur: number, total: number) => {
18
+ process.stdout.write(`\r ${c.cyan(col)} [${cur}/${total}] ${file} `);
19
+ };
20
+
21
+ const docsPlugin = findDocsPlugin(brain);
22
+ if (!docsPlugin) { console.log(c.red(' Docs plugin not loaded. Install @brainbank/docs.')); process.exit(1); }
23
+
24
+ const results = await docsPlugin.indexDocs(opts);
25
+
26
+ console.log('\n');
27
+ for (const [name, stat] of Object.entries(results) as [string, { indexed: number; skipped: number; removed: number; chunks: number }][]) {
28
+ const removedStr = stat.removed > 0 ? `, ${c.red(String(stat.removed) + ' removed')}` : '';
29
+ console.log(` ${c.green(name)}: ${stat.indexed} indexed, ${stat.skipped} skipped${removedStr}, ${stat.chunks} chunks`);
30
+ }
31
+
32
+ brain.close();
33
+ }
34
+
35
+ export async function cmdDocSearch(): Promise<void> {
36
+ const query = stripFlags(args).slice(1).join(' ');
37
+ if (!query) {
38
+ console.log(c.red('Usage: brainbank dsearch <query>'));
39
+ process.exit(1);
40
+ }
41
+
42
+ const brain = await createBrain();
43
+ const collection = getFlag('collection');
44
+ const k = parseInt(getFlag('k') || '8', 10);
45
+
46
+ console.log(c.bold(`\n━━━ BrainBank Doc Search: "${query}" ━━━\n`));
47
+
48
+ const docsPlugin = findDocsPlugin(brain);
49
+ if (!docsPlugin) {
50
+ console.log(c.red('Docs plugin not loaded. Install @brainbank/docs.'));
51
+ process.exit(1);
52
+ }
53
+ const results = await docsPlugin.search(query, { collection: collection ?? undefined, k });
54
+
55
+ if (results.length === 0) {
56
+ console.log(c.yellow(' No results found.'));
57
+ brain.close();
58
+ return;
59
+ }
60
+
61
+ for (const r of results) {
62
+ const score = Math.round(r.score * 100);
63
+ const ctx = r.context ? ` — ${c.dim(r.context)}` : '';
64
+ console.log(`${c.magenta(`[DOC ${score}%]`)} ${c.bold(r.filePath!)} [${r.type === 'document' ? r.metadata.collection ?? '' : ''}]${ctx}`);
65
+ const preview = r.content.split('\n').slice(0, 4).join('\n');
66
+ console.log(c.dim(preview));
67
+ console.log('');
68
+ }
69
+
70
+ brain.close();
71
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * brainbank files <path|glob> [...paths] [--lines]
3
+ *
4
+ * Fetch full file contents from the index.
5
+ * Use after `brainbank context` to view complete files identified by search.
6
+ */
7
+
8
+ import { c, args, getFlag } from '@/cli/utils.ts';
9
+ import { createBrain } from '@/cli/factory/index.ts';
10
+
11
+ export async function cmdFiles(): Promise<void> {
12
+ // Collect positional args (file patterns) — skip 'files' command itself
13
+ const patterns: string[] = [];
14
+ const showLines = args.includes('--lines');
15
+
16
+ for (let i = 1; i < args.length; i++) {
17
+ if (args[i].startsWith('--')) {
18
+ // Skip --lines and --repo <value>
19
+ if (args[i] === '--repo') {
20
+ i++; // skip value
21
+ }
22
+ continue;
23
+ }
24
+ patterns.push(args[i]);
25
+ }
26
+
27
+ if (patterns.length === 0) {
28
+ console.log(c.red('Usage: brainbank files <path|glob> [...paths] [--lines]'));
29
+ console.log(c.dim(' Exact: brainbank files src/auth/login.ts'));
30
+ console.log(c.dim(' Directory: brainbank files src/graph/'));
31
+ console.log(c.dim(' Glob: brainbank files "src/**/*.service.ts"'));
32
+ console.log(c.dim(' Fuzzy: brainbank files plugin.ts'));
33
+ console.log(c.dim(' Lines: brainbank files src/plugin.ts --lines'));
34
+ process.exit(1);
35
+ }
36
+
37
+ const brain = await createBrain();
38
+ await brain.initialize();
39
+ const results = brain.resolveFiles(patterns);
40
+
41
+ if (results.length === 0) {
42
+ console.log(c.yellow('No matching files found in the index.'));
43
+ console.log(c.dim('Run `brainbank index` first to index your codebase.'));
44
+ brain.close();
45
+ return;
46
+ }
47
+
48
+ // Format output
49
+ for (const r of results) {
50
+ const meta = r.metadata as Record<string, unknown>;
51
+ const startLine = (meta.startLine as number) ?? 1;
52
+
53
+ console.log(c.bold(`\n── ${r.filePath} ──\n`));
54
+
55
+ if (showLines) {
56
+ const codeLines = r.content.split('\n');
57
+ const pad = String(startLine + codeLines.length - 1).length;
58
+ for (let i = 0; i < codeLines.length; i++) {
59
+ const lineNum = c.dim(`${String(startLine + i).padStart(pad)}|`);
60
+ console.log(`${lineNum} ${codeLines[i]}`);
61
+ }
62
+ } else {
63
+ console.log(r.content);
64
+ }
65
+ }
66
+
67
+ console.log(c.dim(`\n${results.length} file(s) resolved.`));
68
+ brain.close();
69
+ }
@@ -0,0 +1,77 @@
1
+ /** brainbank help — Show CLI usage. */
2
+
3
+ import { c } from '@/cli/utils.ts';
4
+
5
+ export function showHelp(): void {
6
+ console.log(c.bold('\n━━━ BrainBank — Semantic Knowledge Bank ━━━\n'));
7
+ console.log(c.bold('Indexing:'));
8
+ console.log(` ${c.cyan('index')} ${c.dim('(i)')} [path] Index code + git history`);
9
+ console.log(` ${c.cyan('collection add')} <path> --name Add a document collection`);
10
+ console.log(` ${c.cyan('collection list')} List collections`);
11
+ console.log(` ${c.cyan('collection remove')} <name> Remove a collection`);
12
+ console.log(` ${c.cyan('docs')} [--collection <name>] Index document collections`);
13
+ console.log('');
14
+ console.log(c.bold('Search:'));
15
+ console.log(` ${c.cyan('search')} <query> Semantic search (vector)`);
16
+ console.log(` ${c.cyan('hsearch')} <query> Hybrid search (${c.bold('best quality')})`);
17
+ console.log(` ${c.cyan('ksearch')} <query> Keyword search (BM25, instant)`);
18
+ console.log(` ${c.cyan('dsearch')} <query> Document search`);
19
+ console.log(c.dim(' All accept --repo <path> --path <dir> --<source> <n>'));
20
+ console.log('');
21
+ console.log(c.bold('Context:'));
22
+ console.log(` ${c.cyan('context')} <task> Get formatted context for a task`);
23
+ console.log(` ${c.cyan('context add')} <col> <path> <desc> Add context metadata`);
24
+ console.log(` ${c.cyan('context list')} List all context metadata`);
25
+ console.log(` ${c.cyan('files')} <path|glob> [...] [--lines] View full indexed files directly`);
26
+ console.log('');
27
+ console.log(c.bold('KV Store:'));
28
+ console.log(` ${c.cyan('kv add')} <coll> <content> Add item to a collection`);
29
+ console.log(` ${c.cyan('kv search')} <coll> <query> Search a collection`);
30
+ console.log(` ${c.cyan('kv list')} [coll] List collections or items`);
31
+ console.log(` ${c.cyan('kv trim')} <coll> --keep <n> Keep only N most recent`);
32
+ console.log(` ${c.cyan('kv clear')} <coll> Clear all items`);
33
+ console.log('');
34
+ console.log(c.bold('Utility:'));
35
+ console.log(` ${c.cyan('stats')} Show index statistics`);
36
+ console.log(` ${c.cyan('reembed')} Re-embed all vectors`);
37
+ console.log(` ${c.cyan('watch')} Watch files, auto-re-index`);
38
+ console.log(` ${c.cyan('mcp')} Start MCP server (stdio)`);
39
+ console.log(` ${c.cyan('mcp:export')} [target] Export MCP config (antigravity)`);
40
+ console.log(` ${c.cyan('daemon')} Start HTTP daemon (foreground)`);
41
+ console.log(` ${c.cyan('daemon start')} Start HTTP daemon (background)`);
42
+ console.log(` ${c.cyan('daemon stop')} Stop background daemon`);
43
+ console.log(` ${c.cyan('daemon restart')} Restart background daemon`);
44
+ console.log(` ${c.cyan('status')} Show daemon status`);
45
+ console.log(` ${c.cyan('--version')} ${c.dim('(-v)')} Show version`);
46
+ console.log('');
47
+ console.log(c.bold('Options:'));
48
+ console.log(` ${c.dim('--repo <path>')} Repository path (default: .)`);
49
+ console.log(` ${c.dim('--force')} Force re-index all files`);
50
+ console.log(` ${c.dim('--depth <n>')} Git history depth (default: 500)`);
51
+ console.log(` ${c.dim('--collection <name>')} Filter by collection`);
52
+ console.log(` ${c.dim('--pattern <glob>')} Collection glob (default: **/*.md)`);
53
+ console.log(` ${c.dim('--context <desc>')} Context description`);
54
+ console.log(` ${c.dim('--<source> <n>')} Source filter: max results from <source> (0 = skip)`);
55
+ console.log(` ${c.dim('--path <dir>')} Filter context results to files under this path prefix`);
56
+ console.log(` ${c.dim('--ignore <globs>')} Ignore glob patterns for code indexing (comma-separated)`);
57
+ console.log(` ${c.dim('--include <globs>')} Include only these paths for code indexing (comma-separated)`);
58
+ console.log(` ${c.dim('--yes / -y')} Skip interactive prompt (auto-select all available)`);
59
+ console.log(` ${c.dim('--setup')} Re-run interactive setup (modules, folders, config)`);
60
+ console.log(` ${c.dim('--port <n>')} HTTP daemon port (default: 8181)`);
61
+ console.log('');
62
+ console.log(c.bold('Examples:'));
63
+ console.log(c.dim(' brainbank index .'));
64
+ console.log(c.dim(' brainbank index . --ignore "sdk/**,vendor/**"'));
65
+ console.log(c.dim(' brainbank index . --include "src/**,lib/**"'));
66
+ console.log(c.dim(' brainbank kv add errors "Fixed null pointer in api.ts"'));
67
+ console.log(c.dim(' brainbank kv search errors "null pointer"'));
68
+ console.log(c.dim(' brainbank kv list'));
69
+ console.log(c.dim(' brainbank hsearch "authentication middleware"'));
70
+ console.log(c.dim(' brainbank hsearch "auth" --code 0 --git 10 # git only'));
71
+ console.log(c.dim(' brainbank search "handler" --git 0 # code only'));
72
+ console.log(c.dim(' brainbank hsearch "api" --docs 10 --code 0 --git 0 # docs only'));
73
+ console.log(c.dim(' brainbank context "auth flow" | pbcopy # → clipboard'));
74
+ console.log(c.dim(' brainbank daemon start # background HTTP'));
75
+ console.log(c.dim(' brainbank mcp # MCP stdio'));
76
+ console.log(c.dim(' brainbank mcp:export antigravity # export MCP config'));
77
+ }