@j0hanz/memdb 1.0.5 → 1.0.7

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 (57) hide show
  1. package/README.md +46 -24
  2. package/dist/core/database.d.ts.map +1 -1
  3. package/dist/core/database.js +3 -2
  4. package/dist/core/database.js.map +1 -1
  5. package/dist/core/db-helpers.d.ts +10 -0
  6. package/dist/core/db-helpers.d.ts.map +1 -0
  7. package/dist/core/db-helpers.js +17 -0
  8. package/dist/core/db-helpers.js.map +1 -0
  9. package/dist/core/memory-helpers.d.ts +3 -0
  10. package/dist/core/memory-helpers.d.ts.map +1 -0
  11. package/dist/core/memory-helpers.js +18 -0
  12. package/dist/core/memory-helpers.js.map +1 -0
  13. package/dist/core/memory-service.d.ts +5 -4
  14. package/dist/core/memory-service.d.ts.map +1 -1
  15. package/dist/core/memory-service.js +15 -108
  16. package/dist/core/memory-service.js.map +1 -1
  17. package/dist/core/memory-stats.d.ts +3 -0
  18. package/dist/core/memory-stats.d.ts.map +1 -0
  19. package/dist/core/memory-stats.js +44 -0
  20. package/dist/core/memory-stats.js.map +1 -0
  21. package/dist/core/memory-updates.d.ts +11 -0
  22. package/dist/core/memory-updates.d.ts.map +1 -0
  23. package/dist/core/memory-updates.js +102 -0
  24. package/dist/core/memory-updates.js.map +1 -0
  25. package/dist/core/relation-queries.d.ts.map +1 -1
  26. package/dist/core/relation-queries.js +26 -25
  27. package/dist/core/relation-queries.js.map +1 -1
  28. package/dist/core/search.d.ts +9 -0
  29. package/dist/core/search.d.ts.map +1 -0
  30. package/dist/core/search.js +57 -0
  31. package/dist/core/search.js.map +1 -0
  32. package/dist/core/tag-helpers.d.ts +2 -0
  33. package/dist/core/tag-helpers.d.ts.map +1 -0
  34. package/dist/core/tag-helpers.js +22 -0
  35. package/dist/core/tag-helpers.js.map +1 -0
  36. package/dist/index.js +52 -56
  37. package/dist/index.js.map +1 -1
  38. package/dist/schemas/inputs.d.ts +16 -0
  39. package/dist/schemas/inputs.d.ts.map +1 -1
  40. package/dist/schemas/inputs.js +40 -0
  41. package/dist/schemas/inputs.js.map +1 -1
  42. package/dist/schemas/outputs.d.ts.map +1 -1
  43. package/dist/schemas/outputs.js +25 -2
  44. package/dist/schemas/outputs.js.map +1 -1
  45. package/dist/tools/index.d.ts.map +1 -1
  46. package/dist/tools/index.js +18 -4
  47. package/dist/tools/index.js.map +1 -1
  48. package/dist/types/index.d.ts +8 -0
  49. package/dist/types/index.d.ts.map +1 -1
  50. package/dist/utils/config.d.ts +2 -0
  51. package/dist/utils/config.d.ts.map +1 -1
  52. package/dist/utils/config.js +28 -6
  53. package/dist/utils/config.js.map +1 -1
  54. package/dist/utils/logger.d.ts.map +1 -1
  55. package/dist/utils/logger.js +6 -12
  56. package/dist/utils/logger.js.map +1 -1
  57. package/package.json +1 -1
package/README.md CHANGED
@@ -15,9 +15,9 @@ A SQLite-backed MCP memory server (on-disk by default, in-memory optional).
15
15
  | Feature | Description |
16
16
  | :---------------- | :---------------------------------------------------------------- |
17
17
  | Memory Storage | Store text memories with tags, importance, and type |
18
- | Full-Text Search | FTS5-backed phrase search with relevance ranking |
18
+ | Full-Text Search | FTS5-backed tokenized search with relevance ranking |
19
19
  | Graph Connections | Link memories and traverse relationships |
20
- | Stats | Memory and relationship counts |
20
+ | Stats | Memory, tag, and relationship counts + activity range |
21
21
  | Local Privacy | All data stored locally in SQLite (`.memdb/memory.db` by default) |
22
22
 
23
23
  ## Quick Start
@@ -67,12 +67,14 @@ The path is resolved to an absolute path unless you use `:memory:`.
67
67
 
68
68
  - `MEMDB_PATH`: Override the database path (`:memory:` for in-memory).
69
69
  - `MEMDB_LOG_LEVEL`: `info`, `warn`, or `error` (default: `info`).
70
+ - `MEMDB_SHUTDOWN_TIMEOUT`: Shutdown timeout in ms (1000-60000, default: `5000`).
70
71
 
71
72
  ### CLI Flags
72
73
 
73
74
  - `--db <path>`: Override the database path.
