@j0hanz/memdb 1.0.1 β 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -66
- package/dist/core/database.d.ts +2 -7
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +72 -81
- package/dist/core/database.js.map +1 -1
- package/dist/core/db-worker-client.d.ts +8 -0
- package/dist/core/db-worker-client.d.ts.map +1 -0
- package/dist/core/db-worker-client.js +67 -0
- package/dist/core/db-worker-client.js.map +1 -0
- package/dist/core/db-worker-protocol.d.ts +77 -0
- package/dist/core/db-worker-protocol.d.ts.map +1 -0
- package/dist/core/db-worker-protocol.js +2 -0
- package/dist/core/db-worker-protocol.js.map +1 -0
- package/dist/core/db-worker.d.ts +2 -0
- package/dist/core/db-worker.d.ts.map +1 -0
- package/dist/core/db-worker.js +73 -0
- package/dist/core/db-worker.js.map +1 -0
- package/dist/core/memory-mappers.d.ts +11 -0
- package/dist/core/memory-mappers.d.ts.map +1 -0
- package/dist/core/memory-mappers.js +52 -0
- package/dist/core/memory-mappers.js.map +1 -0
- package/dist/core/memory-search.d.ts +9 -0
- package/dist/core/memory-search.d.ts.map +1 -0
- package/dist/core/memory-search.js +46 -0
- package/dist/core/memory-search.js.map +1 -0
- package/dist/core/memory-service-core.d.ts +9 -0
- package/dist/core/memory-service-core.d.ts.map +1 -0
- package/dist/core/memory-service-core.js +229 -0
- package/dist/core/memory-service-core.js.map +1 -0
- package/dist/core/memory-service.d.ts +8 -30
- package/dist/core/memory-service.d.ts.map +1 -1
- package/dist/core/memory-service.js +184 -169
- package/dist/core/memory-service.js.map +1 -1
- package/dist/core/memory-types.d.ts +18 -0
- package/dist/core/memory-types.d.ts.map +1 -0
- package/dist/core/memory-types.js +2 -0
- package/dist/core/memory-types.js.map +1 -0
- package/dist/core/row-mappers.d.ts +7 -0
- package/dist/core/row-mappers.d.ts.map +1 -0
- package/dist/core/row-mappers.js +52 -0
- package/dist/core/row-mappers.js.map +1 -0
- package/dist/core/search-errors.d.ts +2 -0
- package/dist/core/search-errors.d.ts.map +1 -0
- package/dist/core/search-errors.js +21 -0
- package/dist/core/search-errors.js.map +1 -0
- package/dist/index.js +86 -18
- package/dist/index.js.map +1 -1
- package/dist/lib/errors.d.ts +3 -2
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/schemas/inputs.d.ts.map +1 -1
- package/dist/schemas/inputs.js +5 -5
- package/dist/schemas/inputs.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +130 -14
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +25 -17
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/config.d.ts +4 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +48 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/logger.d.ts +6 -2
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +25 -10
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/protocol.d.ts +2 -0
- package/dist/utils/protocol.d.ts.map +1 -0
- package/dist/utils/protocol.js +7 -0
- package/dist/utils/protocol.js.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# memdb
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A SQLite-backed MCP memory server (on-disk by default, in-memory optional).
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@j0hanz/memdb)
|
|
6
6
|
|
|
@@ -10,17 +10,17 @@ A memory-based MCP server using SQLite in-memory database.
|
|
|
10
10
|
|
|
11
11
|
[](https://cursor.com/install-mcp?name=memdb&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovbWVtZGJAbGF0ZXN0Il19)
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Features
|
|
14
14
|
|
|
15
|
-
| Feature
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
15
|
+
| Feature | Description |
|
|
16
|
+
| :---------------- | :---------------------------------------------------------------- |
|
|
17
|
+
| Memory Storage | Store text memories with tags, importance, and type |
|
|
18
|
+
| Full-Text Search | FTS5-backed phrase search with relevance ranking |
|
|
19
|
+
| Graph Connections | Link memories and traverse relationships |
|
|
20
|
+
| Stats | Memory and relationship counts |
|
|
21
|
+
| Local Privacy | All data stored locally in SQLite (`.memdb/memory.db` by default) |
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Quick Start
|
|
24
24
|
|
|
25
25
|
### VS Code / Cursor
|
|
26
26
|
|
|
@@ -35,7 +35,7 @@ Add this to your `mcpServers` configuration:
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Installation
|
|
39
39
|
|
|
40
40
|
### NPX (Recommended)
|
|
41
41
|
|
|
@@ -58,91 +58,147 @@ npm install
|
|
|
58
58
|
npm run build
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
##
|
|
61
|
+
## Configuration
|
|
62
62
|
|
|
63
|
-
The server uses a local SQLite database
|
|
63
|
+
The server uses a local SQLite database at `<cwd>/.memdb/memory.db` by default.
|
|
64
|
+
The path is resolved to an absolute path unless you use `:memory:`.
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
### Environment Variables
|
|
67
|
+
|
|
68
|
+
- `MEMDB_PATH`: Override the database path (`:memory:` for in-memory).
|
|
69
|
+
- `MEMDB_LOG_LEVEL`: `info`, `warn`, or `error` (default: `info`).
|
|
70
|
+
|
|
71
|
+
### CLI Flags
|
|
72
|
+
|
|
73
|
+
- `--db <path>`: Override the database path.
|
|
74
|
+
- `--memory`: Use in-memory database (`:memory:`).
|
|
75
|
+
- `--log-level <level>`: `info`, `warn`, or `error`.
|
|
76
|
+
|
|
77
|
+
Precedence: CLI flags > environment variables > defaults.
|
|
78
|
+
|
|
79
|
+
## Tool Response Format
|
|
80
|
+
|
|
81
|
+
All tools return structured JSON in both `content` and `structuredContent`.
|
|
82
|
+
|
|
83
|
+
Success:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"ok": true,
|
|
88
|
+
"result": { "...": "..." }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Error:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"ok": false,
|
|
97
|
+
"error": {
|
|
98
|
+
"code": "E_CODE",
|
|
99
|
+
"message": "Human-readable message"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Tools
|
|
66
105
|
|
|
67
106
|
### `store_memory`
|
|
68
107
|
|
|
69
108
|
Store a new memory with optional tags and metadata.
|
|
70
109
|
|
|
71
|
-
| Parameter | Type | Required | Default
|
|
72
|
-
| :----------- | :------- | :------- |
|
|
73
|
-
| `content` | string |
|
|
74
|
-
| `tags` | string[] |
|
|
75
|
-
| `importance` | number |
|
|
76
|
-
| `memoryType` | string |
|
|
110
|
+
| Parameter | Type | Required | Default | Description |
|
|
111
|
+
| :----------- | :------- | :------- | :-------- | :----------------------------------------- |
|
|
112
|
+
| `content` | string | Yes | - | The content of the memory (1-100000 chars) |
|
|
113
|
+
| `tags` | string[] | No | - | Tags (max 100, each 1-50 chars) |
|
|
114
|
+
| `importance` | number | No | `0` | Importance score (0-10) |
|
|
115
|
+
| `memoryType` | string | No | `general` | Type of memory (1-50 chars) |
|
|
116
|
+
|
|
117
|
+
**Returns:** `{ id, hash, isNew }`
|
|
118
|
+
|
|
119
|
+
Notes:
|
|
77
120
|
|
|
78
|
-
|
|
121
|
+
- Content is deduplicated by MD5 hash. Storing the same content again returns the same hash with `isNew: false`.
|
|
79
122
|
|
|
80
123
|
### `search_memories`
|
|
81
124
|
|
|
82
125
|
Full-text search with filters.
|
|
83
126
|
|
|
84
|
-
| Parameter | Type | Required | Default | Description
|
|
85
|
-
| :------------- | :------- | :------- | :------ |
|
|
86
|
-
| `query` | string |
|
|
87
|
-
| `limit` | number |
|
|
88
|
-
| `tags` | string[] |
|
|
89
|
-
| `minRelevance` | number |
|
|
127
|
+
| Parameter | Type | Required | Default | Description |
|
|
128
|
+
| :------------- | :------- | :------- | :------ | :-------------------------------- |
|
|
129
|
+
| `query` | string | Yes | - | Search query (1-1000 chars) |
|
|
130
|
+
| `limit` | number | No | `10` | Maximum number of results (1-100) |
|
|
131
|
+
| `tags` | string[] | No | - | Filter by tags (max 50) |
|
|
132
|
+
| `minRelevance` | number | No | - | Minimum relevance score (0-1) |
|
|
90
133
|
|
|
91
|
-
**Returns:** Array of
|
|
134
|
+
**Returns:** Array of search results (`Memory` + `relevance`).
|
|
92
135
|
|
|
93
136
|
### `get_memory`
|
|
94
137
|
|
|
95
138
|
Retrieve a specific memory by its hash.
|
|
96
139
|
|
|
97
|
-
| Parameter | Type | Required | Default | Description
|
|
98
|
-
| :-------- | :----- | :------- | :------ |
|
|
99
|
-
| `hash` | string |
|
|
140
|
+
| Parameter | Type | Required | Default | Description |
|
|
141
|
+
| :-------- | :----- | :------- | :------ | :------------------ |
|
|
142
|
+
| `hash` | string | Yes | - | MD5 hash (32 chars) |
|
|
100
143
|
|
|
101
|
-
**Returns:**
|
|
144
|
+
**Returns:** `Memory`.
|
|
102
145
|
|
|
103
146
|
### `delete_memory`
|
|
104
147
|
|
|
105
148
|
Delete a memory by its hash.
|
|
106
149
|
|
|
107
|
-
| Parameter | Type | Required | Default | Description
|
|
108
|
-
| :-------- | :----- | :------- | :------ |
|
|
109
|
-
| `hash` | string |
|
|
150
|
+
| Parameter | Type | Required | Default | Description |
|
|
151
|
+
| :-------- | :----- | :------- | :------ | :------------------ |
|
|
152
|
+
| `hash` | string | Yes | - | MD5 hash (32 chars) |
|
|
110
153
|
|
|
111
|
-
**Returns:**
|
|
154
|
+
**Returns:** `{ deleted: true }`.
|
|
112
155
|
|
|
113
156
|
### `link_memories`
|
|
114
157
|
|
|
115
158
|
Create a relationship between two memories.
|
|
116
159
|
|
|
117
|
-
| Parameter | Type | Required | Default | Description
|
|
118
|
-
| :------------- | :----- | :------- | :------ |
|
|
119
|
-
| `fromHash` | string |
|
|
120
|
-
| `toHash` | string |
|
|
121
|
-
| `relationType` | string |
|
|
160
|
+
| Parameter | Type | Required | Default | Description |
|
|
161
|
+
| :------------- | :----- | :------- | :------ | :----------------------------------- |
|
|
162
|
+
| `fromHash` | string | Yes | - | Hash of the source memory (32 chars) |
|
|
163
|
+
| `toHash` | string | Yes | - | Hash of the target memory (32 chars) |
|
|
164
|
+
| `relationType` | string | Yes | - | Type of relationship (1-50 chars) |
|
|
122
165
|
|
|
123
|
-
**Returns:**
|
|
166
|
+
**Returns:** `{ linked: true }`.
|
|
124
167
|
|
|
125
168
|
### `get_related`
|
|
126
169
|
|
|
127
170
|
Get memories related to a given memory.
|
|
128
171
|
|
|
129
|
-
| Parameter | Type | Required | Default | Description
|
|
130
|
-
| :------------- | :----- | :------- | :------ |
|
|
131
|
-
| `hash` | string |
|
|
132
|
-
| `relationType` | string |
|
|
133
|
-
| `depth` | number |
|
|
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) |
|
|
134
177
|
|
|
135
|
-
**Returns:** Array of related memories.
|
|
178
|
+
**Returns:** Array of related memories (`Memory` + `relation_type`, `depth`).
|
|
136
179
|
|
|
137
180
|
### `memory_stats`
|
|
138
181
|
|
|
139
|
-
Get database statistics
|
|
182
|
+
Get database statistics.
|
|
140
183
|
|
|
141
184
|
_No parameters required._
|
|
142
185
|
|
|
143
|
-
**Returns:**
|
|
186
|
+
**Returns:** `{ memoryCount, relationshipCount }`.
|
|
144
187
|
|
|
145
|
-
|
|
188
|
+
### Memory Fields
|
|
189
|
+
|
|
190
|
+
All memory-shaped responses include:
|
|
191
|
+
|
|
192
|
+
- `id`: integer ID
|
|
193
|
+
- `content`: original content string
|
|
194
|
+
- `summary`: optional summary (currently unset by tools)
|
|
195
|
+
- `importance`: integer 0-10
|
|
196
|
+
- `memory_type`: string
|
|
197
|
+
- `created_at`: timestamp string
|
|
198
|
+
- `accessed_at`: timestamp string
|
|
199
|
+
- `hash`: MD5 hash
|
|
200
|
+
|
|
201
|
+
## Client Configuration
|
|
146
202
|
|
|
147
203
|
<details>
|
|
148
204
|
<summary><b>VS Code</b></summary>
|
|
@@ -191,33 +247,68 @@ Add to your `claude_desktop_config.json`:
|
|
|
191
247
|
|
|
192
248
|
</details>
|
|
193
249
|
|
|
194
|
-
##
|
|
250
|
+
## Limits & Constraints
|
|
251
|
+
|
|
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) |
|
|
267
|
+
|
|
268
|
+
### Notes
|
|
269
|
+
|
|
270
|
+
- **Content deduplication**: Memories are deduplicated using MD5 hashes.
|
|
271
|
+
- **Search errors**: If FTS5 is unavailable, `search_memories` returns an error indicating the index is missing. Invalid query syntax returns an error with details.
|
|
272
|
+
- **Local storage**: All data is stored locally in `.memdb/memory.db` unless `:memory:` is used.
|
|
273
|
+
|
|
274
|
+
## Development
|
|
195
275
|
|
|
196
276
|
### Prerequisites
|
|
197
277
|
|
|
198
|
-
- Node.js >= 22.0.0
|
|
278
|
+
- Node.js >= 22.0.0 (required for `node:sqlite`)
|
|
199
279
|
|
|
200
280
|
### Scripts
|
|
201
281
|
|
|
202
|
-
| Command
|
|
203
|
-
|
|
|
204
|
-
| `npm run
|
|
205
|
-
| `npm run
|
|
206
|
-
| `npm run
|
|
207
|
-
| `npm run
|
|
282
|
+
| Command | Description |
|
|
283
|
+
| :------------------------ | :----------------------------------------- |
|
|
284
|
+
| `npm run clean` | Remove `dist/` |
|
|
285
|
+
| `npm run build` | Compile TypeScript to `dist/` |
|
|
286
|
+
| `npm run dev` | Run in development mode with watch |
|
|
287
|
+
| `npm run start` | Run compiled server (`node dist/index.js`) |
|
|
288
|
+
| `npm run test` | Run tests |
|
|
289
|
+
| `npm run test:coverage` | Run tests with coverage |
|
|
290
|
+
| `npm run lint` | Run ESLint |
|
|
291
|
+
| `npm run format` | Format code with Prettier |
|
|
292
|
+
| `npm run format:check` | Check code formatting |
|
|
293
|
+
| `npm run type-check` | TypeScript type checking |
|
|
294
|
+
| `npm run type-check:test` | Type-check tests only |
|
|
295
|
+
| `npm run maintainability` | Generate maintainability report |
|
|
296
|
+
| `npm run duplication` | Run duplication report (jscpd) |
|
|
297
|
+
| `npm run bench:memory` | Run memory-service benchmark |
|
|
298
|
+
| `npm run inspector` | Run MCP inspector |
|
|
208
299
|
|
|
209
300
|
### Project Structure
|
|
210
301
|
|
|
211
302
|
```text
|
|
212
303
|
src/
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
304
|
+
|-- index.ts # Entry point
|
|
305
|
+
|-- core/ # Database and memory service
|
|
306
|
+
|-- tools/ # Tool implementations
|
|
307
|
+
|-- schemas/ # Zod input/output schemas
|
|
308
|
+
|-- lib/ # Error helpers
|
|
309
|
+
`-- utils/ # Config and logger
|
|
219
310
|
```
|
|
220
311
|
|
|
221
|
-
##
|
|
312
|
+
## Contributing
|
|
222
313
|
|
|
223
314
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/dist/core/database.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
-
export declare
|
|
3
|
-
|
|
4
|
-
constructor();
|
|
5
|
-
private init;
|
|
6
|
-
getDb(): DatabaseSync;
|
|
7
|
-
}
|
|
8
|
-
export declare const dbManager: DatabaseManager;
|
|
2
|
+
export declare const db: DatabaseSync;
|
|
3
|
+
export declare const closeDb: () => void;
|
|
9
4
|
//# sourceMappingURL=database.d.ts.map
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAwE3C,eAAO,MAAM,EAAE,cAAqD,CAAC;AAKrE,eAAO,MAAM,OAAO,QAAO,IAG1B,CAAC"}
|
package/dist/core/database.js
CHANGED
|
@@ -2,86 +2,77 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { DatabaseSync } from 'node:sqlite';
|
|
4
4
|
import { config } from '../utils/config.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
this.db.exec(`
|
|
70
|
-
CREATE TRIGGER memories_au AFTER UPDATE ON memories BEGIN
|
|
71
|
-
DELETE FROM memories_fts WHERE rowid = old.id;
|
|
72
|
-
INSERT INTO memories_fts(rowid, content, summary) VALUES (new.id, new.content, new.summary);
|
|
73
|
-
END;
|
|
74
|
-
`);
|
|
75
|
-
this.db.exec(`
|
|
76
|
-
CREATE TRIGGER memories_ad AFTER DELETE ON memories BEGIN
|
|
77
|
-
DELETE FROM memories_fts WHERE rowid = old.id;
|
|
78
|
-
END;
|
|
79
|
-
`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
getDb() {
|
|
83
|
-
return this.db;
|
|
84
|
-
}
|
|
5
|
+
const SCHEMA_SQL = `
|
|
6
|
+
PRAGMA foreign_keys = ON;
|
|
7
|
+
PRAGMA journal_mode = WAL;
|
|
8
|
+
PRAGMA synchronous = NORMAL;
|
|
9
|
+
|
|
10
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
content TEXT NOT NULL,
|
|
13
|
+
summary TEXT,
|
|
14
|
+
importance INTEGER DEFAULT 0,
|
|
15
|
+
memory_type TEXT DEFAULT 'general',
|
|
16
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
17
|
+
accessed_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
18
|
+
hash TEXT UNIQUE NOT NULL
|
|
19
|
+
) STRICT;
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
22
|
+
memory_id INTEGER NOT NULL,
|
|
23
|
+
tag TEXT NOT NULL,
|
|
24
|
+
PRIMARY KEY (memory_id, tag),
|
|
25
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
|
|
26
|
+
) STRICT;
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_tags_tag_memory_id ON tags(tag, memory_id);
|
|
29
|
+
|
|
30
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
31
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
+
from_memory_id INTEGER NOT NULL,
|
|
33
|
+
to_memory_id INTEGER NOT NULL,
|
|
34
|
+
relation_type TEXT NOT NULL,
|
|
35
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
36
|
+
FOREIGN KEY (from_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
37
|
+
FOREIGN KEY (to_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
38
|
+
UNIQUE(from_memory_id, to_memory_id, relation_type)
|
|
39
|
+
) STRICT;
|
|
40
|
+
|
|
41
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
42
|
+
content,
|
|
43
|
+
summary,
|
|
44
|
+
content_rowid='id'
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
|
|
48
|
+
INSERT INTO memories_fts(rowid, content, summary)
|
|
49
|
+
VALUES (new.id, new.content, new.summary);
|
|
50
|
+
END;
|
|
51
|
+
|
|
52
|
+
CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
|
|
53
|
+
DELETE FROM memories_fts WHERE rowid = old.id;
|
|
54
|
+
INSERT INTO memories_fts(rowid, content, summary)
|
|
55
|
+
VALUES (new.id, new.content, new.summary);
|
|
56
|
+
END;
|
|
57
|
+
|
|
58
|
+
CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
|
|
59
|
+
DELETE FROM memories_fts WHERE rowid = old.id;
|
|
60
|
+
END;
|
|
61
|
+
`;
|
|
62
|
+
const FTS_SYNC_SQL = `
|
|
63
|
+
INSERT INTO memories_fts(rowid, content, summary)
|
|
64
|
+
SELECT id, content, summary FROM memories
|
|
65
|
+
WHERE id NOT IN (SELECT rowid FROM memories_fts);
|
|
66
|
+
`;
|
|
67
|
+
if (config.dbPath !== ':memory:') {
|
|
68
|
+
fs.mkdirSync(path.dirname(config.dbPath), { recursive: true });
|
|
85
69
|
}
|
|
86
|
-
export const
|
|
70
|
+
export const db = new DatabaseSync(config.dbPath, { timeout: 5000 });
|
|
71
|
+
db.exec(SCHEMA_SQL);
|
|
72
|
+
db.exec(FTS_SYNC_SQL);
|
|
73
|
+
export const closeDb = () => {
|
|
74
|
+
if (!db.isOpen)
|
|
75
|
+
return;
|
|
76
|
+
db.close();
|
|
77
|
+
};
|
|
87
78
|
//# sourceMappingURL=database.js.map
|
|
@@ -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,
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDlB,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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DbWorkerCallMap } from './db-worker-protocol.js';
|
|
2
|
+
type PayloadFor<K extends keyof DbWorkerCallMap> = DbWorkerCallMap[K]['payload'];
|
|
3
|
+
type ResultFor<K extends keyof DbWorkerCallMap> = DbWorkerCallMap[K]['result'];
|
|
4
|
+
type ArgsFor<K extends keyof DbWorkerCallMap> = undefined extends PayloadFor<K> ? [payload?: PayloadFor<K>] : [payload: PayloadFor<K>];
|
|
5
|
+
export declare const callDbWorker: <K extends keyof DbWorkerCallMap>(type: K, ...args: ArgsFor<K>) => Promise<ResultFor<K>>;
|
|
6
|
+
export declare const closeDbWorker: () => Promise<void>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=db-worker-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-worker-client.d.ts","sourceRoot":"","sources":["../../src/core/db-worker-client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,yBAAyB,CAAC;AAOjC,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,eAAe,IAC7C,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAChC,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,eAAe,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAC/E,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,eAAe,IAC1C,SAAS,SAAS,UAAU,CAAC,CAAC,CAAC,GAC3B,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,GACzB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAkE/B,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,eAAe,EAC1D,MAAM,CAAC,EACP,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,KAClB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAGtB,CAAC;AAEF,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,IAAI,CAUlD,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { Worker } from 'node:worker_threads';
|
|
3
|
+
let worker;
|
|
4
|
+
let nextId = 1;
|
|
5
|
+
const pending = new Map();
|
|
6
|
+
const rejectAll = (error) => {
|
|
7
|
+
for (const entry of pending.values()) {
|
|
8
|
+
entry.reject(error);
|
|
9
|
+
}
|
|
10
|
+
pending.clear();
|
|
11
|
+
};
|
|
12
|
+
const handleMessage = (message) => {
|
|
13
|
+
const entry = pending.get(message.id);
|
|
14
|
+
if (!entry)
|
|
15
|
+
return;
|
|
16
|
+
pending.delete(message.id);
|
|
17
|
+
if (message.ok) {
|
|
18
|
+
entry.resolve(message.result);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
entry.reject(new Error(message.error.message));
|
|
22
|
+
};
|
|
23
|
+
const createWorker = () => {
|
|
24
|
+
const workerUrl = new URL(import.meta.url.endsWith('.ts') ? './db-worker.ts' : './db-worker.js', import.meta.url);
|
|
25
|
+
const instance = new Worker(workerUrl, { execArgv: process.execArgv });
|
|
26
|
+
instance.on('message', handleMessage);
|
|
27
|
+
instance.on('error', (error) => {
|
|
28
|
+
rejectAll(error);
|
|
29
|
+
});
|
|
30
|
+
instance.on('exit', (code) => {
|
|
31
|
+
if (code !== 0) {
|
|
32
|
+
rejectAll(new Error(`DB worker exited with code ${String(code)}`));
|
|
33
|
+
}
|
|
34
|
+
if (worker === instance) {
|
|
35
|
+
worker = undefined;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return instance;
|
|
39
|
+
};
|
|
40
|
+
const getWorker = () => {
|
|
41
|
+
worker ??= createWorker();
|
|
42
|
+
return worker;
|
|
43
|
+
};
|
|
44
|
+
const sendRequest = (instance, type, payload) => new Promise((resolve, reject) => {
|
|
45
|
+
const id = nextId++;
|
|
46
|
+
pending.set(id, { resolve: resolve, reject });
|
|
47
|
+
const request = (payload === undefined ? { id, type } : { id, type, payload });
|
|
48
|
+
instance.postMessage(request);
|
|
49
|
+
});
|
|
50
|
+
export const callDbWorker = (type, ...args) => {
|
|
51
|
+
const payload = args[0];
|
|
52
|
+
return sendRequest(getWorker(), type, payload);
|
|
53
|
+
};
|
|
54
|
+
export const closeDbWorker = async () => {
|
|
55
|
+
if (!worker)
|
|
56
|
+
return;
|
|
57
|
+
const instance = worker;
|
|
58
|
+
try {
|
|
59
|
+
await sendRequest(instance, 'close');
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
worker = undefined;
|
|
63
|
+
rejectAll(new Error('DB worker closed'));
|
|
64
|
+
await instance.terminate();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=db-worker-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-worker-client.js","sourceRoot":"","sources":["../../src/core/db-worker-client.ts"],"names":[],"mappings":"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"}
|