brainbank 0.7.0 → 0.8.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/README.md +76 -1398
- package/bin/brainbank +5 -1
- package/dist/{chunk-N2OJRXSB.js → chunk-3HVCONGF.js} +1 -1
- package/dist/{chunk-N2OJRXSB.js.map → chunk-3HVCONGF.js.map} +1 -1
- package/dist/{chunk-CCXVL56V.js → chunk-3JZIM5AU.js} +6 -3
- package/dist/chunk-3JZIM5AU.js.map +1 -0
- package/dist/{chunk-6XOXM7MI.js → chunk-5KU2PP34.js} +2 -2
- package/dist/{chunk-6XOXM7MI.js.map → chunk-5KU2PP34.js.map} +1 -1
- package/dist/chunk-7JDCHUJV.js +89 -0
- package/dist/chunk-7JDCHUJV.js.map +1 -0
- package/dist/{chunk-B77KABWH.js → chunk-7T2ZCZQA.js} +17 -15
- package/dist/chunk-7T2ZCZQA.js.map +1 -0
- package/dist/chunk-E3J37GDA.js +74 -0
- package/dist/chunk-E3J37GDA.js.map +1 -0
- package/dist/chunk-JEFWMS5Z.js +217 -0
- package/dist/chunk-JEFWMS5Z.js.map +1 -0
- package/dist/chunk-JRVYSTMP.js +3256 -0
- package/dist/chunk-JRVYSTMP.js.map +1 -0
- package/dist/chunk-OLDHLOMT.js +69 -0
- package/dist/chunk-OLDHLOMT.js.map +1 -0
- package/dist/{chunk-424UFCY7.js → chunk-QTZNB6AK.js} +6 -2
- package/dist/chunk-QTZNB6AK.js.map +1 -0
- package/dist/chunk-RFF7HMP6.js +109 -0
- package/dist/chunk-RFF7HMP6.js.map +1 -0
- package/dist/{chunk-ZNLN2VWV.js → chunk-TD3TEFI3.js} +1 -1
- package/dist/chunk-TD3TEFI3.js.map +1 -0
- package/dist/cli.js +1036 -341
- package/dist/cli.js.map +1 -1
- package/dist/haiku-expander-WOVJIVXD.js +8 -0
- package/dist/haiku-pruner-DB77ZQLJ.js +8 -0
- package/dist/http-server-GIRELCCL.js +9 -0
- package/dist/index.d.ts +1774 -611
- package/dist/index.js +282 -70
- package/dist/index.js.map +1 -1
- package/dist/{local-embedding-ZIMTK6PU.js → local-embedding-2RNCC5EU.js} +2 -2
- package/dist/{openai-embedding-VQZCZQYT.js → openai-embedding-Z5I4K4CN.js} +2 -2
- package/dist/perplexity-context-embedding-V5YUMXDR.js +9 -0
- package/dist/{perplexity-embedding-227WQY4R.js → perplexity-embedding-X2S72OAC.js} +2 -2
- package/dist/plugin-FF4Q34TI.js +32 -0
- package/dist/{qwen3-reranker-3MHEENT5.js → qwen3-reranker-HVIQOLKS.js} +2 -2
- package/dist/{resolve-CUJWY6HP.js → resolve-Q5D6HECY.js} +2 -2
- package/package.json +25 -52
- package/src/brainbank.ts +620 -0
- package/src/cli/commands/collection.ts +77 -0
- package/src/cli/commands/context.ts +171 -0
- package/src/cli/commands/daemon.ts +100 -0
- package/src/cli/commands/docs.ts +71 -0
- package/src/cli/commands/files.ts +69 -0
- package/src/cli/commands/help.ts +72 -0
- package/src/cli/commands/index.ts +282 -0
- package/src/cli/commands/kv.ts +140 -0
- package/src/cli/commands/mcp.ts +13 -0
- package/src/cli/commands/reembed.ts +30 -0
- package/src/cli/commands/scan.ts +365 -0
- package/src/cli/commands/search.ts +130 -0
- package/src/cli/commands/stats.ts +44 -0
- package/src/cli/commands/status.ts +47 -0
- package/src/cli/commands/watch.ts +43 -0
- package/src/cli/factory/brain-context.ts +43 -0
- package/src/cli/factory/builtin-registration.ts +123 -0
- package/src/cli/factory/config-loader.ts +72 -0
- package/src/cli/factory/index.ts +65 -0
- package/src/cli/factory/plugin-loader.ts +146 -0
- package/src/cli/index.ts +63 -0
- package/src/cli/server-client.ts +135 -0
- package/src/cli/utils.ts +121 -0
- package/src/config.ts +50 -0
- package/src/constants.ts +13 -0
- package/src/db/adapter.ts +112 -0
- package/src/db/metadata.ts +130 -0
- package/src/db/migrations.ts +66 -0
- package/src/db/sqlite-adapter.ts +208 -0
- package/src/db/tracker.ts +91 -0
- package/src/engine/index-api.ts +85 -0
- package/src/engine/reembed.ts +206 -0
- package/src/engine/search-api.ts +222 -0
- package/src/index.ts +159 -0
- package/src/lib/fts.ts +57 -0
- package/src/lib/languages.ts +180 -0
- package/src/lib/logger.ts +125 -0
- package/src/lib/math.ts +87 -0
- package/src/lib/provider-key.ts +20 -0
- package/src/lib/prune.ts +71 -0
- package/src/lib/rerank.ts +33 -0
- package/src/lib/rrf.ts +133 -0
- package/src/lib/write-lock.ts +108 -0
- package/src/plugin.ts +323 -0
- package/src/providers/embeddings/embedding-worker-thread.ts +95 -0
- package/src/providers/embeddings/embedding-worker.ts +141 -0
- package/src/providers/embeddings/local-embedding.ts +115 -0
- package/src/providers/embeddings/openai-embedding.ts +167 -0
- package/src/providers/embeddings/perplexity-context-embedding.ts +195 -0
- package/src/providers/embeddings/perplexity-embedding.ts +165 -0
- package/src/providers/embeddings/resolve.ts +34 -0
- package/src/providers/pruners/haiku-expander.ts +152 -0
- package/src/providers/pruners/haiku-pruner.ts +112 -0
- package/src/providers/rerankers/qwen3-reranker.ts +180 -0
- package/src/providers/vector/hnsw-index.ts +174 -0
- package/src/providers/vector/hnsw-loader.ts +129 -0
- package/src/search/bm25-boost.ts +61 -0
- package/src/search/context-builder.ts +298 -0
- package/src/search/keyword/composite-bm25-search.ts +62 -0
- package/src/search/types.ts +35 -0
- package/src/search/vector/composite-vector-search.ts +76 -0
- package/src/search/vector/mmr.ts +64 -0
- package/src/services/collection.ts +405 -0
- package/src/services/daemon.ts +87 -0
- package/src/services/http-server.ts +288 -0
- package/src/services/kv-service.ts +65 -0
- package/src/services/plugin-registry.ts +109 -0
- package/src/services/watch.ts +348 -0
- package/src/services/webhook-server.ts +100 -0
- package/src/types.ts +504 -0
- package/dist/base-3SNc_CeY.d.ts +0 -593
- package/dist/chunk-424UFCY7.js.map +0 -1
- package/dist/chunk-7EZR47JV.js +0 -232
- package/dist/chunk-7EZR47JV.js.map +0 -1
- package/dist/chunk-B77KABWH.js.map +0 -1
- package/dist/chunk-CCXVL56V.js.map +0 -1
- package/dist/chunk-DI3H6JVZ.js +0 -2432
- package/dist/chunk-DI3H6JVZ.js.map +0 -1
- package/dist/chunk-FGL32LUJ.js +0 -754
- package/dist/chunk-FGL32LUJ.js.map +0 -1
- package/dist/chunk-JRSKWF6K.js +0 -313
- package/dist/chunk-JRSKWF6K.js.map +0 -1
- package/dist/chunk-U2Q2XGPZ.js +0 -42
- package/dist/chunk-U2Q2XGPZ.js.map +0 -1
- package/dist/chunk-VQ27YUHH.js +0 -629
- package/dist/chunk-VQ27YUHH.js.map +0 -1
- package/dist/chunk-VVXYZIIB.js +0 -304
- package/dist/chunk-VVXYZIIB.js.map +0 -1
- package/dist/chunk-YOLKSYWK.js +0 -79
- package/dist/chunk-YOLKSYWK.js.map +0 -1
- package/dist/chunk-ZNLN2VWV.js.map +0 -1
- package/dist/code.d.ts +0 -33
- package/dist/code.js +0 -9
- package/dist/docs.d.ts +0 -21
- package/dist/docs.js +0 -9
- package/dist/git.d.ts +0 -33
- package/dist/git.js +0 -9
- package/dist/memory.d.ts +0 -17
- package/dist/memory.js +0 -9
- package/dist/notes.d.ts +0 -17
- package/dist/notes.js +0 -10
- package/dist/perplexity-context-embedding-KSVSZXMD.js +0 -9
- package/dist/resolve-CUJWY6HP.js.map +0 -1
- /package/dist/{code.js.map → haiku-expander-WOVJIVXD.js.map} +0 -0
- /package/dist/{docs.js.map → haiku-pruner-DB77ZQLJ.js.map} +0 -0
- /package/dist/{git.js.map → http-server-GIRELCCL.js.map} +0 -0
- /package/dist/{local-embedding-ZIMTK6PU.js.map → local-embedding-2RNCC5EU.js.map} +0 -0
- /package/dist/{memory.js.map → openai-embedding-Z5I4K4CN.js.map} +0 -0
- /package/dist/{notes.js.map → perplexity-context-embedding-V5YUMXDR.js.map} +0 -0
- /package/dist/{openai-embedding-VQZCZQYT.js.map → perplexity-embedding-X2S72OAC.js.map} +0 -0
- /package/dist/{perplexity-context-embedding-KSVSZXMD.js.map → plugin-FF4Q34TI.js.map} +0 -0
- /package/dist/{perplexity-embedding-227WQY4R.js.map → qwen3-reranker-HVIQOLKS.js.map} +0 -0
- /package/dist/{qwen3-reranker-3MHEENT5.js.map → resolve-Q5D6HECY.js.map} +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/services/daemon.ts
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as os from "os";
|
|
9
|
+
var DEFAULT_PORT = 8181;
|
|
10
|
+
function cacheDir() {
|
|
11
|
+
return path.join(os.homedir(), ".cache", "brainbank");
|
|
12
|
+
}
|
|
13
|
+
__name(cacheDir, "cacheDir");
|
|
14
|
+
function pidPath() {
|
|
15
|
+
return path.join(cacheDir(), "server.pid");
|
|
16
|
+
}
|
|
17
|
+
__name(pidPath, "pidPath");
|
|
18
|
+
function writePid(pid, port) {
|
|
19
|
+
const dir = cacheDir();
|
|
20
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
21
|
+
fs.writeFileSync(pidPath(), JSON.stringify({ pid, port }));
|
|
22
|
+
}
|
|
23
|
+
__name(writePid, "writePid");
|
|
24
|
+
function readPid() {
|
|
25
|
+
try {
|
|
26
|
+
const raw = fs.readFileSync(pidPath(), "utf8");
|
|
27
|
+
const info = JSON.parse(raw);
|
|
28
|
+
if (typeof info.pid !== "number" || typeof info.port !== "number") return null;
|
|
29
|
+
return info;
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
__name(readPid, "readPid");
|
|
35
|
+
function removePid() {
|
|
36
|
+
try {
|
|
37
|
+
fs.unlinkSync(pidPath());
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
__name(removePid, "removePid");
|
|
42
|
+
function isServerRunning() {
|
|
43
|
+
const info = readPid();
|
|
44
|
+
if (!info) return null;
|
|
45
|
+
try {
|
|
46
|
+
process.kill(info.pid, 0);
|
|
47
|
+
return info;
|
|
48
|
+
} catch {
|
|
49
|
+
removePid();
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
__name(isServerRunning, "isServerRunning");
|
|
54
|
+
function getServerUrl() {
|
|
55
|
+
const info = isServerRunning();
|
|
56
|
+
if (!info) return null;
|
|
57
|
+
return `http://localhost:${info.port}`;
|
|
58
|
+
}
|
|
59
|
+
__name(getServerUrl, "getServerUrl");
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
DEFAULT_PORT,
|
|
63
|
+
writePid,
|
|
64
|
+
readPid,
|
|
65
|
+
removePid,
|
|
66
|
+
isServerRunning,
|
|
67
|
+
getServerUrl
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=chunk-OLDHLOMT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/daemon.ts"],"sourcesContent":["/**\n * Daemon — PID file management for the BrainBank HTTP server.\n *\n * PID file: ~/.cache/brainbank/server.pid\n * Format: JSON { pid: number, port: number }\n *\n * Used by:\n * - `brainbank daemon` to write PID on start\n * - `brainbank daemon stop` to find and kill the daemon\n * - `brainbank status` to report server state\n * - CLI commands to detect running server for delegation\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\nexport const DEFAULT_PORT = 8181;\n\ninterface PidInfo {\n pid: number;\n port: number;\n}\n\n/** Directory for PID file and other cache data. */\nfunction cacheDir(): string {\n return path.join(os.homedir(), '.cache', 'brainbank');\n}\n\n/** Full path to the PID file. */\nfunction pidPath(): string {\n return path.join(cacheDir(), 'server.pid');\n}\n\n/** Write the PID file after server starts. */\nexport function writePid(pid: number, port: number): void {\n const dir = cacheDir();\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(pidPath(), JSON.stringify({ pid, port } as PidInfo));\n}\n\n/** Read PID info from file. Returns null if missing or malformed. */\nexport function readPid(): PidInfo | null {\n try {\n const raw = fs.readFileSync(pidPath(), 'utf8');\n const info = JSON.parse(raw) as PidInfo;\n if (typeof info.pid !== 'number' || typeof info.port !== 'number') return null;\n return info;\n } catch {\n return null;\n }\n}\n\n/** Remove the PID file. */\nexport function removePid(): void {\n try {\n fs.unlinkSync(pidPath());\n } catch {\n // File doesn't exist — safe to ignore\n }\n}\n\n/**\n * Check if the server process is still alive.\n * Uses `kill(pid, 0)` which doesn't actually send a signal —\n * it just checks whether the process exists.\n */\nexport function isServerRunning(): PidInfo | null {\n const info = readPid();\n if (!info) return null;\n\n try {\n process.kill(info.pid, 0);\n return info;\n } catch {\n // Process not running — stale PID file\n removePid();\n return null;\n }\n}\n\n/** Get the server URL if running, or null. */\nexport function getServerUrl(): string | null {\n const info = isServerRunning();\n if (!info) return null;\n return `http://localhost:${info.port}`;\n}\n"],"mappings":";;;;;AAaA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,QAAQ;AAEb,IAAM,eAAe;AAQ5B,SAAS,WAAmB;AACxB,SAAY,UAAQ,WAAQ,GAAG,UAAU,WAAW;AACxD;AAFS;AAKT,SAAS,UAAkB;AACvB,SAAY,UAAK,SAAS,GAAG,YAAY;AAC7C;AAFS;AAKF,SAAS,SAAS,KAAa,MAAoB;AACtD,QAAM,MAAM,SAAS;AACrB,EAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,EAAG,iBAAc,QAAQ,GAAG,KAAK,UAAU,EAAE,KAAK,KAAK,CAAY,CAAC;AACxE;AAJgB;AAOT,SAAS,UAA0B;AACtC,MAAI;AACA,UAAM,MAAS,gBAAa,QAAQ,GAAG,MAAM;AAC7C,UAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,QAAI,OAAO,KAAK,QAAQ,YAAY,OAAO,KAAK,SAAS,SAAU,QAAO;AAC1E,WAAO;AAAA,EACX,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AATgB;AAYT,SAAS,YAAkB;AAC9B,MAAI;AACA,IAAG,cAAW,QAAQ,CAAC;AAAA,EAC3B,QAAQ;AAAA,EAER;AACJ;AANgB;AAaT,SAAS,kBAAkC;AAC9C,QAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACA,YAAQ,KAAK,KAAK,KAAK,CAAC;AACxB,WAAO;AAAA,EACX,QAAQ;AAEJ,cAAU;AACV,WAAO;AAAA,EACX;AACJ;AAZgB;AAeT,SAAS,eAA8B;AAC1C,QAAM,OAAO,gBAAgB;AAC7B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,oBAAoB,KAAK,IAAI;AACxC;AAJgB;","names":[]}
|
|
@@ -25,7 +25,11 @@ var LocalEmbedding = class {
|
|
|
25
25
|
if (this._pipeline) return this._pipeline;
|
|
26
26
|
if (this._pipelinePromise) return this._pipelinePromise;
|
|
27
27
|
this._pipelinePromise = (async () => {
|
|
28
|
-
const
|
|
28
|
+
const mod = await import(
|
|
29
|
+
/* webpackIgnore: true */
|
|
30
|
+
"@xenova/transformers"
|
|
31
|
+
);
|
|
32
|
+
const { pipeline, env } = mod;
|
|
29
33
|
env.cacheDir = this._cacheDir;
|
|
30
34
|
env.allowLocalModels = true;
|
|
31
35
|
this._pipeline = await pipeline("feature-extraction", this._modelName, {
|
|
@@ -75,4 +79,4 @@ var LocalEmbedding = class {
|
|
|
75
79
|
export {
|
|
76
80
|
LocalEmbedding
|
|
77
81
|
};
|
|
78
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-QTZNB6AK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/embeddings/local-embedding.ts"],"sourcesContent":["/**\n * BrainBank — Local Embedding Provider\n * \n * Uses @xenova/transformers with all-MiniLM-L6-v2 (384 dims, WASM).\n * Downloads ~23MB on first use, cached locally.\n * No external API calls — runs entirely in-process.\n */\n\nimport type { EmbeddingProvider } from '@/types.ts';\n\n/** Minimal interface for @xenova/transformers pipeline results. */\ninterface XenovaPipelineOutput {\n data: Float32Array;\n}\n\n/** Callable pipeline returned by @xenova/transformers. */\ninterface XenovaPipeline {\n (texts: string | string[], options: { pooling: string; normalize: boolean }): Promise<XenovaPipelineOutput>;\n}\n\n/** Configuration environment of @xenova/transformers. */\ninterface XenovaEnv {\n cacheDir: string;\n allowLocalModels: boolean;\n}\n\n/** Shape of the @xenova/transformers module used here. */\ninterface XenovaModule {\n pipeline(task: string, model: string, options?: { quantized?: boolean }): Promise<XenovaPipeline>;\n env: XenovaEnv;\n}\n\nexport class LocalEmbedding implements EmbeddingProvider {\n readonly dims: number = 384;\n\n private _pipeline: XenovaPipeline | null = null;\n private _modelName: string;\n private _cacheDir: string;\n\n constructor(options: { model?: string; cacheDir?: string } = {}) {\n this._modelName = options.model ?? 'Xenova/all-MiniLM-L6-v2';\n this._cacheDir = options.cacheDir ?? '.model-cache';\n }\n\n private _pipelinePromise: Promise<XenovaPipeline> | null = null;\n\n /**\n * Lazy-load the transformer pipeline.\n * Singleton — created once and reused.\n * Promise-deduped to prevent concurrent downloads.\n */\n private async _getPipeline(): Promise<XenovaPipeline> {\n if (this._pipeline) return this._pipeline;\n if (this._pipelinePromise) return this._pipelinePromise;\n\n this._pipelinePromise = (async () => {\n const mod = await import(/* webpackIgnore: true */ '@xenova/transformers' as string) as XenovaModule;\n const { pipeline, env } = mod;\n env.cacheDir = this._cacheDir;\n env.allowLocalModels = true;\n\n this._pipeline = await pipeline('feature-extraction', this._modelName, {\n quantized: true,\n });\n\n return this._pipeline!;\n })();\n\n try {\n return await this._pipelinePromise;\n } finally {\n this._pipelinePromise = null;\n }\n }\n\n /**\n * Embed a single text string.\n * Returns a normalized Float32Array of length 384.\n */\n async embed(text: string): Promise<Float32Array> {\n const pipe = await this._getPipeline();\n const output = await pipe(text, { pooling: 'mean', normalize: true });\n return output.data as Float32Array;\n }\n\n /**\n * Embed multiple texts using real batch processing.\n * Chunks into groups of BATCH_SIZE to balance throughput vs memory.\n */\n async embedBatch(texts: string[]): Promise<Float32Array[]> {\n if (texts.length === 0) return [];\n\n const BATCH_SIZE = 32;\n const pipe = await this._getPipeline();\n const results: Float32Array[] = [];\n\n for (let i = 0; i < texts.length; i += BATCH_SIZE) {\n const batch = texts.slice(i, i + BATCH_SIZE);\n const output = await pipe(batch, { pooling: 'mean', normalize: true });\n\n // output.data is a flat Float32Array — must copy, not view,\n // because the pipeline may reuse the underlying buffer\n for (let j = 0; j < batch.length; j++) {\n const start = j * this.dims;\n results.push(output.data.slice(start, start + this.dims) as Float32Array);\n }\n }\n\n return results;\n }\n\n async close(): Promise<void> {\n this._pipeline = null;\n }\n}\n"],"mappings":";;;;;AAgCO,IAAM,iBAAN,MAAkD;AAAA,EAhCzD,OAgCyD;AAAA;AAAA;AAAA,EAC5C,OAAe;AAAA,EAEhB,YAAmC;AAAA,EACnC;AAAA,EACA;AAAA,EAER,YAAY,UAAiD,CAAC,GAAG;AAC7D,SAAK,aAAa,QAAQ,SAAS;AACnC,SAAK,YAAY,QAAQ,YAAY;AAAA,EACzC;AAAA,EAEQ,mBAAmD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO3D,MAAc,eAAwC;AAClD,QAAI,KAAK,UAAW,QAAO,KAAK;AAChC,QAAI,KAAK,iBAAkB,QAAO,KAAK;AAEvC,SAAK,oBAAoB,YAAY;AACjC,YAAM,MAAM,MAAM;AAAA;AAAA,QAAiC;AAAA,MAAgC;AACnF,YAAM,EAAE,UAAU,IAAI,IAAI;AAC1B,UAAI,WAAW,KAAK;AACpB,UAAI,mBAAmB;AAEvB,WAAK,YAAY,MAAM,SAAS,sBAAsB,KAAK,YAAY;AAAA,QACnE,WAAW;AAAA,MACf,CAAC;AAED,aAAO,KAAK;AAAA,IAChB,GAAG;AAEH,QAAI;AACA,aAAO,MAAM,KAAK;AAAA,IACtB,UAAE;AACE,WAAK,mBAAmB;AAAA,IAC5B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,MAAM,MAAqC;AAC7C,UAAM,OAAO,MAAM,KAAK,aAAa;AACrC,UAAM,SAAS,MAAM,KAAK,MAAM,EAAE,SAAS,QAAQ,WAAW,KAAK,CAAC;AACpE,WAAO,OAAO;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,OAA0C;AACvD,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAEhC,UAAM,aAAa;AACnB,UAAM,OAAO,MAAM,KAAK,aAAa;AACrC,UAAM,UAA0B,CAAC;AAEjC,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,YAAY;AAC/C,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,UAAU;AAC3C,YAAM,SAAS,MAAM,KAAK,OAAO,EAAE,SAAS,QAAQ,WAAW,KAAK,CAAC;AAIrE,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACnC,cAAM,QAAQ,IAAI,KAAK;AACvB,gBAAQ,KAAK,OAAO,KAAK,MAAM,OAAO,QAAQ,KAAK,IAAI,CAAiB;AAAA,MAC5E;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,QAAuB;AACzB,SAAK,YAAY;AAAA,EACrB;AACJ;","names":[]}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/providers/pruners/haiku-expander.ts
|
|
6
|
+
var DEFAULT_MODEL = "claude-haiku-4-5-20251001";
|
|
7
|
+
var HaikuExpander = class {
|
|
8
|
+
static {
|
|
9
|
+
__name(this, "HaikuExpander");
|
|
10
|
+
}
|
|
11
|
+
_apiKey;
|
|
12
|
+
_model;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this._apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
|
|
15
|
+
this._model = options.model ?? DEFAULT_MODEL;
|
|
16
|
+
if (!this._apiKey) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"HaikuExpander: No API key provided. Set ANTHROPIC_API_KEY env var or pass apiKey option."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async expand(query, currentIds, manifest) {
|
|
23
|
+
if (manifest.length === 0) return { ids: [] };
|
|
24
|
+
const currentSet = new Set(currentIds);
|
|
25
|
+
const available = manifest.filter((m) => !currentSet.has(m.id));
|
|
26
|
+
if (available.length === 0) return { ids: [] };
|
|
27
|
+
const manifestLines = available.map(
|
|
28
|
+
(m) => `#${m.id} ${m.filePath} | ${m.chunkType} ${m.name} ${m.lines}`
|
|
29
|
+
).join("\n");
|
|
30
|
+
const currentSummary = manifest.filter((m) => currentSet.has(m.id)).map((m) => `#${m.id} ${m.filePath} | ${m.chunkType} ${m.name}`).join("\n");
|
|
31
|
+
const prompt = `Task: "${query}"
|
|
32
|
+
|
|
33
|
+
Already included chunks:
|
|
34
|
+
${currentSummary}
|
|
35
|
+
|
|
36
|
+
Available chunks NOT yet included:
|
|
37
|
+
${manifestLines}
|
|
38
|
+
|
|
39
|
+
You are a code context expander. The search already found the "included" chunks above.
|
|
40
|
+
Review the "available" chunks and select any that would help an AI agent complete the task.
|
|
41
|
+
|
|
42
|
+
Rules:
|
|
43
|
+
- Select chunks that are structurally related (called by, imported by, or extend included code)
|
|
44
|
+
- Select type definitions, interfaces, or configs needed to understand included code
|
|
45
|
+
- Select initialization or setup code if the task involves debugging or modifying a feature
|
|
46
|
+
- Do NOT select test files, documentation, or unrelated utilities
|
|
47
|
+
- Be selective: only include chunks that fill clear gaps. Quality over quantity.
|
|
48
|
+
- If nothing useful is available, return an empty ids array
|
|
49
|
+
|
|
50
|
+
Respond with ONLY a JSON object:
|
|
51
|
+
{ "ids": [42, 17, 89], "note": "Brief 1-2 sentence observation about the codebase relevant to the task" }
|
|
52
|
+
|
|
53
|
+
The "note" is optional \u2014 use it to mention things like missing files, architectural patterns, deprecated modules, or important relationships you noticed. If nothing notable, omit it.
|
|
54
|
+
If nothing to add: { "ids": [] }`;
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: {
|
|
59
|
+
"Content-Type": "application/json",
|
|
60
|
+
"x-api-key": this._apiKey,
|
|
61
|
+
"anthropic-version": "2023-06-01"
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
model: this._model,
|
|
65
|
+
max_tokens: 512,
|
|
66
|
+
messages: [{
|
|
67
|
+
role: "user",
|
|
68
|
+
content: prompt
|
|
69
|
+
}]
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
return { ids: [] };
|
|
74
|
+
}
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
const text = data.content?.[0]?.text ?? "";
|
|
77
|
+
return this._parseResponse(text, available);
|
|
78
|
+
} catch {
|
|
79
|
+
return { ids: [] };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Parse Haiku response — handles both `{ ids, note }` and bare `[...]` formats. */
|
|
83
|
+
_parseResponse(text, available) {
|
|
84
|
+
const validIds = new Set(available.map((m) => m.id));
|
|
85
|
+
const objMatch = text.match(/\{[\s\S]*"ids"\s*:\s*\[[\d\s,]*\][\s\S]*\}/);
|
|
86
|
+
if (objMatch) {
|
|
87
|
+
try {
|
|
88
|
+
const parsed = JSON.parse(objMatch[0]);
|
|
89
|
+
const ids = parsed.ids.filter((id) => validIds.has(id));
|
|
90
|
+
const note = parsed.note?.trim() || void 0;
|
|
91
|
+
return { ids, note };
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const arrMatch = text.match(/\[[\d\s,]*\]/);
|
|
96
|
+
if (arrMatch) {
|
|
97
|
+
const ids = JSON.parse(arrMatch[0]).filter((id) => validIds.has(id));
|
|
98
|
+
return { ids };
|
|
99
|
+
}
|
|
100
|
+
return { ids: [] };
|
|
101
|
+
}
|
|
102
|
+
async close() {
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
HaikuExpander
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=chunk-RFF7HMP6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/pruners/haiku-expander.ts"],"sourcesContent":["/**\n * BrainBank — Haiku Expander\n *\n * LLM-powered context expansion using Anthropic's Haiku 4.5 model.\n * After search + pruning, reviews a manifest of available chunks\n * and requests additional IDs to include.\n *\n * Flow:\n * 1. Receives lightweight manifest (~20 chars per chunk)\n * 2. Haiku selects additional chunk IDs (just numbers, fast)\n * 3. Caller fetches those chunks from DB and splices into results\n *\n * Designed for minimal token usage:\n * - Input: ~2,000-3,000 tokens (manifest)\n * - Output: ~50-100 tokens (ID array)\n * - Cost: ~$0.001 per call\n * - Latency: ~300-600ms\n *\n * Fail-open: any error returns empty array (no expansion).\n */\n\nimport type { Expander, ExpanderManifestItem, ExpanderResult } from '@/types.ts';\n\nconst DEFAULT_MODEL = 'claude-haiku-4-5-20251001';\n\nexport interface HaikuExpanderOptions {\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var. */\n apiKey?: string;\n /** Model to use. Default: claude-haiku-4-5-20251001 */\n model?: string;\n}\n\nexport class HaikuExpander implements Expander {\n private readonly _apiKey: string;\n private readonly _model: string;\n\n constructor(options: HaikuExpanderOptions = {}) {\n this._apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY ?? '';\n this._model = options.model ?? DEFAULT_MODEL;\n\n if (!this._apiKey) {\n throw new Error(\n 'HaikuExpander: No API key provided. Set ANTHROPIC_API_KEY env var or pass apiKey option.',\n );\n }\n }\n\n async expand(\n query: string,\n currentIds: number[],\n manifest: ExpanderManifestItem[],\n ): Promise<ExpanderResult> {\n if (manifest.length === 0) return { ids: [] };\n\n // Filter out chunks already in results\n const currentSet = new Set(currentIds);\n const available = manifest.filter(m => !currentSet.has(m.id));\n if (available.length === 0) return { ids: [] };\n\n // Build compact manifest string\n const manifestLines = available.map(m =>\n `#${m.id} ${m.filePath} | ${m.chunkType} ${m.name} ${m.lines}`\n ).join('\\n');\n\n const currentSummary = manifest\n .filter(m => currentSet.has(m.id))\n .map(m => `#${m.id} ${m.filePath} | ${m.chunkType} ${m.name}`)\n .join('\\n');\n\n const prompt =\n `Task: \"${query}\"\\n\\n` +\n `Already included chunks:\\n${currentSummary}\\n\\n` +\n `Available chunks NOT yet included:\\n${manifestLines}\\n\\n` +\n `You are a code context expander. The search already found the \"included\" chunks above.\\n` +\n `Review the \"available\" chunks and select any that would help an AI agent complete the task.\\n\\n` +\n `Rules:\\n` +\n `- Select chunks that are structurally related (called by, imported by, or extend included code)\\n` +\n `- Select type definitions, interfaces, or configs needed to understand included code\\n` +\n `- Select initialization or setup code if the task involves debugging or modifying a feature\\n` +\n `- Do NOT select test files, documentation, or unrelated utilities\\n` +\n `- Be selective: only include chunks that fill clear gaps. Quality over quantity.\\n` +\n `- If nothing useful is available, return an empty ids array\\n\\n` +\n `Respond with ONLY a JSON object:\\n` +\n `{ \"ids\": [42, 17, 89], \"note\": \"Brief 1-2 sentence observation about the codebase relevant to the task\" }\\n\\n` +\n `The \"note\" is optional — use it to mention things like missing files, architectural patterns, ` +\n `deprecated modules, or important relationships you noticed. If nothing notable, omit it.\\n` +\n `If nothing to add: { \"ids\": [] }`;\n\n try {\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this._apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: this._model,\n max_tokens: 512,\n messages: [{\n role: 'user',\n content: prompt,\n }],\n }),\n });\n\n if (!response.ok) {\n return { ids: [] };\n }\n\n const data = await response.json() as {\n content: { type: string; text: string }[];\n };\n\n const text = data.content?.[0]?.text ?? '';\n return this._parseResponse(text, available);\n } catch {\n return { ids: [] };\n }\n }\n\n /** Parse Haiku response — handles both `{ ids, note }` and bare `[...]` formats. */\n private _parseResponse(text: string, available: ExpanderManifestItem[]): ExpanderResult {\n const validIds = new Set(available.map(m => m.id));\n\n // Try JSON object first: { \"ids\": [...], \"note\": \"...\" }\n const objMatch = text.match(/\\{[\\s\\S]*\"ids\"\\s*:\\s*\\[[\\d\\s,]*\\][\\s\\S]*\\}/);\n if (objMatch) {\n try {\n const parsed = JSON.parse(objMatch[0]) as { ids: number[]; note?: string };\n const ids = parsed.ids.filter(id => validIds.has(id));\n const note = parsed.note?.trim() || undefined;\n return { ids, note };\n } catch {\n // Fall through to array parsing\n }\n }\n\n // Fallback: bare array [42, 17, 89]\n const arrMatch = text.match(/\\[[\\d\\s,]*\\]/);\n if (arrMatch) {\n const ids = (JSON.parse(arrMatch[0]) as number[]).filter(id => validIds.has(id));\n return { ids };\n }\n\n return { ids: [] };\n }\n\n async close(): Promise<void> {\n // No resources to release (stateless HTTP)\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/providers/rerankers/qwen3-reranker.ts"],"sourcesContent":["/**\n * BrainBank — Qwen3 Local Reranker\n * \n * Cross-encoder reranker using Qwen3-Reranker-0.6B via node-llama-cpp.\n * Auto-downloads the GGUF model from HuggingFace (~640MB, cached).\n * \n * Based on QMD's reranker architecture:\n * - Lazy model loading (loads on first rank() call)\n * - Flash attention for 20× less VRAM\n * - Document deduplication (identical texts scored once)\n * - Tokenizer-based truncation for oversized documents\n */\n\nimport type { Reranker } from '@/types.ts';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { existsSync, mkdirSync } from 'node:fs';\n\n/** Minimal interface for node-llama-cpp model methods used by the reranker. */\ninterface LlamaModel {\n tokenize(text: string): number[];\n detokenize(tokens: number[]): string;\n createRankingContext(opts: { contextSize: number; flashAttention?: boolean }): Promise<LlamaRankingContext>;\n dispose?(): Promise<void>;\n}\n\n/** Minimal interface for node-llama-cpp ranking context. */\ninterface LlamaRankingContext {\n rankAll(query: string, documents: string[]): Promise<number[]>;\n dispose(): Promise<void>;\n}\n\n/** Engine returned by getLlama(). */\ninterface LlamaEngine {\n loadModel(opts: { modelPath: string }): Promise<LlamaModel>;\n}\n\n/** Shape of the node-llama-cpp module used here. */\ninterface NodeLlamaCppModule {\n getLlama(): Promise<LlamaEngine>;\n resolveModelFile(uri: string, cacheDir: string): Promise<string>;\n}\n\n// Default model — Qwen3-Reranker-0.6B quantized to Q8_0 (~640MB)\nconst DEFAULT_MODEL_URI = 'hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf';\n\n// Context size for reranking (Qwen3 template ~200 tokens overhead + query + doc)\nconst CONTEXT_SIZE = 2048;\n\n// Cache directory for downloaded models\nconst MODEL_CACHE_DIR = join(homedir(), '.cache', 'brainbank', 'models');\n\nexport interface Qwen3RerankerOptions {\n /** HuggingFace model URI. Default: Qwen3-Reranker-0.6B-Q8_0 */\n modelUri?: string;\n /** Model cache directory. Default: ~/.cache/brainbank/models/ */\n cacheDir?: string;\n /** Context size for ranking. Default: 2048 */\n contextSize?: number;\n}\n\nexport class Qwen3Reranker implements Reranker {\n private readonly _modelUri: string;\n private readonly _cacheDir: string;\n private readonly _contextSize: number;\n\n private _model: LlamaModel | null = null;\n private _context: LlamaRankingContext | null = null;\n private _loadPromise: Promise<void> | null = null;\n\n constructor(options: Qwen3RerankerOptions = {}) {\n this._modelUri = options.modelUri ?? DEFAULT_MODEL_URI;\n this._cacheDir = options.cacheDir ?? MODEL_CACHE_DIR;\n this._contextSize = options.contextSize ?? CONTEXT_SIZE;\n }\n\n /**\n * Lazy-load the reranker model and create a ranking context.\n * Model is auto-downloaded from HuggingFace on first use.\n */\n private async _ensureLoaded(): Promise<void> {\n if (this._context) return;\n if (this._loadPromise) {\n await this._loadPromise;\n return;\n }\n\n this._loadPromise = (async () => {\n try {\n // Dynamic import — node-llama-cpp is an optional peer dependency.\n // String indirection prevents DTS from resolving the specifier at build time.\n const llamaModule = 'node-llama-cpp';\n const { getLlama, resolveModelFile } = await import(/* webpackIgnore: true */ llamaModule) as NodeLlamaCppModule;\n\n // Ensure cache directory exists\n if (!existsSync(this._cacheDir)) {\n mkdirSync(this._cacheDir, { recursive: true });\n }\n\n // Download model if needed (resolveModelFile handles caching)\n const modelPath = await resolveModelFile(this._modelUri, this._cacheDir);\n\n // Initialize llama engine\n const llama = await getLlama();\n\n // Load model\n this._model = await llama.loadModel({ modelPath });\n\n try {\n this._context = await this._model!.createRankingContext({\n contextSize: this._contextSize,\n flashAttention: true,\n });\n } catch {\n // Flash attention might not be supported — retry without it\n this._context = await this._model!.createRankingContext({\n contextSize: this._contextSize,\n });\n }\n } finally {\n this._loadPromise = null;\n }\n })();\n\n await this._loadPromise;\n }\n\n /**\n * Score each document's relevance to the query.\n * Returns scores (0.0 - 1.0) in same order as input documents.\n * \n * Deduplicates identical documents to avoid redundant computation.\n */\n async rank(query: string, documents: string[]): Promise<number[]> {\n if (documents.length === 0) return [];\n\n await this._ensureLoaded();\n\n // Deduplicate — identical texts get scored once\n const uniqueTexts = [...new Set(documents)];\n const textToScore = new Map<string, number>();\n\n // Truncate documents that exceed context size\n const truncated = uniqueTexts.map(text => {\n if (this._model) {\n const tokens = this._model.tokenize(text);\n // Budget: contextSize - ~200 overhead - query tokens\n const queryTokens = this._model.tokenize(query).length;\n const maxDocTokens = this._contextSize - 200 - queryTokens;\n if (tokens.length > maxDocTokens && maxDocTokens > 0) {\n return this._model.detokenize(tokens.slice(0, maxDocTokens));\n }\n }\n return text;\n });\n\n // Rank all unique documents at once\n const scores: number[] = await this._context!.rankAll(query, truncated);\n\n // Map scores back\n for (let i = 0; i < uniqueTexts.length; i++) {\n textToScore.set(uniqueTexts[i], scores[i] ?? 0);\n }\n\n // Return scores in original document order\n return documents.map(doc => textToScore.get(doc) ?? 0);\n }\n\n /** Release model resources. */\n async close(): Promise<void> {\n if (this._context) {\n await this._context.dispose();\n this._context = null;\n }\n if (this._model) {\n await this._model.dispose?.();\n this._model = null;\n }\n }\n}\n"],"mappings":";;;;;AAcA,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,YAAY,iBAAiB;AA4BtC,IAAM,oBAAoB;AAG1B,IAAM,eAAe;AAGrB,IAAM,kBAAkB,KAAK,QAAQ,GAAG,UAAU,aAAa,QAAQ;AAWhE,IAAM,gBAAN,MAAwC;AAAA,EA7D/C,OA6D+C;AAAA;AAAA;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EAET,SAA4B;AAAA,EAC5B,WAAuC;AAAA,EACvC,eAAqC;AAAA,EAE7C,YAAY,UAAgC,CAAC,GAAG;AAC5C,SAAK,YAAY,QAAQ,YAAY;AACrC,SAAK,YAAY,QAAQ,YAAY;AACrC,SAAK,eAAe,QAAQ,eAAe;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAA+B;AACzC,QAAI,KAAK,SAAU;AACnB,QAAI,KAAK,cAAc;AACnB,YAAM,KAAK;AACX;AAAA,IACJ;AAEA,SAAK,gBAAgB,YAAY;AAC7B,UAAI;AAGA,cAAM,cAAc;AACpB,cAAM,EAAE,UAAU,iBAAiB,IAAI,MAAM;AAAA;AAAA,UAAiC;AAAA;AAG9E,YAAI,CAAC,WAAW,KAAK,SAAS,GAAG;AAC7B,oBAAU,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,QACjD;AAGA,cAAM,YAAY,MAAM,iBAAiB,KAAK,WAAW,KAAK,SAAS;AAGvE,cAAM,QAAQ,MAAM,SAAS;AAG7B,aAAK,SAAS,MAAM,MAAM,UAAU,EAAE,UAAU,CAAC;AAEjD,YAAI;AACA,eAAK,WAAW,MAAM,KAAK,OAAQ,qBAAqB;AAAA,YACpD,aAAa,KAAK;AAAA,YAClB,gBAAgB;AAAA,UACpB,CAAC;AAAA,QACL,QAAQ;AAEJ,eAAK,WAAW,MAAM,KAAK,OAAQ,qBAAqB;AAAA,YACpD,aAAa,KAAK;AAAA,UACtB,CAAC;AAAA,QACL;AAAA,MACJ,UAAE;AACE,aAAK,eAAe;AAAA,MACxB;AAAA,IACJ,GAAG;AAEH,UAAM,KAAK;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAK,OAAe,WAAwC;AAC9D,QAAI,UAAU,WAAW,EAAG,QAAO,CAAC;AAEpC,UAAM,KAAK,cAAc;AAGzB,UAAM,cAAc,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AAC1C,UAAM,cAAc,oBAAI,IAAoB;AAG5C,UAAM,YAAY,YAAY,IAAI,UAAQ;AACtC,UAAI,KAAK,QAAQ;AACb,cAAM,SAAS,KAAK,OAAO,SAAS,IAAI;AAExC,cAAM,cAAc,KAAK,OAAO,SAAS,KAAK,EAAE;AAChD,cAAM,eAAe,KAAK,eAAe,MAAM;AAC/C,YAAI,OAAO,SAAS,gBAAgB,eAAe,GAAG;AAClD,iBAAO,KAAK,OAAO,WAAW,OAAO,MAAM,GAAG,YAAY,CAAC;AAAA,QAC/D;AAAA,MACJ;AACA,aAAO;AAAA,IACX,CAAC;AAGD,UAAM,SAAmB,MAAM,KAAK,SAAU,QAAQ,OAAO,SAAS;AAGtE,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AACzC,kBAAY,IAAI,YAAY,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;AAAA,IAClD;AAGA,WAAO,UAAU,IAAI,SAAO,YAAY,IAAI,GAAG,KAAK,CAAC;AAAA,EACzD;AAAA;AAAA,EAGA,MAAM,QAAuB;AACzB,QAAI,KAAK,UAAU;AACf,YAAM,KAAK,SAAS,QAAQ;AAC5B,WAAK,WAAW;AAAA,IACpB;AACA,QAAI,KAAK,QAAQ;AACb,YAAM,KAAK,OAAO,UAAU;AAC5B,WAAK,SAAS;AAAA,IAClB;AAAA,EACJ;AACJ;","names":[]}
|