brainbank 0.1.0
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/LICENSE +21 -0
- package/README.md +1059 -0
- package/assets/architecture.png +0 -0
- package/bin/brainbank +11 -0
- package/dist/chunk-2P3EGY6S.js +37 -0
- package/dist/chunk-2P3EGY6S.js.map +1 -0
- package/dist/chunk-3GAIDXRW.js +105 -0
- package/dist/chunk-3GAIDXRW.js.map +1 -0
- package/dist/chunk-4ZKBQ33J.js +56 -0
- package/dist/chunk-4ZKBQ33J.js.map +1 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/chunk-EDKSKLX4.js +490 -0
- package/dist/chunk-EDKSKLX4.js.map +1 -0
- package/dist/chunk-GOUBW7UA.js +373 -0
- package/dist/chunk-GOUBW7UA.js.map +1 -0
- package/dist/chunk-MJ3Y24H6.js +185 -0
- package/dist/chunk-MJ3Y24H6.js.map +1 -0
- package/dist/chunk-N6ZMBFDE.js +224 -0
- package/dist/chunk-N6ZMBFDE.js.map +1 -0
- package/dist/chunk-YGSEUWLV.js +2053 -0
- package/dist/chunk-YGSEUWLV.js.map +1 -0
- package/dist/chunk-Z5SU54HP.js +171 -0
- package/dist/chunk-Z5SU54HP.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +731 -0
- package/dist/cli.js.map +1 -0
- package/dist/code.d.ts +31 -0
- package/dist/code.js +8 -0
- package/dist/code.js.map +1 -0
- package/dist/docs.d.ts +19 -0
- package/dist/docs.js +8 -0
- package/dist/docs.js.map +1 -0
- package/dist/git.d.ts +31 -0
- package/dist/git.js +8 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +845 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/memory.d.ts +19 -0
- package/dist/memory.js +146 -0
- package/dist/memory.js.map +1 -0
- package/dist/notes.d.ts +19 -0
- package/dist/notes.js +57 -0
- package/dist/notes.js.map +1 -0
- package/dist/openai-PCTYLOWI.js +8 -0
- package/dist/openai-PCTYLOWI.js.map +1 -0
- package/dist/types-Da_zLLOl.d.ts +474 -0
- package/package.json +91 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/indexers/git-indexer.ts
|
|
6
|
+
var GitIndexer = class {
|
|
7
|
+
static {
|
|
8
|
+
__name(this, "GitIndexer");
|
|
9
|
+
}
|
|
10
|
+
_deps;
|
|
11
|
+
_repoPath;
|
|
12
|
+
_maxDiffBytes;
|
|
13
|
+
constructor(repoPath, deps, maxDiffBytes = 8192) {
|
|
14
|
+
this._deps = deps;
|
|
15
|
+
this._repoPath = repoPath;
|
|
16
|
+
this._maxDiffBytes = maxDiffBytes;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Index git history.
|
|
20
|
+
* Only processes commits not already in the database.
|
|
21
|
+
*/
|
|
22
|
+
async index(options = {}) {
|
|
23
|
+
const { depth = 500, onProgress } = options;
|
|
24
|
+
let git2;
|
|
25
|
+
try {
|
|
26
|
+
const simpleGit = (await import("simple-git")).default;
|
|
27
|
+
git2 = simpleGit(this._repoPath);
|
|
28
|
+
} catch {
|
|
29
|
+
return { indexed: 0, skipped: 0 };
|
|
30
|
+
}
|
|
31
|
+
let log;
|
|
32
|
+
try {
|
|
33
|
+
log = await git2.log({ maxCount: depth });
|
|
34
|
+
} catch {
|
|
35
|
+
return { indexed: 0, skipped: 0 };
|
|
36
|
+
}
|
|
37
|
+
const commits = log.all;
|
|
38
|
+
let indexed = 0, skipped = 0;
|
|
39
|
+
for (let i = 0; i < commits.length; i++) {
|
|
40
|
+
const c = commits[i];
|
|
41
|
+
onProgress?.(`[${c.hash.slice(0, 7)}] ${c.message.slice(0, 50)}`, i + 1, commits.length);
|
|
42
|
+
const exists = this._deps.db.prepare(
|
|
43
|
+
"SELECT id FROM git_commits WHERE hash = ?"
|
|
44
|
+
).get(c.hash);
|
|
45
|
+
if (exists) {
|
|
46
|
+
skipped++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
let diff = "";
|
|
50
|
+
let additions = 0, deletions = 0;
|
|
51
|
+
const filesChanged = [];
|
|
52
|
+
try {
|
|
53
|
+
const stat = await git2.raw(["show", "--stat", "--format=", c.hash]);
|
|
54
|
+
for (const line of stat.trim().split("\n")) {
|
|
55
|
+
const m = line.match(/^\s+(.+?)\s+\|\s+(\d+)\s*([\+\-]*)/);
|
|
56
|
+
if (m) {
|
|
57
|
+
filesChanged.push(m[1].trim());
|
|
58
|
+
additions += (m[3].match(/\+/g) ?? []).length;
|
|
59
|
+
deletions += (m[3].match(/-/g) ?? []).length;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const rawDiff = await git2.raw(["show", "--format=", "--unified=3", "--no-color", c.hash]);
|
|
63
|
+
diff = rawDiff.length > this._maxDiffBytes ? rawDiff.slice(0, this._maxDiffBytes) + "\n... [truncated]" : rawDiff;
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
const isMerge = c.message.startsWith("Merge") || c.message.startsWith("merge");
|
|
67
|
+
const ts = Math.floor(new Date(c.date).getTime() / 1e3);
|
|
68
|
+
const result = this._deps.db.prepare(`
|
|
69
|
+
INSERT OR IGNORE INTO git_commits (hash, short_hash, message, author, date, timestamp, files_json, diff, additions, deletions, is_merge)
|
|
70
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
71
|
+
`).run(
|
|
72
|
+
c.hash,
|
|
73
|
+
c.hash.slice(0, 7),
|
|
74
|
+
c.message,
|
|
75
|
+
c.author_name,
|
|
76
|
+
c.date,
|
|
77
|
+
ts,
|
|
78
|
+
JSON.stringify(filesChanged),
|
|
79
|
+
diff || null,
|
|
80
|
+
additions,
|
|
81
|
+
deletions,
|
|
82
|
+
isMerge ? 1 : 0
|
|
83
|
+
);
|
|
84
|
+
if (result.changes === 0) {
|
|
85
|
+
skipped++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const commitId = Number(result.lastInsertRowid);
|
|
89
|
+
for (const f of filesChanged) {
|
|
90
|
+
this._deps.db.prepare(
|
|
91
|
+
"INSERT INTO commit_files (commit_id, file_path) VALUES (?, ?)"
|
|
92
|
+
).run(commitId, f);
|
|
93
|
+
}
|
|
94
|
+
const text = [
|
|
95
|
+
`Commit: ${c.message}`,
|
|
96
|
+
`Author: ${c.author_name}`,
|
|
97
|
+
`Date: ${c.date}`,
|
|
98
|
+
filesChanged.length > 0 ? `Files: ${filesChanged.join(", ")}` : "",
|
|
99
|
+
diff ? `Changes:
|
|
100
|
+
${diff.slice(0, 2e3)}` : ""
|
|
101
|
+
].filter(Boolean).join("\n");
|
|
102
|
+
const vec = await this._deps.embedding.embed(text);
|
|
103
|
+
this._deps.db.prepare(
|
|
104
|
+
"INSERT OR IGNORE INTO git_vectors (commit_id, embedding) VALUES (?, ?)"
|
|
105
|
+
).run(commitId, Buffer.from(vec.buffer));
|
|
106
|
+
this._deps.hnsw.add(vec, commitId);
|
|
107
|
+
this._deps.vectorCache.set(commitId, vec);
|
|
108
|
+
indexed++;
|
|
109
|
+
}
|
|
110
|
+
this._computeCoEdits();
|
|
111
|
+
return { indexed, skipped };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Compute which files tend to be edited together.
|
|
115
|
+
* Stored in the co_edits table for later suggestion.
|
|
116
|
+
*/
|
|
117
|
+
_computeCoEdits() {
|
|
118
|
+
const rows = this._deps.db.prepare(
|
|
119
|
+
"SELECT commit_id, file_path FROM commit_files ORDER BY commit_id"
|
|
120
|
+
).all();
|
|
121
|
+
const byCommit = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const r of rows) {
|
|
123
|
+
if (!byCommit.has(r.commit_id)) byCommit.set(r.commit_id, []);
|
|
124
|
+
byCommit.get(r.commit_id).push(r.file_path);
|
|
125
|
+
}
|
|
126
|
+
const counts = /* @__PURE__ */ new Map();
|
|
127
|
+
for (const files of byCommit.values()) {
|
|
128
|
+
if (files.length < 2 || files.length > 20) continue;
|
|
129
|
+
for (let i = 0; i < files.length; i++) {
|
|
130
|
+
for (let j = i + 1; j < files.length; j++) {
|
|
131
|
+
const key = [files[i], files[j]].sort().join("|||");
|
|
132
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (const [key, count] of counts) {
|
|
137
|
+
if (count < 2) continue;
|
|
138
|
+
const [a, b] = key.split("|||");
|
|
139
|
+
this._deps.db.prepare(
|
|
140
|
+
`INSERT INTO co_edits (file_a, file_b, count)
|
|
141
|
+
VALUES (?, ?, ?)
|
|
142
|
+
ON CONFLICT(file_a, file_b) DO UPDATE SET count = excluded.count`
|
|
143
|
+
).run(a, b, count);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// src/query/co-edits.ts
|
|
149
|
+
var CoEditAnalyzer = class {
|
|
150
|
+
constructor(_db) {
|
|
151
|
+
this._db = _db;
|
|
152
|
+
}
|
|
153
|
+
static {
|
|
154
|
+
__name(this, "CoEditAnalyzer");
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get files that frequently change alongside the given file.
|
|
158
|
+
* Returns sorted by co-edit count (highest first).
|
|
159
|
+
*/
|
|
160
|
+
suggest(filePath, limit = 5) {
|
|
161
|
+
const rows = this._db.prepare(`
|
|
162
|
+
SELECT
|
|
163
|
+
CASE WHEN file_a = ? THEN file_b ELSE file_a END AS file,
|
|
164
|
+
count
|
|
165
|
+
FROM co_edits
|
|
166
|
+
WHERE file_a = ? OR file_b = ?
|
|
167
|
+
ORDER BY count DESC
|
|
168
|
+
LIMIT ?
|
|
169
|
+
`).all(filePath, filePath, filePath, limit);
|
|
170
|
+
return rows.map((r) => ({ file: r.file, count: r.count }));
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// src/plugins/git.ts
|
|
175
|
+
var GitModuleImpl = class {
|
|
176
|
+
constructor(opts = {}) {
|
|
177
|
+
this.opts = opts;
|
|
178
|
+
this.name = opts.name ?? "git";
|
|
179
|
+
}
|
|
180
|
+
static {
|
|
181
|
+
__name(this, "GitModuleImpl");
|
|
182
|
+
}
|
|
183
|
+
name;
|
|
184
|
+
hnsw;
|
|
185
|
+
indexer;
|
|
186
|
+
coEdits;
|
|
187
|
+
vecCache = /* @__PURE__ */ new Map();
|
|
188
|
+
async initialize(ctx) {
|
|
189
|
+
const shared = await ctx.getOrCreateSharedHnsw("git", 5e5);
|
|
190
|
+
this.hnsw = shared.hnsw;
|
|
191
|
+
this.vecCache = shared.vecCache;
|
|
192
|
+
if (shared.isNew) {
|
|
193
|
+
ctx.loadVectors("git_vectors", "commit_id", this.hnsw, this.vecCache);
|
|
194
|
+
}
|
|
195
|
+
const repoPath = this.opts.repoPath ?? ctx.config.repoPath;
|
|
196
|
+
this.indexer = new GitIndexer(repoPath, {
|
|
197
|
+
db: ctx.db,
|
|
198
|
+
hnsw: this.hnsw,
|
|
199
|
+
vectorCache: this.vecCache,
|
|
200
|
+
embedding: ctx.embedding
|
|
201
|
+
}, this.opts.maxDiffBytes ?? ctx.config.maxDiffBytes);
|
|
202
|
+
this.coEdits = new CoEditAnalyzer(ctx.db);
|
|
203
|
+
}
|
|
204
|
+
async index(options = {}) {
|
|
205
|
+
return this.indexer.index(options);
|
|
206
|
+
}
|
|
207
|
+
suggest(filePath, limit = 5) {
|
|
208
|
+
return this.coEdits.suggest(filePath, limit);
|
|
209
|
+
}
|
|
210
|
+
stats() {
|
|
211
|
+
return { hnswSize: this.hnsw.size };
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
function git(opts) {
|
|
215
|
+
return new GitModuleImpl(opts);
|
|
216
|
+
}
|
|
217
|
+
__name(git, "git");
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
GitIndexer,
|
|
221
|
+
CoEditAnalyzer,
|
|
222
|
+
git
|
|
223
|
+
};
|
|
224
|
+
//# sourceMappingURL=chunk-N6ZMBFDE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/indexers/git-indexer.ts","../src/query/co-edits.ts","../src/plugins/git.ts"],"sourcesContent":["/**\n * BrainBank — Git Indexer\n * \n * Reads git history, embeds commit messages + diffs,\n * and computes file co-edit relationships.\n * Incremental: only processes new commits.\n */\n\nimport type { Database } from '../storage/database.ts';\nimport type { EmbeddingProvider, ProgressCallback, IndexResult } from '../types.ts';\nimport type { HNSWIndex } from '../vector/hnsw.ts';\n\nexport interface GitIndexerDeps {\n db: Database;\n hnsw: HNSWIndex;\n vectorCache: Map<number, Float32Array>;\n embedding: EmbeddingProvider;\n}\n\nexport interface GitIndexOptions {\n depth?: number;\n onProgress?: ProgressCallback;\n}\n\nexport class GitIndexer {\n private _deps: GitIndexerDeps;\n private _repoPath: string;\n private _maxDiffBytes: number;\n\n constructor(repoPath: string, deps: GitIndexerDeps, maxDiffBytes: number = 8192) {\n this._deps = deps;\n this._repoPath = repoPath;\n this._maxDiffBytes = maxDiffBytes;\n }\n\n /**\n * Index git history.\n * Only processes commits not already in the database.\n */\n async index(options: GitIndexOptions = {}): Promise<IndexResult> {\n const { depth = 500, onProgress } = options;\n\n let git: any;\n try {\n const simpleGit = (await import('simple-git')).default;\n git = simpleGit(this._repoPath);\n } catch {\n return { indexed: 0, skipped: 0 };\n }\n\n let log: any;\n try { log = await git.log({ maxCount: depth }); }\n catch { return { indexed: 0, skipped: 0 }; }\n\n const commits = log.all;\n let indexed = 0, skipped = 0;\n\n for (let i = 0; i < commits.length; i++) {\n const c = commits[i];\n onProgress?.(`[${c.hash.slice(0, 7)}] ${c.message.slice(0, 50)}`, i + 1, commits.length);\n\n // Skip if already indexed\n const exists = this._deps.db.prepare(\n 'SELECT id FROM git_commits WHERE hash = ?'\n ).get(c.hash);\n if (exists) { skipped++; continue; }\n\n // Get diff and stat\n let diff = '';\n let additions = 0, deletions = 0;\n const filesChanged: string[] = [];\n\n try {\n const stat = await git.raw(['show', '--stat', '--format=', c.hash]);\n for (const line of stat.trim().split('\\n')) {\n const m = line.match(/^\\s+(.+?)\\s+\\|\\s+(\\d+)\\s*([\\+\\-]*)/);\n if (m) {\n filesChanged.push(m[1].trim());\n additions += (m[3].match(/\\+/g) ?? []).length;\n deletions += (m[3].match(/-/g) ?? []).length;\n }\n }\n\n const rawDiff = await git.raw(['show', '--format=', '--unified=3', '--no-color', c.hash]);\n diff = rawDiff.length > this._maxDiffBytes\n ? rawDiff.slice(0, this._maxDiffBytes) + '\\n... [truncated]'\n : rawDiff;\n } catch {}\n\n const isMerge = c.message.startsWith('Merge') || c.message.startsWith('merge');\n const ts = Math.floor(new Date(c.date).getTime() / 1000);\n\n const result = this._deps.db.prepare(`\n INSERT OR IGNORE INTO git_commits (hash, short_hash, message, author, date, timestamp, files_json, diff, additions, deletions, is_merge)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n c.hash, c.hash.slice(0, 7), c.message, c.author_name, c.date,\n ts, JSON.stringify(filesChanged), diff || null,\n additions, deletions, isMerge ? 1 : 0,\n );\n\n if (result.changes === 0) { skipped++; continue; }\n const commitId = Number(result.lastInsertRowid);\n\n // Insert commit files\n for (const f of filesChanged) {\n this._deps.db.prepare(\n 'INSERT INTO commit_files (commit_id, file_path) VALUES (?, ?)'\n ).run(commitId, f);\n }\n\n // Embed: message + files + diff snippet\n const text = [\n `Commit: ${c.message}`,\n `Author: ${c.author_name}`,\n `Date: ${c.date}`,\n filesChanged.length > 0 ? `Files: ${filesChanged.join(', ')}` : '',\n diff ? `Changes:\\n${diff.slice(0, 2000)}` : '',\n ].filter(Boolean).join('\\n');\n\n const vec = await this._deps.embedding.embed(text);\n this._deps.db.prepare(\n 'INSERT OR IGNORE INTO git_vectors (commit_id, embedding) VALUES (?, ?)'\n ).run(commitId, Buffer.from(vec.buffer));\n\n this._deps.hnsw.add(vec, commitId);\n this._deps.vectorCache.set(commitId, vec);\n indexed++;\n }\n\n // Compute co-edits\n this._computeCoEdits();\n\n return { indexed, skipped };\n }\n\n /**\n * Compute which files tend to be edited together.\n * Stored in the co_edits table for later suggestion.\n */\n private _computeCoEdits(): void {\n const rows = this._deps.db.prepare(\n 'SELECT commit_id, file_path FROM commit_files ORDER BY commit_id'\n ).all() as any[];\n\n const byCommit = new Map<number, string[]>();\n for (const r of rows) {\n if (!byCommit.has(r.commit_id)) byCommit.set(r.commit_id, []);\n byCommit.get(r.commit_id)!.push(r.file_path);\n }\n\n const counts = new Map<string, number>();\n for (const files of byCommit.values()) {\n // Skip very small or very large changesets\n if (files.length < 2 || files.length > 20) continue;\n for (let i = 0; i < files.length; i++) {\n for (let j = i + 1; j < files.length; j++) {\n const key = [files[i], files[j]].sort().join('|||');\n counts.set(key, (counts.get(key) ?? 0) + 1);\n }\n }\n }\n\n for (const [key, count] of counts) {\n if (count < 2) continue;\n const [a, b] = key.split('|||');\n this._deps.db.prepare(\n `INSERT INTO co_edits (file_a, file_b, count)\n VALUES (?, ?, ?)\n ON CONFLICT(file_a, file_b) DO UPDATE SET count = excluded.count`\n ).run(a, b, count);\n }\n }\n}\n","/**\n * BrainBank — Co-Edit Analyzer\n * \n * Suggests files that historically change together.\n * Based on git commit co-occurrence analysis.\n */\n\nimport type { Database } from '../storage/database.ts';\nimport type { CoEditSuggestion } from '../types.ts';\n\nexport class CoEditAnalyzer {\n constructor(private _db: Database) {}\n\n /**\n * Get files that frequently change alongside the given file.\n * Returns sorted by co-edit count (highest first).\n */\n suggest(filePath: string, limit: number = 5): CoEditSuggestion[] {\n const rows = this._db.prepare(`\n SELECT\n CASE WHEN file_a = ? THEN file_b ELSE file_a END AS file,\n count\n FROM co_edits\n WHERE file_a = ? OR file_b = ?\n ORDER BY count DESC\n LIMIT ?\n `).all(filePath, filePath, filePath, limit) as any[];\n\n return rows.map(r => ({ file: r.file, count: r.count }));\n }\n}\n","/**\n * BrainBank — Git Module\n * \n * Git history indexing with co-edit relationships.\n * \n * import { git } from 'brainbank/git';\n * brain.use(git({ depth: 500 }));\n * \n * // Multi-repo: namespace to avoid key collisions\n * brain\n * .use(git({ repoPath: './frontend', name: 'git:frontend' }))\n * .use(git({ repoPath: './backend', name: 'git:backend' }));\n */\n\nimport type { BrainBankModule, ModuleContext } from './types.ts';\nimport type { HNSWIndex } from '../vector/hnsw.ts';\nimport { GitIndexer } from '../indexers/git-indexer.ts';\nimport { CoEditAnalyzer } from '../query/co-edits.ts';\nimport type { IndexResult, ProgressCallback, CoEditSuggestion } from '../types.ts';\n\nexport interface GitModuleOptions {\n /** Repository path. Default: from config */\n repoPath?: string;\n /** Max commits to index. Default: from config */\n depth?: number;\n /** Max diff bytes. Default: from config */\n maxDiffBytes?: number;\n /** Custom indexer name for multi-repo (e.g. 'git:frontend'). Default: 'git' */\n name?: string;\n}\n\nclass GitModuleImpl implements BrainBankModule {\n readonly name: string;\n hnsw!: HNSWIndex;\n indexer!: GitIndexer;\n coEdits!: CoEditAnalyzer;\n vecCache = new Map<number, Float32Array>();\n\n constructor(private opts: GitModuleOptions = {}) {\n this.name = opts.name ?? 'git';\n }\n\n async initialize(ctx: ModuleContext): Promise<void> {\n // Use shared HNSW so all git indexers share one index\n const shared = await ctx.getOrCreateSharedHnsw('git', 500_000);\n this.hnsw = shared.hnsw;\n this.vecCache = shared.vecCache;\n\n if (shared.isNew) {\n ctx.loadVectors('git_vectors', 'commit_id', this.hnsw, this.vecCache);\n }\n\n const repoPath = this.opts.repoPath ?? ctx.config.repoPath;\n this.indexer = new GitIndexer(repoPath, {\n db: ctx.db,\n hnsw: this.hnsw,\n vectorCache: this.vecCache,\n embedding: ctx.embedding,\n }, this.opts.maxDiffBytes ?? ctx.config.maxDiffBytes);\n\n this.coEdits = new CoEditAnalyzer(ctx.db);\n }\n\n async index(options: {\n depth?: number;\n onProgress?: ProgressCallback;\n } = {}): Promise<IndexResult> {\n return this.indexer.index(options);\n }\n\n suggest(filePath: string, limit: number = 5): CoEditSuggestion[] {\n return this.coEdits.suggest(filePath, limit);\n }\n\n stats(): Record<string, any> {\n return { hnswSize: this.hnsw.size };\n }\n}\n\n/** Create a git history module. */\nexport function git(opts?: GitModuleOptions): BrainBankModule {\n return new GitModuleImpl(opts);\n}\n"],"mappings":"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","names":["git"]}
|