mcp-rag-memory 2.6.0 → 2.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/.env.example CHANGED
@@ -20,6 +20,9 @@ RAG_MEMORY_HALF_LIFE_DAYS=14
20
20
  RAG_MAX_FILE_MB=10
21
21
  # RAG_ALLOWED_DIRS=C:\repo\a;C:\repo\b
22
22
 
23
+ # Hybrid ranking: RRF constant for the default fusion (read at call time; default 60)
24
+ # RAG_RRF_K=60
25
+
23
26
  # Session auto-sync / condensing (opencode plugin reads these from its own env)
24
27
  RAG_AUTOSYNC=1
25
28
  RAG_SESSION_CONDENSE=1
package/README.md CHANGED
@@ -18,7 +18,7 @@ context **across sessions**.
18
18
  - **Context Management** — `remember` facts/decisions/preferences, `recall` them later (score-decayed by staleness), rate by importance, consolidate duplicates, filter by type/tag.
19
19
  - **Zero external APIs by default** — local hashing-embedder (1024-dim), built-in `node:sqlite`. Works fully offline. Optional `EMBEDDING_PROVIDER=transformers` for a higher-quality ONNX model.
20
20
  - **Safe ingestion** — content-hash deduplication, file size guard (`RAG_MAX_FILE_MB`) and an opt-in path allowlist (`RAG_ALLOWED_DIRS`).
21
- - **MCP server** — runs on stdio, 19 tools.
21
+ - **MCP server** — runs on stdio, 21 tools.
22
22
 
23
23
  ## Quick start
24
24
 