74
75
  - `--memory`: Use in-memory database (`:memory:`).
75
76
  - `--log-level <level>`: `info`, `warn`, or `error`.
77
+ - `--shutdown-timeout <ms>`: Shutdown timeout in ms (1000-60000).
76
78
 
77
79
  Precedence: CLI flags > environment variables > defaults.
78
80
 
@@ -128,6 +130,7 @@ Full-text search with filters.
128
130
  | :------------- | :------- | :------- | :------ | :-------------------------------- |
129
131
  | `query` | string | Yes | - | Search query (1-1000 chars) |
130
132
  | `limit` | number | No | `10` | Maximum number of results (1-100) |
133
+ | `offset` | number | No | `0` | Pagination offset (0-1000) |
131
134
  | `tags` | string[] | No | - | Filter by tags (max 50) |
132
135
  | `minRelevance` | number | No | - | Minimum relevance score (0-1) |
133
136
 
@@ -169,21 +172,37 @@ Create a relationship between two memories.
169
172
 
170
173
  Get memories related to a given memory.
171
174
 
172
- | Parameter | Type | Required | Default | Description |
173
- | :------------- | :----- | :------- | :------ | :---------------------------- |
174
- | `hash` | string | Yes | - | Hash of the memory (32 chars) |
175
- | `relationType` | string | No | - | Filter by relationship type |
176
- | `depth` | number | No | `1` | Traversal depth (1-3) |
175
+ | Parameter | Type | Required | Default | Description |
176
+ | :------------- | :----- | :------- | :--------- | :----------------------------- |
177
+ | `hash` | string | Yes | - | Hash of the memory (32 chars) |
178
+ | `relationType` | string | No | - | Filter by relationship type |
179
+ | `depth` | number | No | `1` | Traversal depth (1-3) |
180
+ | `direction` | string | No | `outgoing` | `outgoing`, `incoming`, `both` |
177
181
 
178
182
  **Returns:** Array of related memories (`Memory` + `relation_type`, `depth`).
179
183
 
180
184
  ### `memory_stats`
181
185
 
182
- Get database statistics.
186
+ Get database statistics and memory type breakdown.
183
187
 
184
188
  _No parameters required._
185
189
 
186
- **Returns:** `{ memoryCount, relationshipCount }`.
190
+ **Returns:** `{ memoryCount, relationshipCount, tagCount, memoryTypes, oldestMemory, newestMemory }`.
191
+
192
+ ### `update_memory`
193
+
194
+ Update memory metadata (content cannot be changed).
195
+
196
+ | Parameter | Type | Required | Default | Description |
197
+ | :----------- | :------- | :------- | :------ | :------------------------------------------ |
198
+ | `hash` | string | Yes | - | MD5 hash (32 chars) |
199
+ | `importance` | number | No | - | New importance score (0-10) |
200
+ | `memoryType` | string | No | - | New memory type (1-50 chars) |
201
+ | `tags` | string[] | No | - | Replace all tags (max 100, each 1-50 chars) |
202
+ | `addTags` | string[] | No | - | Tags to add (max 100, each 1-50 chars) |
203
+ | `removeTags` | string[] | No | - | Tags to remove (max 100, each 1-50 chars) |
204
+
205
+ **Returns:** `{ updated: true, hash }`.
187
206
 
188
207
  ### Memory Fields
189
208
 
@@ -249,26 +268,29 @@ Add to your `claude_desktop_config.json`:
249
268
 
250
269
  ## Limits & Constraints
251
270
 
252
- | Constraint | Value | Description |
253
- | :---------------------------- | :------------ | :------------------------------------------------------- |
254
- | **Max content length** | 100,000 chars | Maximum characters in memory content |
255
- | **Max query length** | 1,000 chars | Maximum characters in search query |
256
- | **Max search results** | 100 | Maximum results returned from `search_memories` |
257
- | **Default search limit** | 10 | Default `limit` for `search_memories` |
258
- | **Max tags per memory** | 100 | Maximum number of tags when storing a memory |
259
- | **Max tag length** | 50 chars | Maximum characters per tag |
260
- | **Max tags in search filter** | 50 | Maximum tags when filtering search results |
261
- | **Max related memories** | 1,000 | Maximum results from `get_related` queries |
262
- | **Max traversal depth** | 3 | Maximum depth for relationship traversal |
263
- | **Importance range** | 0-10 | Allowed range for `importance` |
264
- | **Min relevance range** | 0-1 | Allowed range for `minRelevance` |
265
- | **Hash length** | 32 chars | MD5 hash length |
266
- | **Search mode** | Phrase | Search uses phrase matching (FTS5 operators are escaped) |
271
+ | Constraint | Value | Description |
272
+ | :---------------------------- | :------------ | :-------------------------------------------------------- |
273
+ | **Max content length** | 100,000 chars | Maximum characters in memory content |
274
+ | **Max query length** | 1,000 chars | Maximum characters in search query |
275
+ | **Max search results** | 100 | Maximum results returned from `search_memories` |
276
+ | **Default search limit** | 10 | Default `limit` for `search_memories` |
277
+ | **Max search offset** | 1,000 | Maximum `offset` for `search_memories` |
278
+ | **Max tags per memory** | 100 | Maximum number of tags when storing a memory |
279
+ | **Max tag length** | 50 chars | Maximum characters per tag |
280
+ | **Max tags in search filter** | 50 | Maximum tags when filtering search results |
281
+ | **Max related memories** | 1,000 | Maximum results from `get_related` queries |
282
+ | **Max traversal depth** | 3 | Maximum depth for relationship traversal |
283
+ | **Importance range** | 0-10 | Allowed range for `importance` |
284
+ | **Min relevance range** | 0-1 | Allowed range for `minRelevance` |
285
+ | **Hash length** | 32 chars | MD5 hash length |
286
+ | **Search mode** | Tokenized OR | Each term is quoted and OR'ed; FTS5 operators are escaped |
267
287
 
