brainbank 0.1.3 → 0.1.4

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 (167) hide show
  1. package/README.md +84 -1107
  2. package/assets/architecture.png +0 -0
  3. package/bin/brainbank +8 -1
  4. package/bin/brainbank-mcp +19 -0
  5. package/dist/chunk-3UIWA32X.js +3341 -0
  6. package/dist/chunk-3UIWA32X.js.map +1 -0
  7. package/dist/chunk-3YBCD6DI.js +117 -0
  8. package/dist/chunk-3YBCD6DI.js.map +1 -0
  9. package/dist/chunk-DAGVUEXL.js +258 -0
  10. package/dist/chunk-DAGVUEXL.js.map +1 -0
  11. package/dist/chunk-DMFMTOHF.js +123 -0
  12. package/dist/chunk-DMFMTOHF.js.map +1 -0
  13. package/dist/chunk-FQYKWB2Q.js +136 -0
  14. package/dist/chunk-FQYKWB2Q.js.map +1 -0
  15. package/dist/chunk-IMJJ2VEM.js +74 -0
  16. package/dist/chunk-IMJJ2VEM.js.map +1 -0
  17. package/dist/chunk-M744PCJQ.js +43 -0
  18. package/dist/chunk-M744PCJQ.js.map +1 -0
  19. package/dist/chunk-NNDY7P2R.js +211 -0
  20. package/dist/chunk-NNDY7P2R.js.map +1 -0
  21. package/dist/chunk-O3J6ZIXK.js +82 -0
  22. package/dist/chunk-O3J6ZIXK.js.map +1 -0
  23. package/dist/chunk-RDQYDLYZ.js +69 -0
  24. package/dist/chunk-RDQYDLYZ.js.map +1 -0
  25. package/dist/chunk-WCQVDF3K.js +14 -0
  26. package/dist/cli.js +2713 -325
  27. package/dist/cli.js.map +1 -1
  28. package/dist/haiku-pruner-5KVT5AI2.js +8 -0
  29. package/dist/http-server-2ZQ6I43B.js +9 -0
  30. package/dist/index.d.ts +1886 -626
  31. package/dist/index.js +319 -46
  32. package/dist/index.js.map +1 -1
  33. package/dist/local-embedding-NZQTILGV.js +8 -0
  34. package/dist/mcp.d.ts +2 -0
  35. package/dist/mcp.js +386 -0
  36. package/dist/mcp.js.map +1 -0
  37. package/dist/openai-embedding-ZP5TSUJG.js +8 -0
  38. package/dist/perplexity-context-embedding-GI5PHE6X.js +9 -0
  39. package/dist/perplexity-context-embedding-GI5PHE6X.js.map +1 -0
  40. package/dist/perplexity-embedding-KZRYGJRC.js +10 -0
  41. package/dist/perplexity-embedding-KZRYGJRC.js.map +1 -0
  42. package/dist/plugin-IKQ6IRSJ.js +32 -0
  43. package/dist/plugin-IKQ6IRSJ.js.map +1 -0
  44. package/dist/resolve-ASGLBNUC.js +10 -0
  45. package/dist/resolve-ASGLBNUC.js.map +1 -0
  46. package/dist/stats-tui-AD3AMYGV.js +1904 -0
  47. package/dist/stats-tui-AD3AMYGV.js.map +1 -0
  48. package/package.json +38 -53
  49. package/src/brainbank.ts +617 -0
  50. package/src/cli/commands/collection.ts +77 -0
  51. package/src/cli/commands/context.ts +59 -0
  52. package/src/cli/commands/daemon.ts +100 -0
  53. package/src/cli/commands/docs.ts +71 -0
  54. package/src/cli/commands/files.ts +69 -0
  55. package/src/cli/commands/help.ts +82 -0
  56. package/src/cli/commands/index.ts +478 -0
  57. package/src/cli/commands/kv.ts +140 -0
  58. package/src/cli/commands/mcp-export.ts +273 -0
  59. package/src/cli/commands/mcp.ts +6 -0
  60. package/src/cli/commands/query.ts +167 -0
  61. package/src/cli/commands/reembed.ts +30 -0
  62. package/src/cli/commands/reindex.ts +40 -0
  63. package/src/cli/commands/scan.ts +336 -0
  64. package/src/cli/commands/search.ts +203 -0
  65. package/src/cli/commands/stats.ts +68 -0
  66. package/src/cli/commands/status.ts +47 -0
  67. package/src/cli/commands/watch.ts +47 -0
  68. package/src/cli/factory/brain-context.ts +43 -0
  69. package/src/cli/factory/builtin-registration.ts +87 -0
  70. package/src/cli/factory/config-loader.ts +77 -0
  71. package/src/cli/factory/index.ts +69 -0
  72. package/src/cli/factory/plugin-loader.ts +324 -0
  73. package/src/cli/index.ts +76 -0
  74. package/src/cli/server-client.ts +186 -0
  75. package/src/cli/tui/index-tui.tsx +667 -0
  76. package/src/cli/tui/stats-data.ts +523 -0
  77. package/src/cli/tui/stats-search.ts +262 -0
  78. package/src/cli/tui/stats-tui.tsx +1465 -0
  79. package/src/cli/tui/tree-scanner.ts +650 -0
  80. package/src/cli/utils.ts +137 -0
  81. package/src/config.ts +48 -0
  82. package/src/constants.ts +21 -0
  83. package/src/db/adapter.ts +112 -0
  84. package/src/db/metadata.ts +130 -0
  85. package/src/db/migrations.ts +66 -0
  86. package/src/db/sqlite-adapter.ts +218 -0
  87. package/src/db/tracker.ts +91 -0
  88. package/src/engine/index-api.ts +81 -0
  89. package/src/engine/reembed.ts +206 -0
  90. package/src/engine/search-api.ts +218 -0
  91. package/src/index.ts +150 -0
  92. package/src/lib/fts.ts +57 -0
  93. package/src/lib/languages.ts +179 -0
  94. package/src/lib/logger.ts +126 -0
  95. package/src/lib/math.ts +87 -0
  96. package/src/lib/provider-key.ts +20 -0
  97. package/src/lib/prune.ts +72 -0
  98. package/src/lib/rrf.ts +133 -0
  99. package/src/lib/write-lock.ts +108 -0
  100. package/src/mcp/mcp-server.ts +268 -0
  101. package/src/mcp/workspace-factory.ts +68 -0
  102. package/src/mcp/workspace-pool.ts +224 -0
  103. package/src/plugin.ts +381 -0
  104. package/src/providers/embeddings/embedding-worker-thread.ts +95 -0
  105. package/src/providers/embeddings/embedding-worker.ts +141 -0
  106. package/src/providers/embeddings/local-embedding.ts +115 -0
  107. package/src/providers/embeddings/openai-embedding.ts +167 -0
  108. package/src/providers/embeddings/perplexity-context-embedding.ts +195 -0
  109. package/src/providers/embeddings/perplexity-embedding.ts +165 -0
  110. package/src/providers/embeddings/resolve.ts +34 -0
  111. package/src/providers/pruners/haiku-expander.ts +178 -0
  112. package/src/providers/pruners/haiku-pruner.ts +263 -0
  113. package/src/providers/vector/hnsw-index.ts +174 -0
  114. package/src/providers/vector/hnsw-loader.ts +129 -0
  115. package/src/search/bm25-boost.ts +76 -0
  116. package/src/search/context-builder.ts +209 -0
  117. package/src/search/keyword/composite-bm25-search.ts +47 -0
  118. package/src/search/query-decomposer.ts +124 -0
  119. package/src/search/types.ts +37 -0
  120. package/src/search/vector/composite-vector-search.ts +105 -0
  121. package/src/search/vector/mmr.ts +64 -0
  122. package/src/services/collection.ts +384 -0
  123. package/src/services/daemon.ts +87 -0
  124. package/src/services/http-server.ts +344 -0
  125. package/src/services/kv-service.ts +64 -0
  126. package/src/services/plugin-registry.ts +77 -0
  127. package/src/services/watch.ts +340 -0
  128. package/src/services/webhook-server.ts +100 -0
  129. package/src/types.ts +509 -0
  130. package/dist/chunk-2P3EGY6S.js +0 -37
  131. package/dist/chunk-2P3EGY6S.js.map +0 -1
  132. package/dist/chunk-3GAIDXRW.js +0 -105
  133. package/dist/chunk-3GAIDXRW.js.map +0 -1
  134. package/dist/chunk-4ZKBQ33J.js +0 -56
  135. package/dist/chunk-4ZKBQ33J.js.map +0 -1
  136. package/dist/chunk-7QVYU63E.js +0 -7
  137. package/dist/chunk-GOUBW7UA.js +0 -373
  138. package/dist/chunk-GOUBW7UA.js.map +0 -1
  139. package/dist/chunk-MJ3Y24H6.js +0 -185
  140. package/dist/chunk-MJ3Y24H6.js.map +0 -1
  141. package/dist/chunk-N6ZMBFDE.js +0 -224
  142. package/dist/chunk-N6ZMBFDE.js.map +0 -1
  143. package/dist/chunk-RAEBYV75.js +0 -709
  144. package/dist/chunk-RAEBYV75.js.map +0 -1
  145. package/dist/chunk-TW5NTYYZ.js +0 -2066
  146. package/dist/chunk-TW5NTYYZ.js.map +0 -1
  147. package/dist/chunk-Z5SU54HP.js +0 -171
  148. package/dist/chunk-Z5SU54HP.js.map +0 -1
  149. package/dist/code.d.ts +0 -31
  150. package/dist/code.js +0 -8
  151. package/dist/docs.d.ts +0 -19
  152. package/dist/docs.js +0 -8
  153. package/dist/git.d.ts +0 -31
  154. package/dist/git.js +0 -8
  155. package/dist/memory.d.ts +0 -19
  156. package/dist/memory.js +0 -146
  157. package/dist/memory.js.map +0 -1
  158. package/dist/notes.d.ts +0 -19
  159. package/dist/notes.js +0 -57
  160. package/dist/notes.js.map +0 -1
  161. package/dist/openai-PCTYLOWI.js +0 -8
  162. package/dist/types-Da_zLLOl.d.ts +0 -474
  163. /package/dist/{chunk-7QVYU63E.js.map → chunk-WCQVDF3K.js.map} +0 -0
  164. /package/dist/{code.js.map → haiku-pruner-5KVT5AI2.js.map} +0 -0
  165. /package/dist/{docs.js.map → http-server-2ZQ6I43B.js.map} +0 -0
  166. /package/dist/{git.js.map → local-embedding-NZQTILGV.js.map} +0 -0
  167. /package/dist/{openai-PCTYLOWI.js.map → openai-embedding-ZP5TSUJG.js.map} +0 -0
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ /**
5
+ * BrainBank — CLI Entry Point
6
+ *
7
+ * Dispatcher that routes commands to their handler modules.
8
+ */
9
+
10
+ import { args, c } from './utils.ts';
11
+ import { cmdIndex } from './commands/index.ts';
12
+ import { cmdCollection } from './commands/collection.ts';
13
+ import { cmdKv } from './commands/kv.ts';
14
+ import { cmdDocs, cmdDocSearch } from './commands/docs.ts';
15
+ import { cmdSearch, cmdHybridSearch, cmdKeywordSearch } from './commands/search.ts';
16
+ import { cmdContext } from './commands/context.ts';
17
+ import { cmdQuery } from './commands/query.ts';
18
+ import { cmdFiles } from './commands/files.ts';
19
+ import { cmdStats } from './commands/stats.ts';
20
+ import { cmdReembed } from './commands/reembed.ts';
21
+ import { cmdReindex } from './commands/reindex.ts';
22
+ import { cmdWatch } from './commands/watch.ts';
23
+ import { cmdMcp } from './commands/mcp.ts';
24
+ import { cmdMcpExport } from './commands/mcp-export.ts';
25
+ import { cmdDaemon } from './commands/daemon.ts';
26
+ import { cmdStatus } from './commands/status.ts';
27
+ import { showHelp } from './commands/help.ts';
28
+ import { VERSION } from '@/constants.ts';
29
+
30
+ const command = args[0];
31
+
32
+ async function main(): Promise<void> {
33
+ switch (command) {
34
+ case '--version':
35
+ case '-v':
36
+ console.log(`brainbank v${VERSION}`);
37
+ break;
38
+ case 'i':
39
+ case 'index': return cmdIndex();
40
+ case 'collection': return cmdCollection();
41
+ case 'kv': return cmdKv();
42
+ case 'docs': return cmdDocs();
43
+ case 'dsearch': return cmdDocSearch();
44
+ case 'search': return cmdSearch();
45
+ case 'hsearch': return cmdHybridSearch();
46
+ case 'ksearch': return cmdKeywordSearch();
47
+ case 'context': return cmdContext();
48
+ case 'q':
49
+ case 'query': return cmdQuery();
50
+ case 'files': return cmdFiles();
51
+ case 'stats': return cmdStats();
52
+ case 'reembed': return cmdReembed();
53
+ case 'reindex': return cmdReindex();
54
+ case 'watch': return cmdWatch();
55
+ case 'mcp': return cmdMcp();
56
+ case 'mcp:export': return cmdMcpExport();
57
+ case 'serve': return cmdMcp(); // backward compat
58
+ case 'daemon': return cmdDaemon();
59
+ case 'status': return cmdStatus();
60
+ case 'help':
61
+ case '--help':
62
+ case '-h':
63
+ showHelp();
64
+ break;
65
+ default:
66
+ if (command) console.log(c.red(`Unknown command: ${command}\n`));
67
+ showHelp();
68
+ process.exit(command ? 1 : 0);
69
+ }
70
+ }
71
+
72
+ main().catch(err => {
73
+ console.error(c.red(`Error: ${err.message}`));
74
+ if (process.env.BRAINBANK_DEBUG) console.error(err.stack);
75
+ process.exit(1);
76
+ });
@@ -0,0 +1,186 @@
1
+ /**
2
+ * ServerClient — Lightweight HTTP client for the BrainBank daemon.
3
+ *
4
+ * Used by CLI commands to delegate to a running HTTP server
5
+ * instead of loading models locally. Falls back gracefully
6
+ * (returns null) if the server is unreachable.
7
+ */
8
+
9
+ import type { SearchResult } from '@/types.ts';
10
+
11
+ import * as http from 'node:http';
12
+
13
+ import { isServerRunning } from '@/services/daemon.ts';
14
+
15
+ interface ContextOptions {
16
+ task: string;
17
+ repo?: string;
18
+ sources?: Record<string, number>;
19
+ pathPrefix?: string | string[];
20
+ ignorePaths?: string[];
21
+ affectedFiles?: string[];
22
+ fields?: Record<string, unknown>;
23
+ context?: string;
24
+ prunerContext?: string;
25
+ }
26
+
27
+ /**
28
+ * Try to get context from the running HTTP server.
29
+ * Returns the context string if successful, null if server is unreachable.
30
+ */
31
+ export async function tryServerContext(options: ContextOptions): Promise<string | null> {
32
+ const info = isServerRunning();
33
+ if (!info) return null;
34
+
35
+ try {
36
+ const body = JSON.stringify({
37
+ task: options.task,
38
+ repo: options.repo,
39
+ sources: options.sources,
40
+ pathPrefix: options.pathPrefix,
41
+ ignorePaths: options.ignorePaths,
42
+ affectedFiles: options.affectedFiles,
43
+ fields: options.fields,
44
+ context: options.context,
45
+ prunerContext: options.prunerContext,
46
+ });
47
+
48
+ const response = await httpPost(info.port, '/context', body);
49
+ const data = JSON.parse(response) as { context?: string; error?: string };
50
+
51
+ if (data.error) return null;
52
+ return data.context ?? null;
53
+ } catch {
54
+ // Server unreachable or error — fall back to local
55
+ return null;
56
+ }
57
+ }
58
+
59
+ interface SearchDelegateOptions {
60
+ query: string;
61
+ repo?: string;
62
+ sources?: Record<string, number>;
63
+ pathPrefix?: string | string[];
64
+ maxResults?: number;
65
+ }
66
+
67
+ /**
68
+ * Try to delegate a search to the running HTTP server.
69
+ * Mode: 'search' (vector), 'hybrid' (hsearch), 'keyword' (ksearch).
70
+ * Returns SearchResult[] if successful, null if server is unreachable.
71
+ */
72
+ export async function tryServerSearch(
73
+ mode: 'search' | 'hybrid' | 'keyword',
74
+ options: SearchDelegateOptions,
75
+ ): Promise<SearchResult[] | null> {
76
+ const info = isServerRunning();
77
+ if (!info) return null;
78
+
79
+ const endpoint = mode === 'search' ? '/search' : mode === 'hybrid' ? '/hsearch' : '/ksearch';
80
+
81
+ try {
82
+ const body = JSON.stringify({
83
+ query: options.query,
84
+ repo: options.repo,
85
+ sources: options.sources,
86
+ pathPrefix: options.pathPrefix,
87
+ maxResults: options.maxResults,
88
+ });
89
+
90
+ const response = await httpPost(info.port, endpoint, body);
91
+ const data = JSON.parse(response) as { results?: SearchResult[]; error?: string };
92
+
93
+ if (data.error) return null;
94
+ return data.results ?? null;
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Try to trigger indexing on the running HTTP server.
102
+ * Returns the result if successful, null if server is unreachable.
103
+ */
104
+ export async function tryServerIndex(repo?: string, forceReindex?: boolean): Promise<Record<string, unknown> | null> {
105
+ const info = isServerRunning();
106
+ if (!info) return null;
107
+
108
+ try {
109
+ const body = JSON.stringify({ repo, forceReindex });
110
+ const response = await httpPost(info.port, '/index', body);
111
+ const data = JSON.parse(response) as { result?: Record<string, unknown>; error?: string };
112
+
113
+ if (data.error) return null;
114
+ return data.result ?? null;
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Check server health. Returns health info or null.
122
+ */
123
+ export async function serverHealth(): Promise<{
124
+ ok: boolean;
125
+ pid: number;
126
+ port: number;
127
+ uptime: number;
128
+ workspaces: number;
129
+ } | null> {
130
+ const info = isServerRunning();
131
+ if (!info) return null;
132
+
133
+ try {
134
+ const response = await httpGet(info.port, '/health');
135
+ return JSON.parse(response) as { ok: boolean; pid: number; port: number; uptime: number; workspaces: number };
136
+ } catch {
137
+ return null;
138
+ }
139
+ }
140
+
141
+ // ── HTTP helpers ────────────────────────────────────
142
+
143
+ function httpPost(port: number, path: string, body: string): Promise<string> {
144
+ return new Promise((resolve, reject) => {
145
+ const req = http.request({
146
+ hostname: '127.0.0.1',
147
+ port,
148
+ path,
149
+ method: 'POST',
150
+ headers: {
151
+ 'Content-Type': 'application/json',
152
+ 'Content-Length': Buffer.byteLength(body),
153
+ },
154
+ timeout: 120_000, // 2 minutes — context queries can be slow on first load
155
+ }, (res) => {
156
+ const chunks: Buffer[] = [];
157
+ res.on('data', (chunk: Buffer) => chunks.push(chunk));
158
+ res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
159
+ });
160
+
161
+ req.on('error', reject);
162
+ req.on('timeout', () => { req.destroy(); reject(new Error('Request timed out')); });
163
+ req.write(body);
164
+ req.end();
165
+ });
166
+ }
167
+
168
+ function httpGet(port: number, path: string): Promise<string> {
169
+ return new Promise((resolve, reject) => {
170
+ const req = http.request({
171
+ hostname: '127.0.0.1',
172
+ port,
173
+ path,
174
+ method: 'GET',
175
+ timeout: 5_000,
176
+ }, (res) => {
177
+ const chunks: Buffer[] = [];
178
+ res.on('data', (chunk: Buffer) => chunks.push(chunk));
179
+ res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
180
+ });
181
+
182
+ req.on('error', reject);
183
+ req.on('timeout', () => { req.destroy(); reject(new Error('Request timed out')); });
184
+ req.end();
185
+ });
186
+ }