@vortex-os/memory-extended 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +244 -0
  2. package/dist/consolidate/index.d.ts +7 -0
  3. package/dist/consolidate/index.d.ts.map +1 -0
  4. package/dist/consolidate/index.js +4 -0
  5. package/dist/consolidate/index.js.map +1 -0
  6. package/dist/consolidate/proposer.d.ts +43 -0
  7. package/dist/consolidate/proposer.d.ts.map +1 -0
  8. package/dist/consolidate/proposer.js +276 -0
  9. package/dist/consolidate/proposer.js.map +1 -0
  10. package/dist/consolidate/query.d.ts +32 -0
  11. package/dist/consolidate/query.d.ts.map +1 -0
  12. package/dist/consolidate/query.js +40 -0
  13. package/dist/consolidate/query.js.map +1 -0
  14. package/dist/consolidate/store.d.ts +21 -0
  15. package/dist/consolidate/store.d.ts.map +1 -0
  16. package/dist/consolidate/store.js +91 -0
  17. package/dist/consolidate/store.js.map +1 -0
  18. package/dist/consolidate/types.d.ts +68 -0
  19. package/dist/consolidate/types.d.ts.map +1 -0
  20. package/dist/consolidate/types.js +2 -0
  21. package/dist/consolidate/types.js.map +1 -0
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +7 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/internal/frontmatter.d.ts +6 -0
  27. package/dist/internal/frontmatter.d.ts.map +1 -0
  28. package/dist/internal/frontmatter.js +38 -0
  29. package/dist/internal/frontmatter.js.map +1 -0
  30. package/dist/internal/proactive-curator-helpers.d.ts +171 -0
  31. package/dist/internal/proactive-curator-helpers.d.ts.map +1 -0
  32. package/dist/internal/proactive-curator-helpers.js +162 -0
  33. package/dist/internal/proactive-curator-helpers.js.map +1 -0
  34. package/dist/mcp/document-tools.d.ts +144 -0
  35. package/dist/mcp/document-tools.d.ts.map +1 -0
  36. package/dist/mcp/document-tools.js +319 -0
  37. package/dist/mcp/document-tools.js.map +1 -0
  38. package/dist/mcp/index.d.ts +34 -0
  39. package/dist/mcp/index.d.ts.map +1 -0
  40. package/dist/mcp/index.js +29 -0
  41. package/dist/mcp/index.js.map +1 -0
  42. package/dist/mcp/install.d.ts +72 -0
  43. package/dist/mcp/install.d.ts.map +1 -0
  44. package/dist/mcp/install.js +92 -0
  45. package/dist/mcp/install.js.map +1 -0
  46. package/dist/mcp/memory-tools.d.ts +101 -0
  47. package/dist/mcp/memory-tools.d.ts.map +1 -0
  48. package/dist/mcp/memory-tools.js +105 -0
  49. package/dist/mcp/memory-tools.js.map +1 -0
  50. package/dist/mcp/recall-tool.d.ts +52 -0
  51. package/dist/mcp/recall-tool.d.ts.map +1 -0
  52. package/dist/mcp/recall-tool.js +60 -0
  53. package/dist/mcp/recall-tool.js.map +1 -0
  54. package/dist/mcp/server.d.ts +32 -0
  55. package/dist/mcp/server.d.ts.map +1 -0
  56. package/dist/mcp/server.js +113 -0
  57. package/dist/mcp/server.js.map +1 -0
  58. package/dist/recall/engine.d.ts +38 -0
  59. package/dist/recall/engine.d.ts.map +1 -0
  60. package/dist/recall/engine.js +113 -0
  61. package/dist/recall/engine.js.map +1 -0
  62. package/dist/recall/index.d.ts +22 -0
  63. package/dist/recall/index.d.ts.map +1 -0
  64. package/dist/recall/index.js +20 -0
  65. package/dist/recall/index.js.map +1 -0
  66. package/dist/recall/intent.d.ts +24 -0
  67. package/dist/recall/intent.d.ts.map +1 -0
  68. package/dist/recall/intent.js +95 -0
  69. package/dist/recall/intent.js.map +1 -0
  70. package/dist/recall/render.d.ts +11 -0
  71. package/dist/recall/render.d.ts.map +1 -0
  72. package/dist/recall/render.js +23 -0
  73. package/dist/recall/render.js.map +1 -0
  74. package/dist/recall/types.d.ts +72 -0
  75. package/dist/recall/types.d.ts.map +1 -0
  76. package/dist/recall/types.js +2 -0
  77. package/dist/recall/types.js.map +1 -0
  78. package/dist/sessionArchive/adapters/claude-code.d.ts +3 -0
  79. package/dist/sessionArchive/adapters/claude-code.d.ts.map +1 -0
  80. package/dist/sessionArchive/adapters/claude-code.js +276 -0
  81. package/dist/sessionArchive/adapters/claude-code.js.map +1 -0
  82. package/dist/sessionArchive/adapters/claude-desktop.d.ts +3 -0
  83. package/dist/sessionArchive/adapters/claude-desktop.d.ts.map +1 -0
  84. package/dist/sessionArchive/adapters/claude-desktop.js +234 -0
  85. package/dist/sessionArchive/adapters/claude-desktop.js.map +1 -0
  86. package/dist/sessionArchive/adapters/codex.d.ts +3 -0
  87. package/dist/sessionArchive/adapters/codex.d.ts.map +1 -0
  88. package/dist/sessionArchive/adapters/codex.js +322 -0
  89. package/dist/sessionArchive/adapters/codex.js.map +1 -0
  90. package/dist/sessionArchive/adapters/gemini.d.ts +3 -0
  91. package/dist/sessionArchive/adapters/gemini.d.ts.map +1 -0
  92. package/dist/sessionArchive/adapters/gemini.js +248 -0
  93. package/dist/sessionArchive/adapters/gemini.js.map +1 -0
  94. package/dist/sessionArchive/adapters/index.d.ts +5 -0
  95. package/dist/sessionArchive/adapters/index.d.ts.map +1 -0
  96. package/dist/sessionArchive/adapters/index.js +5 -0
  97. package/dist/sessionArchive/adapters/index.js.map +1 -0
  98. package/dist/sessionArchive/index.d.ts +9 -0
  99. package/dist/sessionArchive/index.d.ts.map +1 -0
  100. package/dist/sessionArchive/index.js +6 -0
  101. package/dist/sessionArchive/index.js.map +1 -0
  102. package/dist/sessionArchive/ingest.d.ts +68 -0
  103. package/dist/sessionArchive/ingest.d.ts.map +1 -0
  104. package/dist/sessionArchive/ingest.js +134 -0
  105. package/dist/sessionArchive/ingest.js.map +1 -0
  106. package/dist/sessionArchive/normalize.d.ts +15 -0
  107. package/dist/sessionArchive/normalize.d.ts.map +1 -0
  108. package/dist/sessionArchive/normalize.js +40 -0
  109. package/dist/sessionArchive/normalize.js.map +1 -0
  110. package/dist/sessionArchive/store.d.ts +118 -0
  111. package/dist/sessionArchive/store.d.ts.map +1 -0
  112. package/dist/sessionArchive/store.js +491 -0
  113. package/dist/sessionArchive/store.js.map +1 -0
  114. package/dist/sessionArchive/types.d.ts +124 -0
  115. package/dist/sessionArchive/types.d.ts.map +1 -0
  116. package/dist/sessionArchive/types.js +24 -0
  117. package/dist/sessionArchive/types.js.map +1 -0
  118. package/dist/sqlite/drift.d.ts +22 -0
  119. package/dist/sqlite/drift.d.ts.map +1 -0
  120. package/dist/sqlite/drift.js +69 -0
  121. package/dist/sqlite/drift.js.map +1 -0
  122. package/dist/sqlite/index.d.ts +22 -0
  123. package/dist/sqlite/index.d.ts.map +1 -0
  124. package/dist/sqlite/index.js +4 -0
  125. package/dist/sqlite/index.js.map +1 -0
  126. package/dist/sqlite/rebuild.d.ts +32 -0
  127. package/dist/sqlite/rebuild.d.ts.map +1 -0
  128. package/dist/sqlite/rebuild.js +80 -0
  129. package/dist/sqlite/rebuild.js.map +1 -0
  130. package/dist/sqlite/schema.d.ts +15 -0
  131. package/dist/sqlite/schema.d.ts.map +1 -0
  132. package/dist/sqlite/schema.js +41 -0
  133. package/dist/sqlite/schema.js.map +1 -0
  134. package/dist/sqlite/store.d.ts +49 -0
  135. package/dist/sqlite/store.d.ts.map +1 -0
  136. package/dist/sqlite/store.js +179 -0
  137. package/dist/sqlite/store.js.map +1 -0
  138. package/dist/sqlite/types.d.ts +57 -0
  139. package/dist/sqlite/types.d.ts.map +1 -0
  140. package/dist/sqlite/types.js +2 -0
  141. package/dist/sqlite/types.js.map +1 -0
  142. package/dist/vector/backend-brute.d.ts +38 -0
  143. package/dist/vector/backend-brute.d.ts.map +1 -0
  144. package/dist/vector/backend-brute.js +112 -0
  145. package/dist/vector/backend-brute.js.map +1 -0
  146. package/dist/vector/embedder.d.ts +59 -0
  147. package/dist/vector/embedder.d.ts.map +1 -0
  148. package/dist/vector/embedder.js +47 -0
  149. package/dist/vector/embedder.js.map +1 -0
  150. package/dist/vector/index.d.ts +24 -0
  151. package/dist/vector/index.d.ts.map +1 -0
  152. package/dist/vector/index.js +7 -0
  153. package/dist/vector/index.js.map +1 -0
  154. package/dist/vector/math.d.ts +21 -0
  155. package/dist/vector/math.d.ts.map +1 -0
  156. package/dist/vector/math.js +34 -0
  157. package/dist/vector/math.js.map +1 -0
  158. package/dist/vector/schema.d.ts +14 -0
  159. package/dist/vector/schema.d.ts.map +1 -0
  160. package/dist/vector/schema.js +24 -0
  161. package/dist/vector/schema.js.map +1 -0
  162. package/dist/vector/segment.d.ts +65 -0
  163. package/dist/vector/segment.d.ts.map +1 -0
  164. package/dist/vector/segment.js +72 -0
  165. package/dist/vector/segment.js.map +1 -0
  166. package/dist/vector/session.d.ts +90 -0
  167. package/dist/vector/session.d.ts.map +1 -0
  168. package/dist/vector/session.js +242 -0
  169. package/dist/vector/session.js.map +1 -0
  170. package/dist/vector/store.d.ts +69 -0
  171. package/dist/vector/store.d.ts.map +1 -0
  172. package/dist/vector/store.js +131 -0
  173. package/dist/vector/store.js.map +1 -0
  174. package/dist/vector/types.d.ts +109 -0
  175. package/dist/vector/types.d.ts.map +1 -0
  176. package/dist/vector/types.js +24 -0
  177. package/dist/vector/types.js.map +1 -0
  178. package/package.json +96 -0
  179. package/scripts/mcp-stdio.mjs +143 -0
  180. package/scripts/rebuild-memory-sqlite.mjs +39 -0
  181. package/scripts/rebuild-memory-vector.mjs +64 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sessionArchive/types.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,uGAAuG;AAEvG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAoIrD;;;;;GAKG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACzC,IAAI,GAAW,gBAAgB,CAAC;IACzC,YAAY,OAAO,GAAG,yGAAyG;QAC7H,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import type { MemorySqliteStore } from "./store.js";