268
288
  ### Notes
269
289
 
270
290
  - **Content deduplication**: Memories are deduplicated using MD5 hashes.
271
291
  - **Search errors**: If FTS5 is unavailable, `search_memories` returns an error indicating the index is missing. Invalid query syntax returns an error with details.
292
+ - **Tag behavior**: Tags are de-duplicated per memory; exceeding tag limits throws an error.
293
+ - **Bidirectional depth**: `get_related` with `direction: "both"` caps traversal depth at 2.
272
294
  - **Local storage**: All data is stored locally in `.memdb/memory.db` unless `:memory:` is used.
273
295
 
274
296
  ## Development
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0E3C,eAAO,MAAM,EAAE,cAAqD,CAAC;AAKrE,eAAO,MAAM,OAAO,QAAO,IAG1B,CAAC"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0E3C,eAAO,MAAM,EAAE,cAAqD,CAAC;AAUrE,eAAO,MAAM,OAAO,QAAO,IAG1B,CAAC"}
@@ -1,4 +1,4 @@
1
- import fs from 'node:fs';
1
+ import { mkdir } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { DatabaseSync } from 'node:sqlite';
4
4
  import { config } from '../utils/config.js';
@@ -67,9 +67,10 @@ const FTS_SYNC_SQL = `
67
67
  WHERE id NOT IN (SELECT rowid FROM memories_fts);
68
68
  `;
69
69
  if (config.dbPath !== ':memory:') {
70
- fs.mkdirSync(path.dirname(config.dbPath), { recursive: true });
70
+ await mkdir(path.dirname(config.dbPath), { recursive: true });
71
71
  }
72
72
  export const db = new DatabaseSync(config.dbPath, { timeout: 5000 });
73
+ db.enableDefensive?.(true);
73
74
  db.exec(SCHEMA_SQL);
74
75
  db.exec(FTS_SYNC_SQL);
75
76
  export const closeDb = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DlB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;CAIpB,CAAC;AAEF,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;IACjC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAErE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACpB,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAEtB,MAAM,CAAC,MAAM,OAAO,GAAG,GAAS,EAAE;IAChC,IAAI,CAAC,EAAE,CAAC,MAAM;QAAE,OAAO;IACvB,EAAE,CAAC,KAAK,EAAE,CAAC;AACb,CAAC,CAAC"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DlB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;CAIpB,CAAC;AAEF,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;IACjC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAEnE,EAGD,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC;AAE1B,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACpB,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAEtB,MAAM,CAAC,MAAM,OAAO,GAAG,GAAS,EAAE;IAChC,IAAI,CAAC,EAAE,CAAC,MAAM;QAAE,OAAO;IACvB,EAAE,CAAC,KAAK,EAAE,CAAC;AACb,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { StatementSync } from 'node:sqlite';