@@ -27,7 +27,7 @@ Requires **Node.js ≥ 22.12** (for `node:sqlite` read-only handles and
27
27
 
28
28
  ```bash
29
29
  npm install
30
- npm test # 160 checks: unit + MCP round-trip via SDK client
30
+ npm test # 238 checks: unit + MCP round-trip via SDK client
31
31
  npm run lint # oxlint
32
32
  npm run typecheck # src + scripts + .opencode/plugin
33
33
  npm run build # compile to dist/
@@ -190,15 +190,17 @@ the global config to apply to every project.
190
190
 
191
191
  Restart opencode after any config change.
192
192
 
193
- ## MCP tools (19)
193
+ ## MCP tools (21)
194
194
 
195
195
  | Group | Tool | Purpose |
196
196
  |-------|------|---------|
197
- | System | `system_stats` | DB dir, embedding backend, doc/memory counts |
197
+ | System | `system_stats` | DB dir, embedding backend (incl. what the vector leg measures), store state, DB integrity, doc/memory counts |
198
+ | Maintenance | `rag_reindex` | Re-embed every stored vector for the current model, migrating the store in place |
199
+ | | `rag_backup` | Snapshot the store to a consistent SQLite file (VACUUM INTO — safe under WAL) and report its integrity; refuses to overwrite |
198
200
  | RAG ingest | `rag_ingest_text` | Store text as a knowledge document (dedup-aware) |
199
201
  | | `rag_ingest_file` | Store a file (`content_type` auto-detected) |
200
202
  | | `rag_ingest_dir` | Recursively ingest source files |
201
- | RAG query | `rag_search` | Hybrid (BM25 + vector) search, ranked chunks + scores |
203
+ | RAG query | `rag_search` | Hybrid (BM25 + vector) search, ranked chunks + scores; `explain: true` adds per-leg scores, `alpha` tips the blend (0 = keyword-only, 1 = vector-only) |
202
204
  | | `rag_retrieve` | Ready-to-inject context block with token count |
203
205
  | RAG docs | `rag_list_documents`, `rag_document_stats` | Inventory (`rag_list_documents` is paginated: `limit` 1–1000, `offset`) |
204
206
  | | `rag_delete_document` | Remove a document + chunks + FTS rows |
@@ -269,9 +271,51 @@ first winning: the MCP client's `env` block → your shell environment → a
269
271
  `.env` and edit, or point at any file via `RAG_ENV_FILE`. The store defaults to
270
272
  `.rag-data/` in the working directory.
271
273
 
274
+ ## Changing the embedding model
275
+
276
+ The store refuses to mix vector spaces: if `EMBEDDING_MODEL` changes, searching
277
+ with new vectors against old ones would silently blend two spaces and return
278
+ noise. `ensureDim` catches the mismatch and tells you to point `RAG_DB_DIR` at a
279
+ fresh directory and re-ingest — correct, but for a memory store holding months of
280
+ history that is a manual rebuild rather than a migration.
281
+
282
+ `reindex` does the migration in place. It re-embeds every chunk and memory for the
283
+ currently configured provider/model, then rewrites the store metadata.
284
+
285
+ ```bash
286
+ # 1. install the optional provider
287
+ npm i @huggingface/transformers
288
+
289
+ # 2. migrate the existing store (documents' text is the source of truth)
290
+ EMBEDDING_PROVIDER=transformers \
291
+ EMBEDDING_MODEL=Xenova/all-MiniLM-L6-v2 \
292
+ npm run cli -- reindex --batch 32
293
+
294
+ # 3. bake the provider into .env so the server uses it from now on
295
+ ```
296
+
297
+ Or over MCP: the `rag_reindex` tool takes the same `batch_size`.
298
+
299
+ **How interruption behaves.** A half-migrated store mixes old and new vectors, so
300
+ `reindex` marks the store `reindexing` for its whole duration and every search,
301
+ recall and ingest refuses to run while that flag is set. This is deliberate: the
302
+ failure mode of a partial migration is confident nonsense, and nothing about the
303
+ results would reveal it. If the process dies mid-run, just run `reindex` again —
304
+ the whole store is rewritten from text, so resuming is identical to starting over.
305
+ `system_stats` reports `storeState` and the remediation if you hit this.
306
+
307
+ Re-running is always safe: embedding is deterministic per model, so `reindex` is
308
+ idempotent. On an empty store it is a no-op that just records the model.
309
+
310
+ > **Upgrading the embedder version.** Bumping the bundled local embedder (e.g. the
311
+ > 2.8 word-bi-gram `local-lexical-v2`) changes its model id, so an existing store is
312
+ > treated as a different vector space and refuses to search until migrated. After
313
+ > upgrading, run `npm run cli -- reindex` (or the `rag_reindex` tool) **once** — it
314
+ > re-embeds in place. This is the same guard as changing `EMBEDDING_MODEL`, on purpose.
315
+
272
316
  ## Custom slash commands
273
317
 
274
- The 19 MCP tools are called by the AI automatically — but you can also
318
+ The 21 MCP tools are called by the AI automatically — but you can also
275
319
  trigger them directly with custom commands. Sources (same name, project
276
320
  wins):
277
321
 
@@ -298,11 +342,16 @@ npm run cli -- recall "deployment schedule"
298
342
  npm run cli -- ingest-dir ./src/rag
299
343
  npm run cli -- search "vector similarity"
300
344
  npm run cli -- search "auth bug" --source opencode-db # filter by source or doc-id
345
+ npm run cli -- search "auth bug" --explain # per-leg vector/keyword/RRF scores
346
+ npm run cli -- search "client" --alpha 0 # keyword-only blend (0 = keyword, 1 = vector, default = RRF)
301
347
  npm run cli -- docs --limit 20 --offset 20 # paginated inventory
302
348
  npm run cli -- mem-context "database"
303
349
  npm run cli -- sessions # list recent opencode sessions
304
350
  npm run cli -- sync-session ses_123 # ingest one session's inputs
305
351
  npm run cli -- sync-latest # ingest the most recent session
352
+ npm run cli -- reindex --batch 32 # re-embed all vectors for the current model
353
+ npm run cli -- backup backups/v1.sqlite # consistent snapshot (VACUUM INTO)
354
+ npm run cli -- restore backups/v1.sqlite # replace the store from a backup (stop the server first)
306
355
  npm run clean-db -- --force # wipe ALL documents + memories (destructive)
307
356
  ```
308
357
 
@@ -359,30 +408,106 @@ The plugin needs an opencode restart to take effect.
359
408
  ## Performance & limits
360
409
 
361
410
  - **Search is brute-force cosine / FTS5 over every chunk**: `O(N)` per query
362
- (exact, deterministic — good for a personal store of thousands of chunks).
363
- ANN / HNSW indexing is planned scope (v3) for 100k+ chunks.
411
+ (exact, deterministic — good for a personal store of thousands of chunks).
412
+ ANN / HNSW indexing is planned scope (v3) for 100k+ chunks.
413
+ - **The vector cache holds every vector in RAM**, uncapped and complete. Truncating
414
+ it would silently change which documents are findable, so the cache stays whole
415
+ and the server warns instead: 8 KB per row at the default 1024 dims, so 100k
416
+ chunks is roughly 800 MB. Tune the warning threshold with
417
+ `RAG_VECTOR_CACHE_WARN_MB` (default 256). Beyond a few hundred thousand chunks,
418
+ expect to prune rather than scale.
364
419
  - Keyword leg uses the FTS5 **trigram** tokenizer, so CJK text and
365
420
  Indonesian-style substring/inflection matching work without extra config.
366
421
  Consequence: keyword terms of **≤ 2 characters are skipped** (trigram needs
367
422
  3); the vector leg still covers them.
368
423
  - Vector embeddings are local hash-based (no external APIs, ~0 cost, offline).
369
- They are tuned for short-phrase similarity, not full-document semantics.
424
+ They are tuned for short-phrase similarity, not full-document semantics.
425
+
426
+ ### What the vector leg actually measures
427
+
428
+ This matters more than it sounds, so the server states it explicitly in
429
+ `system_stats` (`embedding.vectorLeg`) rather than calling everything "semantic".
430
+
431
+ | Provider | `vectorLeg` | Meaning |
432
+ |---|---|---|
433
+ | `local` (default) | `lexical` | Hashes character 1/2/3-grams **plus word bi-grams** into 1024 buckets. Scores **lexical and sub-word overlap** (word order now matters a little), not meaning. |
434
+ | `transformers` | `semantic` | Real sentence embeddings from `EMBEDDING_MODEL`. Captures meaning. |
435
+
436
+ Consequence for the default: `"cara fix login"` and `"masalah autentikasi"`
437
+ share almost no n-grams, so the **vector** leg scores near zero even though they
438
+ mean the same thing. Retrieval still works because the **FTS5 trigram** leg
439
+ carries the query, and because the local embedder does respond to shared substrings
440
+ and character shapes. What you should not expect from the default is
441
+ paraphrase-level recall — restating a concept with different vocabulary is the
442
+ known blind spot.
443
+
444
+ To get true semantic recall, install the optional dependency and migrate in place:
445
+
446
+ ```bash
447
+ npm i @huggingface/transformers
448
+ EMBEDDING_PROVIDER=transformers EMBEDDING_MODEL=Xenova/all-MiniLM-L6-v2 npm run cli -- reindex
449
+ ```
450
+
451
+ `reindex` rewrites every stored vector for the new model. See
452
+ [Changing the embedding model](#changing-the-embedding-model).
453
+
454
+ ### Scoring & `min_score` calibration
455
+
456
+ Two ordering modes, and `min_score` means something different in each:
457
+
458
+ | Mode | How hits are ordered | What `score` / `min_score` is |
459
+ |---|---|---|
460
+ | **Default (RRF)** | Reciprocal-rank fusion over the vector and keyword rankings | The fused RRF contribution (`rrfScore`), a small number — top hits are typically `0.03`–`0.08`, so the practical floor is ~`0.01`–`0.03`. |
461
+ | **`alpha` blend** | `score = alpha·vectorScore + (1−alpha)·keywordScore` | A real 0..1 relevance value — `alpha = 0` is keyword-only, `1` is vector-only, in between is a weighted average. `0.1`–`0.3` is a sensible default threshold. |
462
+
463
+ - The RRF constant is `RAG_RRF_K` (default `60`); it is read **at call time**, so
464
+ raise it to widen the rank spread (harder to distinguish hits) or lower it to
465
+ sharpen it. With `alpha`, `min_score` runs against the blended value instead.
466
+ - The keyword leg always reports a 0..1 normalised BM25 (`keywordScore`); the
467
+ vector leg reports cosine in `-1..1` (`vectorScore`). `explain` shows exactly
468
+ what fed the final number — see the table below.
469
+
470
+ ### Debugging a bad search
471
+
472
+ `rag_search` accepts `explain: true` (CLI: `--explain`), which attaches the
473
+ per-leg diagnostics to every hit:
474
+
475
+ ```jsonc
476
+ {
477
+ "score": 0.71, // final relevance, 0..1 — what min_score filters on
478
+ "legs": ["vector", "keyword"],
479
+ "explain": {
480
+ "vectorScore": 0.63, // cosine similarity, -1..1
481
+ "keywordScore": 1.0, // BM25 normalised against the best hit, 0..1
482
+ "rrfScore": 0.0246, // fused contribution that decided the order
483
+ "vectorRank": 0,
484
+ "keywordRank": 2
485
+ }
486
+ }
487
+ ```
488
+
489
+ | Symptom | Likely cause |
490
+ |---|---|
491
+ | `legs: ["keyword"]`, no `vectorScore` | Only the trigram leg matched. Expected for paraphrase queries under the `local` provider. |
492
+ | `legs: ["vector"]` with a low `vectorScore` | Lexical overlap only. Rephrase, or switch provider. |
493
+ | `keywordScore` near 0 for every hit | The query terms are absent from the corpus, or under 3 characters. |
494
+ | No hits at all | Lower `min_score`, or set `SEARCH_MODE=keyword` to isolate which leg is failing. |
370
495
 
371
496
  ## Architecture
372
497
 
373
498
  ```
374
499
  src/
375
- ├── db/database.ts node:sqlite (documents, chunks, memories, chunks_fts, meta)
500
+ ├── db/database.ts node:sqlite (documents, chunks, memories, chunks_fts, meta) + integrity/backup/restore
376
501
  ├── rag/
377
- │ ├── embedder.ts local hashing embedder (1024-d, FNV-1a, n-grams)
502
+ │ ├── embedder.ts local hashing embedder (1024-d, FNV-1a, word + char n-grams)
378
503
  │ ├── embeddings.ts provider layer: local | transformers (optional dep)
379
504
  │ ├── chunker.ts paragraph/code-aware chunking with overlap
380
- │ ├── vector-search.ts vector cache + FTS5 BM25 + RRF hybrid scoring
505
+ │ ├── vector-search.ts vector cache + FTS5 BM25 + RRF hybrid scoring (alpha blend, RAG_RRF_K)
381
506
  │ └── pipeline.ts async ingest/search/retrieve, dedup, guards, doc mgmt
382
507
  ├── session/transcript.ts read opencode sessions (global+local DB), ingest inputs
383
- ├── memory/memory.ts remember / recall / consolidate + decay + prune
384
- ├── mcp/rag-server.ts MCP server (19 tools, stdio, npm bin)
385
- ├── cli.ts CLI playground (incl. sync-session / sync-latest / sync-logs)
508
+ ├── memory/memory.ts remember / recall / consolidate + decay + prune (last-activity anchored)
509
+ ├── mcp/rag-server.ts MCP server (21 tools, stdio, npm bin)
510
+ ├── cli.ts CLI playground (incl. sync-session / sync-latest / backup / restore)
386
511
  └── test/test-all.ts full test suite (unit + MCP round-trip)
387
512
  ```
388
513
 
@@ -398,7 +523,10 @@ Data lives in `.rag-data/rag.sqlite` (git-ignored).
398
523
  | `EMBEDDING_MODEL` | `Xenova/all-MiniLM-L6-v2` | Transformers model name |
399
524
  | `RAG_MAX_FILE_MB` | `10` | Reject files larger than this |
400
525
  | `RAG_ALLOWED_DIRS` | *(unset = anywhere)* | Semicolon/pipe/comma-separated allowed ingest roots |
526
+ | `RAG_RRF_K` | `60` | RRF constant for default hybrid ranking (read at call time) |
401
527
  | `RAG_MEMORY_HALF_LIFE_DAYS` | `14` | Recall score decay half-life |
528
+ | `RAG_DEDUP_MAX_VECTORS` | `500` | Above this many memories `consolidate` skips near-duplicate detection and reports `skippedDedup`. Raise it on a dedicated server (the pass is O(n²)) |
529
+ | `RAG_VECTOR_CACHE_WARN_MB` | `256` | Warn when the in-memory vector cache exceeds this size |
402
530
  | `RAG_PRUNE` | `0` | Set `1` to allow `consolidate` to delete non-essential memories |
403
531
  | `RAG_PRUNE_IMPORTANCE` | `0.2` | Delete memories below this importance |
404
532
  | `RAG_PRUNE_AGE_DAYS` | `90` | ...and older than this (never-recalled only) |
@@ -523,7 +651,7 @@ can slow down the TUI. This repo ships exactly one plugin
523
651
  `npx … sync-latest` per 60s, spawned detached with `stdio: "ignore"` and
524
652
  `shell: false`. If it still costs too much, set `RAG_AUTOSYNC=0` (keeps the
525
653
  plugin, disables the auto-sync) or drop the `plugin` entry from
526
- `opencode.json` — the MCP server and its 19 tools keep working, you just have
654
+ `opencode.json` — the MCP server and its 21 tools keep working, you just have
527
655
  to call `rag_sync_session` yourself.
528
656
 
529
657
  ---
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * ingest-text <title> <file|-> Ingest text (from file or stdin)
10
10
  * ingest-file <path> Ingest a single file
11
11
  * ingest-dir <dir> Ingest a directory
12
- * search <query> Semantic search over documents
12
+ * search <query> [--top-k N] [--min-score S] [--explain] [--alpha A] [--doc-id ID] [--source S]
13
13
  * retrieve <query> Retrieve context block
14
14
  * docs List documents
15
15
  * doc-stats Document stats
@@ -24,6 +24,9 @@
24
24
  * memory-stats
25
25
  * mem-context <topic>
26
26
  * stats Everything
27
+ * reindex [--batch N] Re-embed all vectors for the current model
28
+ * backup [path] Snapshot the store to a consistent SQLite file
29
+ * restore <path> Replace the store from a backup (offline — stop the server first)
27
30
  * sessions List opencode sessions (recent first)
28
31
  * sync-session <sessionId> [--limit N] Ingest a session's user inputs to RAG
29
32
  * sync-latest [--limit N] [--dir PATH] Ingest the most recent session (workspace-aware)
@@ -34,8 +37,10 @@ import "./env.js";
34
37
  import { ingestText, ingestFile, ingestDirectory, searchDocs, retrieve, listDocuments, deleteDocument, documentStats } from "./rag/pipeline.js";
35
38
  import { remember, recall, listMemories, getMemory, updateMemory, forget, consolidate, memoryStats, contextPrompt, MEMORY_TYPES } from "./memory/memory.js";
36
39
  import { ingestSession, ingestJsonlFile, ingestLogDir, ingestLatest, listOpenCodeSessions } from "./session/transcript.js";
37
- import { closeDB, STORAGE_DIR } from "./db/database.js";
40
+ import { reindex } from "./rag/reindex.js";
41
+ import { closeDB, STORAGE_DIR, backupStore, restoreStore } from "./db/database.js";
38
42
  import * as fs from "fs";
43
+ import * as path from "path";
39
44
  async function main() {
40
45
  const [, , cmd, ...rest] = process.argv;
41
46
  if (!cmd) {
@@ -47,7 +52,7 @@ async function main() {
47
52
  closeDB();
48
53
  }
49
54
  function helpText() {
50
- return `Commands: ingest-text|ingest-file|ingest-dir|search|retrieve|docs|doc-stats|rm-doc|remember|recall|memory-list|memory-get|memory-update|forget|consolidate|memory-stats|mem-context|stats|sessions|sync-session|sync-latest|sync-logs|ingest-jsonl`;
55
+ return `Commands: ingest-text|ingest-file|ingest-dir|search|retrieve|docs|doc-stats|rm-doc|remember|recall|memory-list|memory-get|memory-update|forget|consolidate|memory-stats|mem-context|stats|reindex|backup|restore|sessions|sync-session|sync-latest|sync-logs|ingest-jsonl`;
51
56
  }
52
57
  function assertMemoryType(type) {
53
58
  if (!MEMORY_TYPES.includes(type)) {
@@ -80,10 +85,14 @@ async function run(cmd, args) {
80
85
  break;
81
86
  case "search": {
82
87
  const parsed = parseOpts(args);
88
+ const alpha = toNum(parsed.opts.alpha, undefined);
89
+ if (alpha !== undefined && (alpha < 0 || alpha > 1)) {
90
+ throw new Error("--alpha must be between 0 and 1");
91
+ }
83
92
  out = await searchDocs(queryArg(parsed.positional), toNum(parsed.opts["top-k"], 10), toNum(parsed.opts["min-score"], 0.08), {
84
93
  docId: parsed.opts["doc-id"],
85
94
  source: parsed.opts.source,
86
- });
95
+ }, parsed.opts.explain !== undefined, alpha);
87
96
  break;
88
97
  }
89
98
  case "retrieve": {
@@ -181,6 +190,27 @@ async function run(cmd, args) {
181
190
  case "stats":
182
191
  out = { documents: documentStats(), memories: memoryStats(), dbDir: STORAGE_DIR };
183
192
  break;
193
+ case "reindex": {
194
+ const parsed = parseOpts(args);
195
+ out = await reindex({
196
+ batchSize: toNum(parsed.opts.batch, undefined),
197
+ onProgress: (p) => {
198
+ if (p.total > 0) {
199
+ process.stderr.write(`reindex ${p.phase}: ${p.done}/${p.total}\r`);
200
+ }
201
+ },
202
+ });
203
+ process.stderr.write("\n");
204
+ break;
205
+ }
206
+ case "backup": {
207
+ const target = args[0] ?? path.join(STORAGE_DIR, "backups", `rag-backup-${Date.now()}.sqlite`);
208
+ out = backupStore(target);
209
+ break;
210
+ }
211
+ case "restore":
212
+ out = restoreStore(requireArg(args[0], "restore <backup-file>"));
213
+ break;
184
214
  case "sessions": {
185
215
  const parsed = parseOpts(args);
186
216
  out = listOpenCodeSessions(toNum(parsed.opts.limit, 15) ?? 15, { directory: parsed.opts.dir });
@@ -11,6 +11,56 @@ export declare function packVector(v: Float64Array): Uint8Array;
11
11
  export declare function unpackVector(blob: Uint8Array | null): Float64Array | null;
12
12
  export declare function nowMs(): number;
13
13
  export declare function closeDB(): void;
14
+ export interface IntegrityReport {
15
+ ok: boolean;
16
+ errorCount: number;
17
+ firstError?: string;
18
+ }
19
+ /**
20
+ * Surface-level check for one page of corruption (the default pass) on either
21
+ * the live store or a standalone file. Reading the store while another process
22
+ * writes is safe here: integrity_check takes its own snapshot.
23
+ */
24
+ export declare function integrityCheck(targetPath?: string): IntegrityReport;
25
+ export interface StoreCounts {
26
+ documents: number;
27
+ chunks: number;
28
+ memories: number;
29
+ }
30
+ export declare function storeCounts(db?: DatabaseSync): StoreCounts;
31
+ export interface BackupReport extends StoreCounts {
32
+ path: string;
33
+ bytes: number;
34
+ integrity: IntegrityReport;
35
+ }
36
+ /**
37
+ * Consistent snapshot of the live store via `VACUUM INTO`. Unlike a raw file
38
+ * copy this works regardless of WAL state and never writes into the live DB.
39
+ * SQLite refuses to overwrite an existing target, which doubles as a built-in
40
+ * no-clobber guard for the tool surface.
41
+ */
42
+ export declare function backupStore(target: string): BackupReport;
43
+ export interface RestoreReport extends StoreCounts {
44
+ path: string;
45
+ restoredFrom: string;
46
+ integrity: IntegrityReport;
47
+ }
48
+ /**
49
+ * Replace the live store with a backup file, offline (run while no server is
50
+ * using the store). The current WAL journal is checkpointed and then discarded
51
+ * together with -shm before the copy, so a stale WAL belonging to the replaced
52
+ * database can never bleed into the restored one. The store is reopened and
53
+ * re-verified before returning; on failure it is left closed so a subsequent
54
+ * command surfaces the problem instead of running against a half state.
55
+ */
56
+ export declare function restoreStore(source: string): RestoreReport;
57
+ /** Health lamp for system_stats: runs integrity_check only on stores small enough that it cannot stall the server. */
58
+ export declare function storeHealthSummary(): {
59
+ status: "ok" | "corrupt" | "deferred";
60
+ errorCount?: number;
61
+ firstError?: string;
62
+ reason?: string;
63
+ };
14
64
  export declare function getEmbedDim(): number;
15
65
  export declare function setEmbedMeta(dim: number, model: string): void;
16
66
  /**
@@ -19,4 +69,12 @@ export declare function setEmbedMeta(dim: number, model: string): void;
19
69
  */
20
70
  export declare function ensureDim(vec: Float64Array, model: string): void;
21
71
  export declare function getEmbedModel(): string;
72
+ /**
73
+ * `embed_state` is '' (or 'ready') for a coherent store and 'reindexing' while a
74
+ * vector-space migration is in flight.
75
+ */
76
+ export declare function getEmbedState(): string;
77
+ export declare function setEmbedState(state: string): void;
78
+ /** Throws when the store is mid-reindex. Called from ensureDim, the shared gate. */
79
+ export declare function assertEmbedStateReady(): void;
22
80
  //# sourceMappingURL=database.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,eAAO,MAAM,WAAW,QAEoB,CAAC;AAE7C,eAAO,MAAM,OAAO,QAAuC,CAAC;AAU5D,wBAAgB,KAAK,IAAI,YAAY,CA0BpC;AA+GD,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,UAAU,CAEtD;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAGzE;AAED,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,wBAAgB,OAAO,SAItB;AASD,wBAAgB,WAAW,IAAI,MAAM,CAWpC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAStD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAwBhE;AAED,wBAAgB,aAAa,IAAI,MAAM,CAKtC"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,eAAO,MAAM,WAAW,QAEoB,CAAC;AAE7C,eAAO,MAAM,OAAO,QAAuC,CAAC;AAU5D,wBAAgB,KAAK,IAAI,YAAY,CA0BpC;AA+GD,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,UAAU,CAEtD;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAGzE;AAED,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,wBAAgB,OAAO,SAItB;AAMD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,eAAe,CAsBnE;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,WAAW,CAAC,EAAE,GAAE,YAAsB,GAAG,WAAW,CAOnE;AAED,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,eAAe,CAAC;CAC5B;AAOD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAgBxD;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CA6B1D;AAED,sHAAsH;AACtH,wBAAgB,kBAAkB,IAAI;IACpC,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,UAAU,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAaA;AASD,wBAAgB,WAAW,IAAI,MAAM,CAWpC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAWtD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA6BhE;AAED,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,IAAI,IAAI,CAS5C"}
@@ -173,6 +173,128 @@ export function closeDB() {
173
173
  _db = null;
174
174
  cachedDim = null;
175
175
  }
176
+ /**
177
+ * Surface-level check for one page of corruption (the default pass) on either
178
+ * the live store or a standalone file. Reading the store while another process
179
+ * writes is safe here: integrity_check takes its own snapshot.
180
+ */
181
+ export function integrityCheck(targetPath) {
182
+ // Opening a corrupt/foreign file can throw synchronously — that is exactly the
183
+ // case this helper exists to classify, so swallow it and report the failure.
184
+ let own;
185
+ try {
186
+ own = targetPath ? new DatabaseSync(path.resolve(targetPath), { readOnly: true }) : getDB();
187
+ }
188
+ catch (e) {
189
+ return { ok: false, errorCount: 1, firstError: String(e.message ?? e) };
190
+ }
191
+ let rows;
192
+ try {
193
+ rows = own.prepare("PRAGMA integrity_check").all();
194
+ }
195
+ catch (e) {
196
+ return { ok: false, errorCount: 1, firstError: String(e.message ?? e) };
197
+ }
198
+ finally {
199
+ if (targetPath)
200
+ own.close();
201
+ }
202
+ const errors = rows
203
+ .map((r) => String(r.integrity_check ?? Object.values(r)[0] ?? ""))
204
+ .filter((t) => t !== "ok");
205
+ if (errors.length === 0)
206
+ return { ok: true, errorCount: 0 };
207
+ return { ok: false, errorCount: errors.length, firstError: errors[0] };
208
+ }
209
+ export function storeCounts(db = getDB()) {
210
+ const one = (sql) => Number(db.prepare(sql).get().c);
211
+ return {
212
+ documents: one("SELECT COUNT(*) AS c FROM documents"),
213
+ chunks: one("SELECT COUNT(*) AS c FROM chunks"),
214
+ memories: one("SELECT COUNT(*) AS c FROM memories"),
215
+ };
216
+ }
217
+ /** Quote a path as a SQLite string literal (VACUUM INTO takes a literal, not a bound param). */
218
+ function sqliteLiteral(value) {
219
+ return "'" + value.replace(/'/g, "''") + "'";
220
+ }
221
+ /**
222
+ * Consistent snapshot of the live store via `VACUUM INTO`. Unlike a raw file
223
+ * copy this works regardless of WAL state and never writes into the live DB.
224
+ * SQLite refuses to overwrite an existing target, which doubles as a built-in
225
+ * no-clobber guard for the tool surface.
226
+ */
227
+ export function backupStore(target) {
228
+ const abs = path.resolve(target);
229
+ if (abs.toLowerCase() === DB_PATH.toLowerCase()) {
230
+ throw new Error("Backup target must not be the live store file");
231
+ }
232
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
233
+ getDB().exec(`VACUUM INTO ${sqliteLiteral(abs)}`);
234
+ const counts = storeCounts();
235
+ return {
236
+ path: abs,
237
+ bytes: fs.statSync(abs).size,
238
+ documents: counts.documents,
239
+ chunks: counts.chunks,
240
+ memories: counts.memories,
241
+ integrity: integrityCheck(abs),
242
+ };
243
+ }
244
+ /**
245
+ * Replace the live store with a backup file, offline (run while no server is
246
+ * using the store). The current WAL journal is checkpointed and then discarded
247
+ * together with -shm before the copy, so a stale WAL belonging to the replaced
248
+ * database can never bleed into the restored one. The store is reopened and
249
+ * re-verified before returning; on failure it is left closed so a subsequent
250
+ * command surfaces the problem instead of running against a half state.
251
+ */
252
+ export function restoreStore(source) {
253
+ const src = path.resolve(source);
254
+ if (!fs.existsSync(src) || !fs.statSync(src).isFile()) {
255
+ throw new Error(`Backup file not found: ${src}`);
256
+ }
257
+ if (src.toLowerCase() === DB_PATH.toLowerCase()) {
258
+ throw new Error("Source is the live store file itself; pick a backup copy");
259
+ }
260
+ try {
261
+ getDB().exec("PRAGMA wal_checkpoint(TRUNCATE);");
262
+ }
263
+ catch {
264
+ /* a closed or locked store has nothing to checkpoint */
265
+ }
266
+ closeDB();
267
+ try {
268
+ // -wal/-shm belong to the database being replaced; leaving them around lets
269
+ // SQLite replay a journal that has nothing to do with the restored file.
270
+ fs.rmSync(`${DB_PATH}-wal`, { force: true });
271
+ fs.rmSync(`${DB_PATH}-shm`, { force: true });
272
+ fs.copyFileSync(src, DB_PATH);
273
+ const db = getDB();
274
+ const integrity = integrityCheck();
275
+ const counts = storeCounts(db);
276
+ return { path: DB_PATH, restoredFrom: src, ...counts, integrity };
277
+ }
278
+ catch (e) {
279
+ throw new Error(`Restore failed (the store is closed; run any command to reopen it): ${e instanceof Error ? e.message : String(e)}`);
280
+ }
281
+ }
282
+ /** Health lamp for system_stats: runs integrity_check only on stores small enough that it cannot stall the server. */
283
+ export function storeHealthSummary() {
284
+ const counts = storeCounts();
285
+ const rows = counts.documents + counts.chunks + counts.memories;
286
+ const max = 100_000;
287
+ if (rows > max) {
288
+ return {
289
+ status: "deferred",
290
+ reason: `store has ${rows} rows; run 'rag_backup' or 'cli backup' to verify integrity`,
291
+ };
292
+ }
293
+ const rep = integrityCheck();
294
+ if (rep.ok)
295
+ return { status: "ok", errorCount: 0 };
296
+ return { status: "corrupt", errorCount: rep.errorCount, firstError: rep.firstError };
297
+ }
176
298
  /* ------------------------------------------------------------------ */
177
299
  /* Embedding dimension metadata */
178
300
  /* ------------------------------------------------------------------ */
@@ -193,12 +315,19 @@ export function setEmbedMeta(dim, model) {
193
315
  db.prepare("INSERT INTO meta(key, value) VALUES ('embed_dim', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(String(dim));
194
316
  db.prepare("INSERT INTO meta(key, value) VALUES ('embed_model', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(model);
195
317
  cachedDim = dim;
318
+ // A completed migration restores the store to a coherent state.
319
+ setEmbedState("ready");
196
320
  }
197
321
  /**
198
322
  * Lock the store to one embedding dimension. Call after producing a vector.
199
323
  * Prevents silently mixing vectors of different models/providers.
200
324
  */
201
325
  export function ensureDim(vec, model) {
326
+ // A half-migrated store mixes old and new vectors: cosine across two spaces
327
+ // is meaningless and every search silently returns noise. Blocking here stops
328
+ // it at the one chokepoint every search and ingest already passes through,
329
+ // rather than letting a partial reindex look like a working store.
330
+ assertEmbedStateReady();
202
331
  const current = getEmbedDim();
203
332
  if (current === 0) {
204
333
  setEmbedMeta(vec.length, model);
@@ -223,4 +352,26 @@ export function getEmbedModel() {
223
352
  const r = getDB().prepare("SELECT value FROM meta WHERE key = 'embed_model'").get();
224
353
  return r ? r.value : "";
225
354
  }
355
+ /**
356
+ * `embed_state` is '' (or 'ready') for a coherent store and 'reindexing' while a
357
+ * vector-space migration is in flight.
358
+ */
359
+ export function getEmbedState() {
360
+ const r = getDB().prepare("SELECT value FROM meta WHERE key = 'embed_state'").get();
361
+ return r ? r.value : "";
362
+ }
363
+ export function setEmbedState(state) {
364
+ getDB()
365
+ .prepare("INSERT INTO meta(key, value) VALUES('embed_state', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value")
366
+ .run(state);
367
+ }
368
+ /** Throws when the store is mid-reindex. Called from ensureDim, the shared gate. */
369
+ export function assertEmbedStateReady() {
370
+ const state = getEmbedState();
371
+ if (state !== "" && state !== "ready") {
372
+ throw new Error(`Store is mid-reindex (embed_state=${state}): vectors from two embedding models are ` +
373
+ `mixed and search results would be meaningless. Run 'reindex' again to finish the ` +
374
+ `migration. Current store: ${STORAGE_DIR}.`);
375
+ }
376
+ }
226
377
  //# sourceMappingURL=database.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU;IAC/C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACtC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;AAE7C,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;AAE5D,IAAI,GAAG,GAAwB,IAAI,CAAC;AAEpC,SAAS,SAAS;IAChB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,+DAA+D;QAC/D,EAAE,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACvC,EAAE,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACtC,EAAE,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACxC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACrC,4EAA4E;QAC5E,2EAA2E;QAC3E,OAAO,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,IAAI,CAAC;YACH,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,oBAAoB;QACtB,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;IACD,GAAG,GAAG,EAAE,CAAC;IACT,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,YAAY,CAAC,EAAgB,EAAE,KAAa,EAAE,MAAc;IACnE,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,GAAG,EAA6B,CAAC;IACxF,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,OAAO,CAAC,EAAgB;IAC/B,6EAA6E;IAC7E,4EAA4E;IAC5E,yDAAyD;IACzD,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC5B,IAAI,CAAC;QACH,YAAY,CAAC,EAAE,CAAC,CAAC;QACjB,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,gCAAgC;QAClC,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,EAAgB;IACpC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CP,CAAC,CAAC;IAEH,2EAA2E;IAC3E,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,WAAW,EAAE,cAAc,CAAC,EAAE,CAAC;QACnD,EAAE,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACjE,CAAC;IACD,EAAE,CAAC,IAAI,CACL,yHAAyH,CAC1H,CAAC;IAEF,sEAAsE;IACtE,yEAAyE;IACzE,4EAA4E;IAC5E,8EAA8E;IAC9E,MAAM,MAAM,GAAG,EAAE;SACd,OAAO,CAAC,4EAA4E,CAAC;SACrF,GAAG,EAAkC,CAAC;IACzC,IAAI,MAAM,EAAE,CAAC;QACX,8EAA8E;QAC9E,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,uEAAuE;QACvE,8EAA8E;QAC9E,qEAAqE;QACrE,UAAU,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;AACH,CAAC;AAED,6CAA6C;AAC7C,SAAS,UAAU,CAAC,EAAgB;IAClC,EAAE,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC5C,EAAE,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;IACtF,EAAE,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;AACvF,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,CAAe;IACxC,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAAC,IAAuB;IAClD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7E,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,GAAG,EAAE,KAAK,EAAE,CAAC;IACb,GAAG,GAAG,IAAI,CAAC;IACX,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAYD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAmB;IAChD,+EAA+E;IAC/E,6EAA6E;IAC7E,IAAI,GAAiB,CAAC;IACtB,IAAI,CAAC;QACH,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC9F,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAE,CAAW,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC;IACrF,CAAC;IACD,IAAI,IAAoC,CAAC;IACzC,IAAI,CAAC;QACH,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,GAAG,EAAoC,CAAC;IACvF,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAE,CAAW,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC;IACrF,CAAC;YAAS,CAAC;QACT,IAAI,UAAU;YAAE,GAAG,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IACD,MAAM,MAAM,GAAG,IAAI;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SAClE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC5D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AACzE,CAAC;AAQD,MAAM,UAAU,WAAW,CAAC,KAAmB,KAAK,EAAE;IACpD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,MAAM,CAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAoB,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO;QACL,SAAS,EAAE,GAAG,CAAC,qCAAqC,CAAC;QACrD,MAAM,EAAE,GAAG,CAAC,kCAAkC,CAAC;QAC/C,QAAQ,EAAE,GAAG,CAAC,oCAAoC,CAAC;KACpD,CAAC;AACJ,CAAC;AAQD,gGAAgG;AAChG,SAAS,aAAa,CAAC,KAAa;IAClC,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IACD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,KAAK,EAAE,CAAC,IAAI,CAAC,eAAe,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,OAAO;QACL,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI;QAC5B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,cAAc,CAAC,GAAG,CAAC;KAC/B,CAAC;AACJ,CAAC;AAQD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,CAAC;QACH,KAAK,EAAE,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;IACD,OAAO,EAAE,CAAC;IACV,IAAI,CAAC;QACH,4EAA4E;QAC5E,yEAAyE;QACzE,EAAE,CAAC,MAAM,CAAC,GAAG,OAAO,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,EAAE,CAAC,MAAM,CAAC,GAAG,OAAO,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC9B,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,cAAc,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC;IACpE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,uEAAuE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACpH,CAAC;IACJ,CAAC;AACH,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,kBAAkB;IAMhC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC;IACpB,IAAI,IAAI,GAAG,GAAG,EAAE,CAAC;QACf,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,aAAa,IAAI,6DAA6D;SACvF,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,cAAc,EAAE,CAAC;IAC7B,IAAI,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IACnD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;AACvF,CAAC;AAED,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AAExE,+EAA+E;AAC/E,IAAI,SAAS,GAAkB,IAAI,CAAC;AAEpC,MAAM,UAAU,WAAW;IACzB,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,OAAO,CAAC,gDAAgD,CAAC,CAAC,GAAG,EAElE,CAAC;QACd,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3B,uEAAuE;QACvE,iDAAiD;QACjD,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAa;IACrD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,EAAE,CAAC,OAAO,CACR,4GAA4G,CAC7G,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACnB,EAAE,CAAC,OAAO,CACR,8GAA8G,CAC/G,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACb,SAAS,GAAG,GAAG,CAAC;IAChB,gEAAgE;IAChE,aAAa,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAiB,EAAE,KAAa;IACxD,4EAA4E;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,mEAAmE;IACnE,qBAAqB,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,2CAA2C,OAAO,YAAY,aAAa,EAAE,KAAK;YAChF,mBAAmB,GAAG,CAAC,MAAM,YAAY,KAAK,KAAK;YACnD,+CAA+C,WAAW,GAAG,CAChE,CAAC;IACJ,CAAC;IACD,yEAAyE;IACzE,4EAA4E;IAC5E,+EAA+E;IAC/E,MAAM,YAAY,GAAG,aAAa,EAAE,CAAC;IACrC,IAAI,YAAY,IAAI,YAAY,KAAK,KAAK,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,uCAAuC,YAAY,eAAe,KAAK,UAAU,OAAO,SAAS;YAC/F,oFAAoF;YACpF,kBAAkB,WAAW,GAAG,CACnC,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,EAEpE,CAAC;IACd,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,EAEpE,CAAC;IACd,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,KAAK,EAAE;SACJ,OAAO,CAAC,6GAA6G,CAAC;SACtH,GAAG,CAAC,KAAK,CAAC,CAAC;AAChB,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAC9B,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,qCAAqC,KAAK,2CAA2C;YACnF,mFAAmF;YACnF,6BAA6B,WAAW,GAAG,CAC9C,CAAC;IACJ,CAAC;AACH,CAAC"}