2
+ import type { DriftReport } from "./types.js";
3
+ /**
4
+ * Compare the sqlite store against `data/_memory/` markdown on disk.
5
+ *
6
+ * Operator decision 3 (2026-05-29): drift is reported, not auto-fixed.
7
+ * The caller decides whether to re-run rebuild (treat markdown as truth)
8
+ * or accept the row (treat sqlite as truth). Auto-overwrite would silently
9
+ * lose local edits — out of scope for first cycle.
10
+ *
11
+ * Three drift kinds surface:
12
+ * - `missing-in-sqlite` — file exists on disk, no row in sqlite.
13
+ * - `missing-on-disk` — row in sqlite, no file on disk.
14
+ * - `body-hash-mismatch` — both present, body bytes differ.
15
+ *
16
+ * Frontmatter-only changes that do not touch the body are *not* drift in
17
+ * the body-hash sense. They are still re-imported on the next rebuild.
18
+ * If frontmatter-level drift detection becomes useful, it lands here as
19
+ * a separate kind.
20
+ */
21
+ export declare function driftCheck(store: MemorySqliteStore, memoryDir: string): Promise<DriftReport>;
22
+ //# sourceMappingURL=drift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../../src/sqlite/drift.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,iBAAiB,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CA6CtB"}
@@ -0,0 +1,69 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync } from "node:fs";
3
+ import { readFile, readdir } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { parseFrontmatter } from "../internal/frontmatter.js";
6
+ /**
7
+ * Compare the sqlite store against `data/_memory/` markdown on disk.
8
+ *
9
+ * Operator decision 3 (2026-05-29): drift is reported, not auto-fixed.
10
+ * The caller decides whether to re-run rebuild (treat markdown as truth)
11
+ * or accept the row (treat sqlite as truth). Auto-overwrite would silently
12
+ * lose local edits — out of scope for first cycle.
13
+ *
14
+ * Three drift kinds surface:
15
+ * - `missing-in-sqlite` — file exists on disk, no row in sqlite.
16
+ * - `missing-on-disk` — row in sqlite, no file on disk.
17
+ * - `body-hash-mismatch` — both present, body bytes differ.
18
+ *
19
+ * Frontmatter-only changes that do not touch the body are *not* drift in
20
+ * the body-hash sense. They are still re-imported on the next rebuild.
21
+ * If frontmatter-level drift detection becomes useful, it lands here as
22
+ * a separate kind.
23
+ */
24
+ export async function driftCheck(store, memoryDir) {
25
+ const rows = store.listAll();
26
+ const drifted = [];
27
+ const seenOnDisk = new Set();
28
+ const rowById = new Map(rows.map((r) => [r.id, r]));
29
+ let filesScanned = 0;
30
+ if (existsSync(memoryDir)) {
31
+ const entries = await readdir(memoryDir, { withFileTypes: true });
32
+ for (const e of entries) {
33
+ if (!e.isFile() || !e.name.endsWith(".md"))
34
+ continue;
35
+ if (e.name === "MEMORY.md" || e.name === "README.md" || e.name === "_INDEX.md")
36
+ continue;
37
+ filesScanned++;
38
+ const id = e.name.replace(/\.md$/i, "");
39
+ seenOnDisk.add(id);
40
+ const row = rowById.get(id);
41
+ const raw = await readFile(join(memoryDir, e.name), "utf8");
42
+ const { body } = parseFrontmatter(raw);
43
+ const currentHash = createHash("sha256").update(body).digest("hex");
44
+ if (!row) {
45
+ drifted.push({ id, kind: "missing-in-sqlite", currentHash });
46
+ continue;
47
+ }
48
+ if (row.bodyHash !== currentHash) {
49
+ drifted.push({
50
+ id,
51
+ kind: "body-hash-mismatch",
52
+ storedHash: row.bodyHash,
53
+ currentHash,
54
+ });
55
+ }
56
+ }
57
+ }
58
+ for (const row of rows) {
59
+ if (!seenOnDisk.has(row.id)) {
60
+ drifted.push({
61
+ id: row.id,
62
+ kind: "missing-on-disk",
63
+ storedHash: row.bodyHash,
64
+ });
65
+ }
66
+ }
67
+ return { filesScanned, rowsScanned: rows.length, drifted };
68
+ }
69
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/sqlite/drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `sqlite` namespace — structured index over `data/_memory/*.md`.
3
+ *
4
+ * Phase 11a shipped (2026-05-29). Five operator decisions backed the
5
+ * implementation; see `docs/memory-extended-design.md` §sqlite namespace
6
+ * for the rationale:
7
+ *
8
+ * 1. DB file location — `data/_indexes/memory.sqlite`
9
+ * 2. Schema shape — hybrid columns + frontmatter_json
10
+ * 3. Drift policy — log + skip (non-destructive)
11
+ * 4. Rebuild surface — one-shot `npm run rebuild-memory-sqlite`
12
+ * 5. Query surface — byType / byTag / byPrivacy / updatedSince
13
+ *
14
+ * Public exports below. Consumers feature-check `MemorySqliteStore` to
15
+ * confirm the namespace is present in the installed version.
16
+ */
17
+ export type { DriftEntry, DriftReport, MemoryQuery, MemoryRow, } from "./types.js";
18
+ export { MemorySqliteStore } from "./store.js";
19
+ export { rebuildFromMemoryDir, readRowFromFile } from "./rebuild.js";
20
+ export type { RebuildResult } from "./rebuild.js";
21
+ export { driftCheck } from "./drift.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,YAAY,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACrE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { MemorySqliteStore } from "./store.js";
2
+ export { rebuildFromMemoryDir, readRowFromFile } from "./rebuild.js";
3
+ export { driftCheck } from "./drift.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { MemorySqliteStore } from "./store.js";
2
+ import type { MemoryRow } from "./types.js";
3
+ /**
4
+ * Rebuild result returned by {@link rebuildFromMemoryDir}.
5
+ *
6
+ * - `scanned` — total .md files inspected.
7
+ * - `upserted` — rows written to sqlite.
8
+ * - `skipped` — files that lacked the minimum frontmatter (`name` + `type`)
9
+ * and were ignored rather than half-imported.
10
+ */
11
+ export interface RebuildResult {
12
+ readonly scanned: number;
13
+ readonly upserted: number;
14
+ readonly skipped: number;
15
+ }
16
+ /**
17
+ * Scan a memory directory, parse each `*.md` file, and upsert into the
18
+ * store. Idempotent — running twice on an unchanged directory writes the
19
+ * same rows back without surprise.
20
+ *
21
+ * Files without `name` or `type` frontmatter are skipped (they cannot be
22
+ * keyed); this is by design and not an error. The caller decides whether
23
+ * to surface them.
24
+ */
25
+ export declare function rebuildFromMemoryDir(store: MemorySqliteStore, memoryDir: string): Promise<RebuildResult>;
26
+ /**
27
+ * Parse one markdown file into a `MemoryRow`. Returns `null` when the
28
+ * file lacks the minimum required frontmatter — keeps the rebuild loop
29
+ * simple by externalizing the skip decision.
30
+ */
31
+ export declare function readRowFromFile(id: string, absPath: string): Promise<MemoryRow | null>;
32
+ //# sourceMappingURL=rebuild.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild.d.ts","sourceRoot":"","sources":["../../src/sqlite/rebuild.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,iBAAiB,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CAsBxB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAyB3B"}
@@ -0,0 +1,80 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync } from "node:fs";
3
+ import { readFile, readdir } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { parseFrontmatter } from "../internal/frontmatter.js";
6
+ /**
7
+ * Scan a memory directory, parse each `*.md` file, and upsert into the
8
+ * store. Idempotent — running twice on an unchanged directory writes the
9
+ * same rows back without surprise.
10
+ *
11
+ * Files without `name` or `type` frontmatter are skipped (they cannot be
12
+ * keyed); this is by design and not an error. The caller decides whether
13
+ * to surface them.
14
+ */
15
+ export async function rebuildFromMemoryDir(store, memoryDir) {
16
+ if (!existsSync(memoryDir)) {
17
+ return { scanned: 0, upserted: 0, skipped: 0 };
18
+ }
19
+ let scanned = 0;
20
+ let upserted = 0;
21
+ let skipped = 0;
22
+ const entries = await readdir(memoryDir, { withFileTypes: true });
23
+ for (const e of entries) {
24
+ if (!e.isFile() || !e.name.endsWith(".md"))
25
+ continue;
26
+ if (e.name === "MEMORY.md" || e.name === "README.md" || e.name === "_INDEX.md")
27
+ continue;
28
+ scanned++;
29
+ const id = e.name.replace(/\.md$/i, "");
30
+ const row = await readRowFromFile(id, join(memoryDir, e.name));
31
+ if (!row) {
32
+ skipped++;
33
+ continue;
34
+ }
35
+ store.upsert(row);
36
+ upserted++;
37
+ }
38
+ return { scanned, upserted, skipped };
39
+ }
40
+ /**
41
+ * Parse one markdown file into a `MemoryRow`. Returns `null` when the
42
+ * file lacks the minimum required frontmatter — keeps the rebuild loop
43
+ * simple by externalizing the skip decision.
44
+ */
45
+ export async function readRowFromFile(id, absPath) {
46
+ const raw = await readFile(absPath, "utf8");
47
+ const { frontmatter, body } = parseFrontmatter(raw);
48
+ const name = pickString(frontmatter.name) ?? id;
49
+ const type = pickString(frontmatter.type);
50
+ if (!type)
51
+ return null;
52
+ const description = pickString(frontmatter.description) ?? "";
53
+ const privacy = pickString(frontmatter.privacy) ?? "internal";
54
+ const created = pickString(frontmatter.created);
55
+ const updated = pickString(frontmatter.updated);
56
+ const tags = pickStringArray(frontmatter.tags);
57
+ const bodyHash = createHash("sha256").update(body).digest("hex");
58
+ return {
59
+ id,
60
+ name,
61
+ description,
62
+ type,
63
+ privacy,
64
+ created,
65
+ updated,
66
+ tags,
67
+ body,
68
+ bodyHash,
69
+ frontmatterJson: JSON.stringify(frontmatter),
70
+ };
71
+ }
72
+ function pickString(v) {
73
+ return typeof v === "string" ? v : null;
74
+ }
75
+ function pickStringArray(v) {
76
+ if (!Array.isArray(v))
77
+ return [];
78
+ return v.filter((x) => typeof x === "string");
79
+ }
80
+ //# sourceMappingURL=rebuild.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild.js","sourceRoot":"","sources":["../../src/sqlite/rebuild.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CREATE TABLE statements + tag-table layout for the memory sqlite store.
3
+ *
4
+ * The schema follows operator decision 2 (2026-05-29): hybrid columns
5
+ * for frequently-queried fields + a JSON column for the rest. Run once
6
+ * at store open via `db.exec(SCHEMA)`; the `CREATE TABLE IF NOT EXISTS`
7
+ * form makes it idempotent.
8
+ *
9
+ * No migrations infrastructure on the first cycle. If a column needs to
10
+ * change, the next minor adds a one-shot migration script. Schema churn
11
+ * is rare for a memory store; we trade an upfront migration runner for
12
+ * simpler 0.x code.
13
+ */
14
+ export declare const SCHEMA = "\nCREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n description TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL,\n privacy TEXT NOT NULL DEFAULT 'internal',\n created TEXT,\n updated TEXT,\n body TEXT NOT NULL,\n body_hash TEXT NOT NULL,\n frontmatter_json TEXT NOT NULL DEFAULT '{}'\n);\n\nCREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\nCREATE INDEX IF NOT EXISTS idx_memories_privacy ON memories(privacy);\nCREATE INDEX IF NOT EXISTS idx_memories_updated ON memories(updated);\n\nCREATE TABLE IF NOT EXISTS memory_tags (\n memory_id TEXT NOT NULL,\n tag TEXT NOT NULL,\n PRIMARY KEY (memory_id, tag),\n FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE\n);\n\nCREATE INDEX IF NOT EXISTS idx_memory_tags_tag ON memory_tags(tag);\n";
15
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/sqlite/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,MAAM,kzBA0BlB,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * CREATE TABLE statements + tag-table layout for the memory sqlite store.
3
+ *
4
+ * The schema follows operator decision 2 (2026-05-29): hybrid columns
5
+ * for frequently-queried fields + a JSON column for the rest. Run once
6
+ * at store open via `db.exec(SCHEMA)`; the `CREATE TABLE IF NOT EXISTS`
7
+ * form makes it idempotent.
8
+ *
9
+ * No migrations infrastructure on the first cycle. If a column needs to
10
+ * change, the next minor adds a one-shot migration script. Schema churn
11
+ * is rare for a memory store; we trade an upfront migration runner for
12
+ * simpler 0.x code.
13
+ */
14
+ export const SCHEMA = `
15
+ CREATE TABLE IF NOT EXISTS memories (
16
+ id TEXT PRIMARY KEY,
17
+ name TEXT NOT NULL,
18
+ description TEXT NOT NULL DEFAULT '',
19
+ type TEXT NOT NULL,
20
+ privacy TEXT NOT NULL DEFAULT 'internal',
21
+ created TEXT,
22
+ updated TEXT,
23
+ body TEXT NOT NULL,
24
+ body_hash TEXT NOT NULL,
25
+ frontmatter_json TEXT NOT NULL DEFAULT '{}'
26
+ );
27
+
28
+ CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
29
+ CREATE INDEX IF NOT EXISTS idx_memories_privacy ON memories(privacy);
30
+ CREATE INDEX IF NOT EXISTS idx_memories_updated ON memories(updated);
31
+
32
+ CREATE TABLE IF NOT EXISTS memory_tags (
33
+ memory_id TEXT NOT NULL,
34
+ tag TEXT NOT NULL,
35
+ PRIMARY KEY (memory_id, tag),
36
+ FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
37
+ );
38
+
39
+ CREATE INDEX IF NOT EXISTS idx_memory_tags_tag ON memory_tags(tag);
40
+ `;
41
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/sqlite/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BrB,CAAC"}
@@ -0,0 +1,49 @@
1
+ import type { MemoryQuery, MemoryRow } from "./types.js";
2
+ /**
3
+ * SQLite-backed store mirroring `data/_memory/*.md`. The store is a
4
+ * derived index — markdown remains the source of truth (see
5
+ * `docs/memory-extended-design.md` §Non-goal). Delete the .sqlite file
6
+ * and re-run `npm run rebuild-memory-sqlite` to regenerate.
7
+ *
8
+ * Construction is open(path) — synchronous; better-sqlite3 is sync by
9
+ * design. Close with `close()` to release the file lock (matters on
10
+ * Windows; less so on POSIX).
11
+ *
12
+ * Query surface is the minimal four (operator decision 5 / 2026-05-29):
13
+ * `byType`, `byTag`, `byPrivacy`, `updatedSince`. They compose via the
14
+ * generic `query(q)` method when more than one filter is needed.
15
+ *
16
+ * Writes are `upsert` (INSERT OR REPLACE) + `deleteById`. The schema's
17
+ * ON DELETE CASCADE handles tag-table cleanup for free.
18
+ */
19
+ export declare class MemorySqliteStore {
20
+ readonly dbPath: string;
21
+ private db;
22
+ constructor(dbPath: string);
23
+ close(): void;
24
+ /** Upsert a row + its tags. Atomic via SQLite transaction. */
25
+ upsert(row: MemoryRow): void;
26
+ /** Delete a row + its tags (cascade). */
27
+ deleteById(id: string): boolean;
28
+ /** Return all rows. Use sparingly — primarily for rebuild + drift scans. */
29
+ listAll(): readonly MemoryRow[];
30
+ /** Read a single row by id (or null if absent). */
31
+ getById(id: string): MemoryRow | null;
32
+ byType(type: string): readonly MemoryRow[];
33
+ byTag(tag: string): readonly MemoryRow[];
34
+ byPrivacy(privacy: string): readonly MemoryRow[];
35
+ /**
36
+ * Memories with `updated` >= the given ISO date string (or epoch ms).
37
+ * Accepts ms because that's how the orchestrator typically tracks
38
+ * "since last consolidate run."
39
+ */
40
+ updatedSince(since: string | number): readonly MemoryRow[];
41
+ /**
42
+ * Composite query. All present fields AND together; list-valued fields
43
+ * OR within themselves. Use this when more than one filter applies; the
44
+ * single-field helpers above are thin wrappers.
45
+ */
46
+ query(q: MemoryQuery): readonly MemoryRow[];
47
+ private hydrate;
48
+ }
49
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/sqlite/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAa1B,KAAK,IAAI,IAAI;IAIb,8DAA8D;IAC9D,MAAM,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI;IA+B5B,yCAAyC;IACzC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAO/B,4EAA4E;IAC5E,OAAO,IAAI,SAAS,SAAS,EAAE;IAO/B,mDAAmD;IACnD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAOrC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAI1C,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAIxC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,SAAS,EAAE;IAIhD;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,SAAS,EAAE;IAO1D;;;;OAIG;IACH,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,SAAS,SAAS,EAAE;IAoC3C,OAAO,CAAC,OAAO;CAkBhB"}
@@ -0,0 +1,179 @@
1
+ import { chmodSync, mkdirSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import Database from "better-sqlite3";
4
+ import { SCHEMA } from "./schema.js";
5
+ /**
6
+ * SQLite-backed store mirroring `data/_memory/*.md`. The store is a
7
+ * derived index — markdown remains the source of truth (see
8
+ * `docs/memory-extended-design.md` §Non-goal). Delete the .sqlite file
9
+ * and re-run `npm run rebuild-memory-sqlite` to regenerate.
10
+ *
11
+ * Construction is open(path) — synchronous; better-sqlite3 is sync by
12
+ * design. Close with `close()` to release the file lock (matters on
13
+ * Windows; less so on POSIX).
14
+ *
15
+ * Query surface is the minimal four (operator decision 5 / 2026-05-29):
16
+ * `byType`, `byTag`, `byPrivacy`, `updatedSince`. They compose via the
17
+ * generic `query(q)` method when more than one filter is needed.
18
+ *
19
+ * Writes are `upsert` (INSERT OR REPLACE) + `deleteById`. The schema's
20
+ * ON DELETE CASCADE handles tag-table cleanup for free.
21
+ */
22
+ export class MemorySqliteStore {
23
+ dbPath;
24
+ db;
25
+ constructor(dbPath) {
26
+ // Restrict the index dir/file on multi-user POSIX hosts (no-op on Windows).
27
+ // The sqlite index mirrors data/_memory/*.md, so keep it owner-only.
28
+ mkdirSync(dirname(dbPath), { recursive: true, mode: 0o700 });
29
+ chmodQuietly(dirname(dbPath), 0o700);
30
+ this.dbPath = dbPath;
31
+ this.db = new Database(dbPath);
32
+ chmodQuietly(dbPath, 0o600);
33
+ this.db.pragma("journal_mode = WAL");
34
+ this.db.pragma("foreign_keys = ON");
35
+ this.db.exec(SCHEMA);
36
+ }
37
+ close() {
38
+ this.db.close();
39
+ }
40
+ /** Upsert a row + its tags. Atomic via SQLite transaction. */
41
+ upsert(row) {
42
+ const tx = this.db.transaction(() => {
43
+ this.db
44
+ .prepare(`INSERT OR REPLACE INTO memories
45
+ (id, name, description, type, privacy, created, updated, body, body_hash, frontmatter_json)
46
+ VALUES (@id, @name, @description, @type, @privacy, @created, @updated, @body, @bodyHash, @frontmatterJson)`)
47
+ .run({
48
+ id: row.id,
49
+ name: row.name,
50
+ description: row.description,
51
+ type: row.type,
52
+ privacy: row.privacy,
53
+ created: row.created,
54
+ updated: row.updated,
55
+ body: row.body,
56
+ bodyHash: row.bodyHash,
57
+ frontmatterJson: row.frontmatterJson,
58
+ });
59
+ this.db
60
+ .prepare(`DELETE FROM memory_tags WHERE memory_id = ?`)
61
+ .run(row.id);
62
+ const tagInsert = this.db.prepare(`INSERT INTO memory_tags (memory_id, tag) VALUES (?, ?)`);
63
+ for (const tag of row.tags)
64
+ tagInsert.run(row.id, tag);
65
+ });
66
+ tx();
67
+ }
68
+ /** Delete a row + its tags (cascade). */
69
+ deleteById(id) {
70
+ const res = this.db
71
+ .prepare(`DELETE FROM memories WHERE id = ?`)
72
+ .run(id);
73
+ return res.changes > 0;
74
+ }
75
+ /** Return all rows. Use sparingly — primarily for rebuild + drift scans. */
76
+ listAll() {
77
+ const rows = this.db
78
+ .prepare(`SELECT id, name, description, type, privacy, created, updated, body, body_hash, frontmatter_json FROM memories`)
79
+ .all();
80
+ return rows.map((r) => this.hydrate(r));
81
+ }
82
+ /** Read a single row by id (or null if absent). */
83
+ getById(id) {
84
+ const row = this.db
85
+ .prepare(`SELECT id, name, description, type, privacy, created, updated, body, body_hash, frontmatter_json FROM memories WHERE id = ?`)
86
+ .get(id);
87
+ return row ? this.hydrate(row) : null;
88
+ }
89
+ byType(type) {
90
+ return this.query({ type: [type] });
91
+ }
92
+ byTag(tag) {
93
+ return this.query({ tags: [tag] });
94
+ }
95
+ byPrivacy(privacy) {
96
+ return this.query({ privacy: [privacy] });
97
+ }
98
+ /**
99
+ * Memories with `updated` >= the given ISO date string (or epoch ms).
100
+ * Accepts ms because that's how the orchestrator typically tracks
101
+ * "since last consolidate run."
102
+ */
103
+ updatedSince(since) {
104
+ const iso = typeof since === "number"
105
+ ? new Date(since).toISOString().slice(0, 10)
106
+ : since;
107
+ return this.query({ updatedSinceMs: new Date(iso).getTime() });
108
+ }
109
+ /**
110
+ * Composite query. All present fields AND together; list-valued fields
111
+ * OR within themselves. Use this when more than one filter applies; the
112
+ * single-field helpers above are thin wrappers.
113
+ */
114
+ query(q) {
115
+ const wheres = [];
116
+ const params = [];
117
+ if (q.type && q.type.length > 0) {
118
+ wheres.push(`type IN (${q.type.map(() => "?").join(", ")})`);
119
+ params.push(...q.type);
120
+ }
121
+ if (q.privacy && q.privacy.length > 0) {
122
+ wheres.push(`privacy IN (${q.privacy.map(() => "?").join(", ")})`);
123
+ params.push(...q.privacy);
124
+ }
125
+ if (q.updatedSinceMs !== undefined) {
126
+ const iso = new Date(q.updatedSinceMs).toISOString().slice(0, 10);
127
+ wheres.push(`updated >= ?`);
128
+ params.push(iso);
129
+ }
130
+ let baseSql = `SELECT m.id, m.name, m.description, m.type, m.privacy, m.created, m.updated, m.body, m.body_hash, m.frontmatter_json FROM memories m`;
131
+ if (q.tags && q.tags.length > 0) {
132
+ baseSql += ` JOIN memory_tags t ON t.memory_id = m.id`;
133
+ wheres.push(`t.tag IN (${q.tags.map(() => "?").join(", ")})`);
134
+ params.push(...q.tags);
135
+ }
136
+ if (wheres.length > 0)
137
+ baseSql += ` WHERE ${wheres.join(" AND ")}`;
138
+ baseSql += ` GROUP BY m.id ORDER BY m.updated DESC NULLS LAST`;
139
+ let rows;
140
+ try {
141
+ rows = this.db.prepare(baseSql).all(...params);
142
+ }
143
+ catch {
144
+ // SQLite versions older than 3.30 reject `NULLS LAST`. Fall back.
145
+ const safeSql = baseSql.replace(" NULLS LAST", "");
146
+ rows = this.db.prepare(safeSql).all(...params);
147
+ }
148
+ return rows.map((r) => this.hydrate(r));
149
+ }
150
+ hydrate(r) {
151
+ const tagRows = this.db
152
+ .prepare(`SELECT tag FROM memory_tags WHERE memory_id = ? ORDER BY tag ASC`)
153
+ .all(r.id);
154
+ return {
155
+ id: r.id,
156
+ name: r.name,
157
+ description: r.description,
158
+ type: r.type,
159
+ privacy: r.privacy,
160
+ created: r.created,
161
+ updated: r.updated,
162
+ body: r.body,
163
+ bodyHash: r.body_hash,
164
+ frontmatterJson: r.frontmatter_json,
165
+ tags: tagRows.map((t) => t.tag),
166
+ };
167
+ }
168
+ }
169
+ // Best-effort POSIX permission hardening. Intentional no-op on Windows /
170
+ // unsupported FS — the index must open even if the mode bit cannot be set.
171
+ function chmodQuietly(path, mode) {
172
+ try {
173
+ chmodSync(path, mode);
174
+ }
175
+ catch {
176
+ /* no-op on Windows / unsupported FS */
177
+ }
178
+ }
179
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sqlite/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Row stored in the `memories` table — mirrors a markdown file under
3
+ * `data/_memory/`. Hybrid schema (operator decision 2 / 2026-05-29):
4
+ * frequently-queried fields are promoted to columns; the full frontmatter
5
+ * lands in `frontmatter_json` so adding a new frontmatter field does not
6
+ * trigger a schema migration.
7
+ *
8
+ * `id` is the filename stem (e.g. `feedback_response_concise` for
9
+ * `feedback_response_concise.md`). `body_hash` is sha256 over the markdown
10
+ * body and is the load-bearing field for drift detection: if the rebuilt
11
+ * hash differs from the stored one, the markdown file has changed since
12
+ * the last rebuild.
13
+ */
14
+ export interface MemoryRow {
15
+ readonly id: string;
16
+ readonly name: string;
17
+ readonly description: string;
18
+ readonly type: string;
19
+ readonly privacy: string;
20
+ readonly created: string | null;
21
+ readonly updated: string | null;
22
+ readonly tags: readonly string[];
23
+ readonly bodyHash: string;
24
+ readonly body: string;
25
+ /** Full frontmatter serialized as JSON. Source of truth for any field not in columns. */
26
+ readonly frontmatterJson: string;
27
+ }
28
+ /**
29
+ * Structured query input. All fields optional — the store treats absent
30
+ * fields as "no constraint." Composition is AND across fields, OR within a
31
+ * field that takes a list (`type: ["feedback", "project"]` matches either).
32
+ *
33
+ * The 11a surface deliberately starts narrow: type / tag / privacy /
34
+ * updatedSince. Phase 11c hybrid recall extends from here with text search
35
+ * + vector similarity; that surface lives in the `recall` namespace, not
36
+ * here, so the sqlite query type does not grow to swallow it.
37
+ */
38
+ export interface MemoryQuery {
39
+ readonly type?: readonly string[];
40
+ readonly tags?: readonly string[];
41
+ readonly privacy?: readonly string[];
42
+ readonly updatedSinceMs?: number;
43
+ }
44
+ /** Single entry returned by `driftCheck`. */
45
+ export interface DriftEntry {
46
+ readonly id: string;
47
+ readonly kind: "missing-in-sqlite" | "missing-on-disk" | "body-hash-mismatch";
48
+ readonly storedHash?: string;
49
+ readonly currentHash?: string;
50
+ }
51
+ /** Aggregate result of a drift scan. */
52
+ export interface DriftReport {
53
+ readonly filesScanned: number;
54
+ readonly rowsScanned: number;
55
+ readonly drifted: readonly DriftEntry[];
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sqlite/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,6CAA6C;AAC7C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CACzC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sqlite/types.ts"],"names":[],"mappings":""}