2
+ import type { DbRow } from './row-mappers.js';
3
+ export type SqlParam = string | number | bigint | null | Uint8Array;
4
+ export declare const executeAll: (stmt: StatementSync, ...params: SqlParam[]) => DbRow[];
5
+ export declare const executeGet: (stmt: StatementSync, ...params: SqlParam[]) => DbRow | undefined;
6
+ export declare const executeRun: (stmt: StatementSync, ...params: SqlParam[]) => {
7
+ changes: number | bigint;
8
+ };
9
+ export declare const withImmediateTransaction: <T>(operation: () => T) => T;
10
+ //# sourceMappingURL=db-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-helpers.d.ts","sourceRoot":"","sources":["../../src/core/db-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,UAAU,CAAC;AAEpE,eAAO,MAAM,UAAU,GACrB,MAAM,aAAa,EACnB,GAAG,QAAQ,QAAQ,EAAE,KACpB,KAAK,EAAoC,CAAC;AAE7C,eAAO,MAAM,UAAU,GACrB,MAAM,aAAa,EACnB,GAAG,QAAQ,QAAQ,EAAE,KACpB,KAAK,GAAG,SAAqD,CAAC;AAEjE,eAAO,MAAM,UAAU,GACrB,MAAM,aAAa,EACnB,GAAG,QAAQ,QAAQ,EAAE,KACpB;IAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CAG1B,CAAC;AAEJ,eAAO,MAAM,wBAAwB,GAAI,CAAC,EAAE,WAAW,MAAM,CAAC,KAAG,CAUhE,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { db } from './database.js';
2
+ export const executeAll = (stmt, ...params) => stmt.all(...params);
3
+ export const executeGet = (stmt, ...params) => stmt.get(...params);
4
+ export const executeRun = (stmt, ...params) => stmt.run(...params);
5
+ export const withImmediateTransaction = (operation) => {
6
+ db.exec('BEGIN IMMEDIATE');
7
+ try {
8
+ const result = operation();
9
+ db.exec('COMMIT');
10
+ return result;
11
+ }
12
+ catch (err) {
13
+ db.exec('ROLLBACK');
14
+ throw err;
15
+ }
16
+ };
17
+ //# sourceMappingURL=db-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-helpers.js","sourceRoot":"","sources":["../../src/core/db-helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAKnC,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAmB,EACnB,GAAG,MAAkB,EACZ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAY,CAAC;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAmB,EACnB,GAAG,MAAkB,EACF,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAsB,CAAC;AAEjE,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAmB,EACnB,GAAG,MAAkB,EACS,EAAE,CAChC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAEjB,CAAC;AAEJ,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAI,SAAkB,EAAK,EAAE;IACnE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpB,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const findMemoryIdByHash: (hash: string) => number | undefined;
2
+ export declare const insertTags: (memoryId: number, tags: readonly string[]) => void;
3
+ //# sourceMappingURL=memory-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-helpers.d.ts","sourceRoot":"","sources":["../../src/core/memory-helpers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,SAO1D,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,EAAE,MAAM,SAAS,MAAM,EAAE,KAAG,IAQtE,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { db } from './database.js';
2
+ import { executeGet, executeRun } from './db-helpers.js';
3
+ import { toSafeInteger } from './row-mappers.js';
4
+ export const findMemoryIdByHash = (hash) => {
5
+ const row = executeGet(db.prepare('SELECT id FROM memories WHERE hash = ?'), hash);
6
+ if (!row)
7
+ return undefined;
8
+ return toSafeInteger(row.id, 'id');
9
+ };
10
+ export const insertTags = (memoryId, tags) => {
11
+ if (tags.length === 0)
12
+ return;
13
+ const placeholders = tags.map(() => '(?, ?)').join(', ');
14
+ const params = tags.flatMap((tag) => [memoryId, tag]);
15
+ const stmt = db.prepare(`INSERT OR IGNORE INTO tags (memory_id, tag) VALUES ${placeholders}`);
16
+ executeRun(stmt, ...params);
17
+ };
18
+ //# sourceMappingURL=memory-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-helpers.js","sourceRoot":"","sources":["../../src/core/memory-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAsB,EAAE;IACrE,MAAM,GAAG,GAAG,UAAU,CACpB,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,EACpD,IAAI,CACL,CAAC;IACF,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,IAAuB,EAAQ,EAAE;IAC5E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,MAAM,GAAe,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB,sDAAsD,YAAY,EAAE,CACrE,CAAC;IACF,UAAU,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC"}
@@ -1,10 +1,11 @@
1
- import type { Memory, MemoryInsertResult, MemoryStats, RelatedMemory, SearchResult, StatementResult } from '../types/index.js';
1
+ import type { Memory, MemoryInsertResult, RelatedMemory, SearchResult, StatementResult } from '../types/index.js';
2
2
  export declare const createMemory: (content: string, tags?: readonly string[], importance?: number, memoryType?: string) => MemoryInsertResult;
3
- export declare const searchMemories: (query: string, limit?: number, tags?: readonly string[], minRelevance?: number) => SearchResult[];
3
+ export declare const searchMemories: (query: string, limit?: number, tags?: readonly string[], minRelevance?: number, offset?: number) => SearchResult[];
4
4
  export declare const getMemory: (hash: string) => Memory | undefined;
5
5
  export declare const deleteMemory: (hash: string) => StatementResult;
6
6
  export declare const linkMemories: (fromHash: string, toHash: string, relationType: string) => StatementResult;
7
- export type RelationDirection = 'outgoing' | 'incoming' | 'both';
7
+ type RelationDirection = 'outgoing' | 'incoming' | 'both';
8
8
  export declare const getRelated: (hash: string, relationType?: string, depth?: number, direction?: RelationDirection) => RelatedMemory[];
9
- export declare const getStats: () => MemoryStats;
9
+ export { getStats } from './memory-stats.js';
10
+ export { updateMemory } from './memory-updates.js';
10
11
  //# sourceMappingURL=memory-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-service.d.ts","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAuJ3B,eAAO,MAAM,YAAY,GACvB,SAAS,MAAM,EACf,OAAM,SAAS,MAAM,EAAO,EAC5B,mBAAc,EACd,mBAAsB,KACrB,kBAeC,CAAC;AAEL,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,cAAU,EACV,OAAM,SAAS,MAAM,EAAO,EAC5B,eAAe,MAAM,KACpB,YAAY,EASd,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,SAMjD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,eAM3C,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,cAAc,MAAM,KACnB,eAcF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAKjE,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,eAAe,MAAM,EACrB,cAAS,EACT,YAAW,iBAA8B,KACxC,aAAa,EASf,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,WAiB3B,CAAC"}
1
+ {"version":3,"file":"memory-service.d.ts","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,eAAe,EAChB,MAAM,mBAAmB,CAAC;AA2B3B,eAAO,MAAM,YAAY,GACvB,SAAS,MAAM,EACf,OAAM,SAAS,MAAM,EAAO,EAC5B,mBAAc,EACd,mBAAsB,KACrB,kBAeC,CAAC;AAEL,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,cAAU,EACV,OAAM,SAAS,MAAM,EAAO,EAC5B,eAAe,MAAM,EACrB,SAAS,MAAM,KACd,YAAY,EAUd,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,SAMjD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,eAM3C,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,cAAc,MAAM,KACnB,eAcF,CAAC;AAEF,KAAK,iBAAiB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAY1D,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,eAAe,MAAM,EACrB,cAAS,EACT,YAAW,iBAA8B,KACxC,aAAa,EASf,CAAC;AAEF,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,100 +1,12 @@
1
1
  import crypto from 'node:crypto';
2
2
  import { db } from './database.js';
3
+ import { executeGet, executeRun, withImmediateTransaction, } from './db-helpers.js';
4
+ import { findMemoryIdByHash, insertTags } from './memory-helpers.js';
3
5
  import { deduplicateByHash, queryBothDirect, queryIncomingDirect, queryIncomingRecursive, queryOutgoingDirect, queryOutgoingRecursive, } from './relation-queries.js';
4
6
  import { mapRowToMemory, mapRowToSearchResult, toSafeInteger, } from './row-mappers.js';
5
- import { toSearchError } from './search-errors.js';
6
- const executeAll = (stmt, ...params) => stmt.all(...params);
7
- const executeGet = (stmt, ...params) => stmt.get(...params);
8
- const executeRun = (stmt, ...params) => stmt.run(...params);
9
- const buildSearchQuery = (query, limit, tags, minRelevance) => {
10
- const sanitizedQuery = `"${query.replace(/"/g, '""')}"`;
11
- const relevanceExpr = '1.0 / (1.0 + abs(bm25(memories_fts)))';
12
- const whereParts = ['memories_fts MATCH ?'];
13
- const params = [sanitizedQuery];
14
- if (tags.length > 0) {
15
- whereParts.push(`m.id IN (SELECT memory_id FROM tags WHERE tag IN (${tags
16
- .map(() => '?')
17
- .join(', ')}))`);
18
- params.push(...tags);
19
- }
20
- let sql = `
21
- WITH ranked AS (
22
- SELECT m.*, ${relevanceExpr} as relevance
23
- FROM memories m
24
- JOIN memories_fts fts ON m.id = fts.rowid
25
- WHERE ${whereParts.join(' AND ')}
26
- )
27
- SELECT * FROM ranked
28
- `;
29
- if (minRelevance !== undefined) {
30
- sql += ' WHERE relevance >= ?';
31
- params.push(minRelevance);
32
- }
33
- sql += ' ORDER BY relevance DESC LIMIT ?';
34
- params.push(limit);
35
- return { sql, params };
36
- };
37
- const executeSearch = (sql, params) => {
38
- try {
39
- const stmt = db.prepare(sql);
40
- return executeAll(stmt, ...params);
41
- }
42
- catch (err) {
43
- const mappedError = toSearchError(err);
44
- if (mappedError) {
45
- throw mappedError;
46
- }
47
- throw err;
48
- }
49
- };
7
+ import { buildSearchQuery, executeSearch } from './search.js';
8
+ import { normalizeTags } from './tag-helpers.js';
50
9
  const buildHash = (content) => crypto.createHash('md5').update(content).digest('hex');
51
- const assertValidTag = (tag) => {
52
- if (tag.length === 0) {
53
- throw new Error('Tag must be at least 1 character');
54
- }
55
- if (tag.length > 50) {
56
- throw new Error('Tag exceeds 50 characters');
57
- }
58
- };
59
- const normalizeTags = (tags, maxTags) => {
60
- if (tags.length === 0)
61
- return [];
62
- if (tags.length > maxTags) {
63
- throw new Error('Too many tags (max ' + String(maxTags) + ')');
64
- }
65
- const seen = new Set();
66
- for (const tag of tags) {
67
- assertValidTag(tag);
68
- seen.add(tag);
69
- }
70
- return [...seen];
71
- };
72
- const withImmediateTransaction = (operation) => {
73
- db.exec('BEGIN IMMEDIATE');
74
- try {
75
- const result = operation();
76
- db.exec('COMMIT');
77
- return result;
78
- }
79
- catch (err) {
80
- db.exec('ROLLBACK');
81
- throw err;
82
- }
83
- };
84
- const findMemoryIdByHash = (hash) => {
85
- const row = executeGet(db.prepare('SELECT id FROM memories WHERE hash = ?'), hash);
86
- if (!row)
87
- return undefined;
88
- return toSafeInteger(row.id, 'id');
89
- };
90
- const insertTags = (memoryId, tags) => {
91
- if (tags.length === 0)
92
- return;
93
- const insertTag = db.prepare('INSERT OR IGNORE INTO tags (memory_id, tag) VALUES (?, ?)');
94
- for (const tag of tags) {
95
- executeRun(insertTag, memoryId, tag);
96
- }
97
- };
98
10
  export const createMemory = (content, tags = [], importance = 0, memoryType = 'general') => withImmediateTransaction(() => {
99
11
  const hash = buildHash(content);
100
12
  const normalizedTags = normalizeTags(tags, 100);
@@ -108,8 +20,8 @@ export const createMemory = (content, tags = [], importance = 0, memoryType = 'g
108
20
  insertTags(id, normalizedTags);
109
21
  return { id, hash, isNew: toSafeInteger(result.changes, 'changes') === 1 };
110
22
  });
111
- export const searchMemories = (query, limit = 10, tags = [], minRelevance) => {
112
- const { sql, params } = buildSearchQuery(query, limit, normalizeTags(tags, 50), minRelevance);
23
+ export const searchMemories = (query, limit = 10, tags = [], minRelevance, offset) => {
24
+ const { sql, params } = buildSearchQuery(query, limit, normalizeTags(tags, 50), minRelevance, offset);
113
25
  const rows = executeSearch(sql, params);
114
26
  return rows.map((row) => mapRowToSearchResult(row));
115
27
  };
@@ -132,28 +44,24 @@ export const linkMemories = (fromHash, toHash, relationType) => {
132
44
  const result = executeRun(insert, fromId, toId, relationType);
133
45
  return { changes: toSafeInteger(result.changes, 'changes') };
134
46
  };
135
- const calcMaxDepth = (depth, direction) => direction === 'both' ? Math.min(depth, 2) : Math.max(1, depth);
47
+ const resolveMaxDepth = (depth, direction) => {
48
+ if (direction === 'both') {
49
+ return Math.min(depth, 2);
50
+ }
51
+ return Math.max(1, depth);
52
+ };
136
53
  export const getRelated = (hash, relationType, depth = 1, direction = 'outgoing') => {
137
54
  const memoryId = findMemoryIdByHash(hash);
138
55
  if (memoryId === undefined)
139
56
  return [];
140
- const maxDepth = calcMaxDepth(depth, direction);
57
+ const maxDepth = resolveMaxDepth(depth, direction);
141
58
  if (maxDepth === 1) {
142
59
  return getRelatedDirect(memoryId, relationType, direction);
143
60
  }
144
61
  return getRelatedRecursive(memoryId, relationType, maxDepth, direction);
145
62
  };
146
- export const getStats = () => {
147
- const memoryRow = executeGet(db.prepare('SELECT COUNT(*) as count FROM memories'));
148
- const relationshipRow = executeGet(db.prepare('SELECT COUNT(*) as count FROM relationships'));
149
- if (!memoryRow || !relationshipRow) {
150
- throw new Error('Failed to load database stats');
151
- }
152
- return {
153
- memoryCount: toSafeInteger(memoryRow.count, 'memoryCount'),
154
- relationshipCount: toSafeInteger(relationshipRow.count, 'relationshipCount'),
155
- };
156
- };
63
+ export { getStats } from './memory-stats.js';
64
+ export { updateMemory } from './memory-updates.js';
157
65
  const getRelatedDirect = (memoryId, relationType, direction = 'outgoing') => {
158
66
  if (direction === 'outgoing')
159
67
  return queryOutgoingDirect(memoryId, relationType);
@@ -168,7 +76,6 @@ const getRelatedRecursive = (memoryId, relationType, maxDepth, direction = 'outg
168
76
  if (direction === 'incoming') {
169
77
  return queryIncomingRecursive(memoryId, relationType, maxDepth);
170
78
  }
171
- // direction === 'both'
172
79
  const outgoing = queryOutgoingRecursive(memoryId, relationType, maxDepth);
173
80
  const incoming = queryIncomingRecursive(memoryId, relationType, maxDepth);
174
81
  return deduplicateByHash([...outgoing, ...incoming]);
@@ -1 +1 @@
1
- {"version":3,"file":"memory-service.js","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-service.js","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { MemoryStats } from '../types/index.js';
2
+ export declare const getStats: () => MemoryStats;
3
+ //# sourceMappingURL=memory-stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-stats.d.ts","sourceRoot":"","sources":["../../src/core/memory-stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA0CrD,eAAO,MAAM,QAAQ,QAAO,WAwB3B,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { db } from './database.js';
2
+ import { executeAll, executeGet } from './db-helpers.js';
3
+ import { toSafeInteger } from './row-mappers.js';
4
+ const buildMemoryTypes = (typeRows) => {
5
+ const memoryTypes = {};
6
+ for (const row of typeRows) {
7
+ const rawType = row.memory_type;
8
+ const typeKey = typeof rawType === 'string' ? rawType : 'unknown';
9
+ memoryTypes[typeKey] = toSafeInteger(row.count, 'typeCount');
10
+ }
11
+ return memoryTypes;
12
+ };
13
+ const toDateString = (value) => {
14
+ if (value == null)
15
+ return null;
16
+ if (typeof value === 'string')
17
+ return value;
18
+ if (typeof value === 'number')
19
+ return String(value);
20
+ return null;
21
+ };
22
+ const queryCounts = () => {
23
+ const memoryRow = executeGet(db.prepare('SELECT COUNT(*) as count FROM memories'));
24
+ const relationshipRow = executeGet(db.prepare('SELECT COUNT(*) as count FROM relationships'));
25
+ const tagRow = executeGet(db.prepare('SELECT COUNT(DISTINCT tag) as count FROM tags'));
26
+ if (!memoryRow || !relationshipRow || !tagRow) {
27
+ throw new Error('Failed to load database stats');
28
+ }
29
+ return { memoryRow, relationshipRow, tagRow };
30
+ };
31
+ export const getStats = () => {
32
+ const { memoryRow, relationshipRow, tagRow } = queryCounts();
33
+ const typeRows = executeAll(db.prepare('SELECT memory_type, COUNT(*) as count FROM memories GROUP BY memory_type'));
34
+ const dateRow = executeGet(db.prepare('SELECT MIN(created_at) as oldest, MAX(created_at) as newest FROM memories'));
35
+ return {
36
+ memoryCount: toSafeInteger(memoryRow.count, 'memoryCount'),
37
+ relationshipCount: toSafeInteger(relationshipRow.count, 'relationshipCount'),
38
+ tagCount: toSafeInteger(tagRow.count, 'tagCount'),
39
+ memoryTypes: buildMemoryTypes(typeRows),
40
+ oldestMemory: toDateString(dateRow?.oldest),
41
+ newestMemory: toDateString(dateRow?.newest),
42
+ };
43
+ };
44
+ //# sourceMappingURL=memory-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-stats.js","sourceRoot":"","sources":["../../src/core/memory-stats.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAc,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,gBAAgB,GAAG,CAAC,QAAiB,EAA0B,EAAE;IACrE,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC;QAChC,MAAM,OAAO,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAClE,WAAW,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAc,EAAiB,EAAE;IACrD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,GAIlB,EAAE;IACF,MAAM,SAAS,GAAG,UAAU,CAC1B,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CACrD,CAAC;IACF,MAAM,eAAe,GAAG,UAAU,CAChC,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAC1D,CAAC;IACF,MAAM,MAAM,GAAG,UAAU,CACvB,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC,CAC5D,CAAC;IACF,IAAI,CAAC,SAAS,IAAI,CAAC,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAgB,EAAE;IACxC,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;IAC7D,MAAM,QAAQ,GAAG,UAAU,CACzB,EAAE,CAAC,OAAO,CACR,0EAA0E,CAC3E,CACF,CAAC;IACF,MAAM,OAAO,GAAG,UAAU,CACxB,EAAE,CAAC,OAAO,CACR,2EAA2E,CAC5E,CACF,CAAC;IAEF,OAAO;QACL,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC;QAC1D,iBAAiB,EAAE,aAAa,CAC9B,eAAe,CAAC,KAAK,EACrB,mBAAmB,CACpB;QACD,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC;QACjD,WAAW,EAAE,gBAAgB,CAAC,QAAQ,CAAC;QACvC,YAAY,EAAE,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC;QAC3C,YAAY,EAAE,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC;KAC5C,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { MemoryUpdateResult } from '../types/index.js';
2
+ interface UpdateMemoryOptions {
3
+ importance?: number | undefined;
4
+ memoryType?: string | undefined;
5
+ tags?: readonly string[] | undefined;
6
+ addTags?: readonly string[] | undefined;
7
+ removeTags?: readonly string[] | undefined;
8
+ }
9
+ export declare const updateMemory: (hash: string, options: UpdateMemoryOptions) => MemoryUpdateResult;
10
+ export {};
11
+ //# sourceMappingURL=memory-updates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-updates.d.ts","sourceRoot":"","sources":["../../src/core/memory-updates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AA4B5D,UAAU,mBAAmB;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACrC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC5C;AAyGD,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,SAAS,mBAAmB,KAC3B,kBASF,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { db } from './database.js';
2
+ import { executeAll, executeRun, withImmediateTransaction, } from './db-helpers.js';
3
+ import { findMemoryIdByHash, insertTags } from './memory-helpers.js';
4
+ import { normalizeTags } from './tag-helpers.js';
5
+ const MAX_TAGS = 100;
6
+ const loadTagsForMemory = (memoryId) => {
7
+ const rows = executeAll(db.prepare('SELECT tag FROM tags WHERE memory_id = ?'), memoryId);
8
+ const tags = new Set();
9
+ for (const row of rows) {
10
+ if (typeof row.tag !== 'string') {
11
+ throw new Error('Invalid tag');
12
+ }
13
+ tags.add(row.tag);
14
+ }
15
+ return tags;
16
+ };
17
+ const updateMetadataFields = (memoryId, options) => {
18
+ if (options.importance === undefined && options.memoryType === undefined) {
19
+ return;
20
+ }
21
+ const updates = [];
22
+ const params = [];
23
+ if (options.importance !== undefined) {
24
+ updates.push('importance = ?');
25
+ params.push(options.importance);
26
+ }
27
+ if (options.memoryType !== undefined) {
28
+ updates.push('memory_type = ?');
29
+ params.push(options.memoryType);
30
+ }
31
+ params.push(memoryId);
32
+ executeRun(db.prepare(`UPDATE memories SET ${updates.join(', ')} WHERE id = ?`), ...params);
33
+ };
34
+ const replaceTags = (memoryId, tags) => {
35
+ executeRun(db.prepare('DELETE FROM tags WHERE memory_id = ?'), memoryId);
36
+ insertTags(memoryId, normalizeTags(tags, MAX_TAGS));
37
+ };
38
+ const filterTagsToInsert = (tags, removeTags) => {
39
+ if (removeTags.length === 0)
40
+ return [...tags];
41
+ const removeSet = new Set(removeTags);
42
+ return tags.filter((tag) => !removeSet.has(tag));
43
+ };
44
+ const removeTagsFromSet = (tags, tagSet) => {
45
+ for (const tag of tags) {
46
+ tagSet.delete(tag);
47
+ }
48
+ };
49
+ const enforceTagLimit = (existingTags, tagsToInsert, maxTags) => {
50
+ let projectedCount = existingTags.size;
51
+ for (const tag of tagsToInsert) {
52
+ if (existingTags.has(tag))
53
+ continue;
54
+ projectedCount += 1;
55
+ if (projectedCount > maxTags) {
56
+ throw new Error('Too many tags (max ' + String(maxTags) + ')');
57
+ }
58
+ existingTags.add(tag);
59
+ }
60
+ };
61
+ const addTagsToMemory = (memoryId, tags, removeTags = []) => {
62
+ if (tags.length === 0)
63
+ return;
64
+ const normalizedTags = normalizeTags(tags, MAX_TAGS);
65
+ const tagsToInsert = filterTagsToInsert(normalizedTags, removeTags);
66
+ if (tagsToInsert.length === 0)
67
+ return;
68
+ const existingTags = loadTagsForMemory(memoryId);
69
+ removeTagsFromSet(removeTags, existingTags);
70
+ enforceTagLimit(existingTags, tagsToInsert, MAX_TAGS);
71
+ insertTags(memoryId, tagsToInsert);
72
+ };
73
+ const removeTagsFromMemory = (memoryId, tags) => {
74
+ if (tags.length === 0)
75
+ return;
76
+ const placeholders = tags.map(() => '?').join(', ');
77
+ const stmt = db.prepare(`DELETE FROM tags WHERE memory_id = ? AND tag IN (${placeholders})`);
78
+ executeRun(stmt, memoryId, ...tags);
79
+ };
80
+ const updateTags = (memoryId, options) => {
81
+ if (options.tags !== undefined) {
82
+ replaceTags(memoryId, options.tags);
83
+ return;
84
+ }
85
+ if (options.addTags !== undefined) {
86
+ addTagsToMemory(memoryId, options.addTags, options.removeTags ?? []);
87
+ }
88
+ if (options.removeTags !== undefined) {
89
+ removeTagsFromMemory(memoryId, options.removeTags);
90
+ }
91
+ };
92
+ export const updateMemory = (hash, options) => {
93
+ const memoryId = findMemoryIdByHash(hash);
94
+ if (memoryId === undefined)
95
+ throw new Error('Memory not found');
96
+ return withImmediateTransaction(() => {
97
+ updateMetadataFields(memoryId, options);
98
+ updateTags(memoryId, options);
99
+ return { updated: true, hash };
100
+ });
101
+ };
102
+ //# sourceMappingURL=memory-updates.js.map