@whenmoon-afk/memory-mcp 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/database/connection.d.ts +47 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +151 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/database/schema.d.ts +33 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +293 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/extractors/entity-extractor.d.ts +25 -0
- package/dist/extractors/entity-extractor.d.ts.map +1 -0
- package/dist/extractors/entity-extractor.js +195 -0
- package/dist/extractors/entity-extractor.js.map +1 -0
- package/dist/extractors/fact-extractor.d.ts +38 -0
- package/dist/extractors/fact-extractor.d.ts.map +1 -0
- package/dist/extractors/fact-extractor.js +172 -0
- package/dist/extractors/fact-extractor.js.map +1 -0
- package/dist/extractors/summary-generator.d.ts +28 -0
- package/dist/extractors/summary-generator.d.ts.map +1 -0
- package/dist/extractors/summary-generator.js +149 -0
- package/dist/extractors/summary-generator.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -0
- package/dist/scoring/importance.d.ts +39 -0
- package/dist/scoring/importance.d.ts.map +1 -0
- package/dist/scoring/importance.js +150 -0
- package/dist/scoring/importance.js.map +1 -0
- package/dist/scoring/ttl-manager.d.ts +33 -0
- package/dist/scoring/ttl-manager.d.ts.map +1 -0
- package/dist/scoring/ttl-manager.js +99 -0
- package/dist/scoring/ttl-manager.js.map +1 -0
- package/dist/search/semantic-search.d.ts +15 -0
- package/dist/search/semantic-search.d.ts.map +1 -0
- package/dist/search/semantic-search.js +236 -0
- package/dist/search/semantic-search.js.map +1 -0
- package/dist/tools/memory-forget.d.ts +10 -0
- package/dist/tools/memory-forget.d.ts.map +1 -0
- package/dist/tools/memory-forget.js +34 -0
- package/dist/tools/memory-forget.js.map +1 -0
- package/dist/tools/memory-recall.d.ts +12 -0
- package/dist/tools/memory-recall.d.ts.map +1 -0
- package/dist/tools/memory-recall.js +106 -0
- package/dist/tools/memory-recall.js.map +1 -0
- package/dist/tools/memory-store.d.ts +13 -0
- package/dist/tools/memory-store.d.ts.map +1 -0
- package/dist/tools/memory-store.js +279 -0
- package/dist/tools/memory-store.js.map +1 -0
- package/dist/tools/response-formatter.d.ts +71 -0
- package/dist/tools/response-formatter.d.ts.map +1 -0
- package/dist/tools/response-formatter.js +180 -0
- package/dist/tools/response-formatter.js.map +1 -0
- package/dist/types/index.d.ts +244 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +29 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/token-estimator.d.ts +33 -0
- package/dist/utils/token-estimator.d.ts.map +1 -0
- package/dist/utils/token-estimator.js +54 -0
- package/dist/utils/token-estimator.js.map +1 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 WhenMoon-afk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# claude-memory-mcp
|
|
2
|
+
|
|
3
|
+
**Local, Persistent Memory for Any MCP-Compatible AI**
|
|
4
|
+
A lightweight, **zero-cloud**, **token-efficient** Model Context Protocol (MCP) server that gives your AI **durable, searchable, and context-aware memory** - entirely under your control.
|
|
5
|
+
|
|
6
|
+
Built with **TypeScript**, **SQLite + FTS5**, and **no external dependencies**, it runs locally and stores everything in a single, portable `.db` file.
|
|
7
|
+
|
|
8
|
+
Works with **Claude Desktop**, **Cursor**, **Windsurf**, or any MCP client.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why Local Memory?
|
|
13
|
+
|
|
14
|
+
| You Control | Cloud Services |
|
|
15
|
+
|-----------|----------------|
|
|
16
|
+
| Data never leaves your machine | Sent to remote servers |
|
|
17
|
+
| Portable `.db` file | Locked in proprietary storage |
|
|
18
|
+
| Full audit & backup | Opaque retention policies |
|
|
19
|
+
| Zero recurring cost | Subscription required |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
| Feature | Benefit |
|
|
26
|
+
|-------|--------|
|
|
27
|
+
| **Dual-Response Pattern** | Returns *all* matches (compact index) + full *details* within token budget |
|
|
28
|
+
| **Token Budgeting** | Auto-respects `max_tokens` (~30% index, ~70% details) |
|
|
29
|
+
| **Hybrid Relevance Scoring** | 40% relevance, 30% importance, 20% recency, 10% frequency |
|
|
30
|
+
| **Auto-Summarization** | Generates ≤20-word natural-language summaries |
|
|
31
|
+
| **Entity Extraction** | Detects people, tools, concepts, preferences |
|
|
32
|
+
| **FTS5 Full-Text Search** | Sub-10ms queries, Unicode, stemming — no embeddings |
|
|
33
|
+
| **Provenance Tracking** | Full audit trail: source, timestamp, updates |
|
|
34
|
+
| **Soft Deletes** | Memories preserved for debugging/rollback |
|
|
35
|
+
| **Single-File DB** | `memory.db` — copy, backup, move freely |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
### Prerequisites
|
|
42
|
+
- Node.js ≥ 18
|
|
43
|
+
- An **MCP-compatible client**
|
|
44
|
+
|
|
45
|
+
### Quick Install (NPM)
|
|
46
|
+
```bash
|
|
47
|
+
npx @whenmoon-afk/memory-mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or install globally:
|
|
51
|
+
```bash
|
|
52
|
+
npm install -g @whenmoon-afk/memory-mcp
|
|
53
|
+
memory-mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### From Source
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/WhenMoon-afk/claude-memory-mcp.git
|
|
59
|
+
cd claude-memory-mcp
|
|
60
|
+
npm install
|
|
61
|
+
npm run build
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> Output: `dist/index.js` — your memory server.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Integrate with Your MCP Client
|
|
69
|
+
|
|
70
|
+
Add to your client's MCP config:
|
|
71
|
+
|
|
72
|
+
### Using NPM Package (Recommended)
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"memory": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["@whenmoon-afk/memory-mcp"],
|
|
79
|
+
"env": {
|
|
80
|
+
"MEMORY_DB_PATH": "./memory.db"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Using Global Install
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"memory": {
|
|
92
|
+
"command": "memory-mcp",
|
|
93
|
+
"env": {
|
|
94
|
+
"MEMORY_DB_PATH": "./memory.db"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### From Source
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"mcpServers": {
|
|
105
|
+
"memory": {
|
|
106
|
+
"command": "node",
|
|
107
|
+
"args": ["/absolute/path/to/claude-memory-mcp/dist/index.js"],
|
|
108
|
+
"env": {
|
|
109
|
+
"MEMORY_DB_PATH": "./memory.db"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> Restart or reload MCP servers.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## MCP Tools
|
|
121
|
+
|
|
122
|
+
| Tool | Input | Description |
|
|
123
|
+
|------|-------|-----------|
|
|
124
|
+
| `memory_store` | `{ content, type, importance?, entities?, ttl_days?, provenance? }` | Store or update memory with auto-summary |
|
|
125
|
+
| `memory_recall` | `{ query, type?, entities?, limit?, max_tokens? }` | Search memories with token-aware loading |
|
|
126
|
+
| `memory_forget` | `{ id, reason? }` | Soft-delete memory (preserves provenance) |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### Store a Preference
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"tool": "memory_store",
|
|
135
|
+
"input": {
|
|
136
|
+
"content": "User works best in focused 90-minute blocks with 15-minute breaks.",
|
|
137
|
+
"type": "fact",
|
|
138
|
+
"importance": 8
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
→ Auto-creates:
|
|
144
|
+
- Summary: `"User follows 90/15 focused work cycles."`
|
|
145
|
+
- Entities: `focused work`, `90-minute blocks`
|
|
146
|
+
- Provenance: current session
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### Smart Recall (Dual-Response)
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"tool": "memory_recall",
|
|
155
|
+
"input": {
|
|
156
|
+
"query": "work habits",
|
|
157
|
+
"max_tokens": 1200
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Response**:
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"index": [
|
|
166
|
+
{ "id": "mem_8b1", "summary": "User follows 90/15 focused work cycles.", "score": 96 },
|
|
167
|
+
{ "id": "mem_2c9", "summary": "User avoids meetings before 10 AM.", "score": 88 }
|
|
168
|
+
],
|
|
169
|
+
"details": [
|
|
170
|
+
{
|
|
171
|
+
"id": "mem_8b1",
|
|
172
|
+
"content": "User works best in focused 90-minute blocks with 15-minute breaks.",
|
|
173
|
+
"entities": ["focused work", "90-minute blocks"],
|
|
174
|
+
"provenance": { "source": "chat_2025-11-03", "created_at": "2025-11-03T14:10Z" }
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"meta": {
|
|
178
|
+
"tokens_used": 698,
|
|
179
|
+
"total_matches": 2,
|
|
180
|
+
"truncated": false
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Your AI **knows what it knows** — and can ask for more.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Forget a Memory
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"tool": "memory_forget",
|
|
194
|
+
"input": {
|
|
195
|
+
"id": "mem_8b1",
|
|
196
|
+
"reason": "Information no longer relevant"
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Response**:
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"success": true,
|
|
205
|
+
"memory_id": "mem_8b1",
|
|
206
|
+
"message": "Memory soft-deleted successfully. Reason: Information no longer relevant"
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
> Soft-deleted memories are **preserved** in the database with full provenance trail. They won't appear in searches but remain recoverable.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Dual-Response Pattern
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
[index] → All matching summaries (~20 tokens each)
|
|
218
|
+
[details] → Full content of top memories (budget-capped)
|
|
219
|
+
[meta] → tokens_used, total_matches, truncated
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
- **Index**: Always included → *discovery*
|
|
223
|
+
- **Details**: Budget-safe → *precision*
|
|
224
|
+
- **Follow-up**: Use `ids: [...]` to expand
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Database & Portability
|
|
229
|
+
|
|
230
|
+
- **File**: `memory.db` (SQLite) — path via `MEMORY_DB_PATH`
|
|
231
|
+
- **Portable**: Copy to USB, cloud sync, or new machine
|
|
232
|
+
- **Backup**: Just copy the file
|
|
233
|
+
- **Tip**: For extra security, store `memory.db` on a **VeraCrypt Encrypted USB drive** (adds friction, but maximum control).
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Environment Variables
|
|
238
|
+
|
|
239
|
+
| Var | Default | Description |
|
|
240
|
+
|-----|---------|-----------|
|
|
241
|
+
| `MEMORY_DB_PATH` | `./memory.db` | Database file location |
|
|
242
|
+
| `DEFAULT_TTL_DAYS` | `90` | Default time-to-live for memories (days) |
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### Security
|
|
247
|
+
|
|
248
|
+
This is a **local-only** MCP server.
|
|
249
|
+
Data is stored in a plain SQLite file (`memory.db`).
|
|
250
|
+
For sensitive data, use OS-level encryption (FileVault, BitLocker).
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Best Practices
|
|
255
|
+
|
|
256
|
+
1. **Start with `max_tokens: 1000`** — adjust per model and task.
|
|
257
|
+
2. **Filter by `type`** to reduce noise and improve relevance.
|
|
258
|
+
3. **Use entity filtering** to narrow searches to specific topics.
|
|
259
|
+
4. **Reference provenance**: Track source and context for audit trails.
|
|
260
|
+
5. **Backup `memory.db`** regularly — it's just a file!
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database connection management and utilities
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
import { type DatabaseStats } from './schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* Get or create database connection
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDatabase(path: string): Database.Database;
|
|
10
|
+
/**
|
|
11
|
+
* Close database connection
|
|
12
|
+
*/
|
|
13
|
+
export declare function closeDatabase(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Execute a transaction
|
|
16
|
+
*/
|
|
17
|
+
export declare function transaction<T>(db: Database.Database, fn: () => T): T;
|
|
18
|
+
/**
|
|
19
|
+
* Serialize metadata to JSON string
|
|
20
|
+
*/
|
|
21
|
+
export declare function serializeMetadata(metadata: Record<string, unknown>): string;
|
|
22
|
+
/**
|
|
23
|
+
* Deserialize metadata from JSON string
|
|
24
|
+
*/
|
|
25
|
+
export declare function deserializeMetadata(json: string): Record<string, unknown>;
|
|
26
|
+
/**
|
|
27
|
+
* Generate unique ID
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateId(prefix?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Get current timestamp in milliseconds
|
|
32
|
+
*/
|
|
33
|
+
export declare function now(): number;
|
|
34
|
+
/**
|
|
35
|
+
* Prune expired and deleted memories
|
|
36
|
+
*/
|
|
37
|
+
export interface PruneResult {
|
|
38
|
+
expired_count: number;
|
|
39
|
+
deleted_count: number;
|
|
40
|
+
total_pruned: number;
|
|
41
|
+
}
|
|
42
|
+
export declare function pruneMemories(db: Database.Database, olderThanDays?: number, dryRun?: boolean): PruneResult;
|
|
43
|
+
/**
|
|
44
|
+
* Get database statistics
|
|
45
|
+
*/
|
|
46
|
+
export declare function getStats(db: Database.Database): DatabaseStats;
|
|
47
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/database/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAKrB;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAiC3D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAGpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAE3E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,GAAE,MAAc,GAAG,MAAM,CAIzD;AAED;;GAEG;AACH,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,aAAa,GAAE,MAAU,EACzB,MAAM,GAAE,OAAe,GACtB,WAAW,CAwEb;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,aAAa,CAE7D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database connection management and utilities
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
6
|
+
import { dirname } from 'path';
|
|
7
|
+
import { initializeSchema, createViews, optimizeDatabase, getDatabaseStats, } from './schema.js';
|
|
8
|
+
import { DatabaseError } from '../types/index.js';
|
|
9
|
+
let dbInstance = null;
|
|
10
|
+
/**
|
|
11
|
+
* Get or create database connection
|
|
12
|
+
*/
|
|
13
|
+
export function getDatabase(path) {
|
|
14
|
+
if (dbInstance) {
|
|
15
|
+
return dbInstance;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
// Ensure directory exists
|
|
19
|
+
const dir = dirname(path);
|
|
20
|
+
if (!existsSync(dir)) {
|
|
21
|
+
mkdirSync(dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
// Open database
|
|
24
|
+
dbInstance = new Database(path, {
|
|
25
|
+
verbose: process.env['NODE_ENV'] === 'development' ? () => { } : undefined,
|
|
26
|
+
});
|
|
27
|
+
// Initialize schema
|
|
28
|
+
initializeSchema(dbInstance);
|
|
29
|
+
// Create views
|
|
30
|
+
createViews(dbInstance);
|
|
31
|
+
// Optimize
|
|
32
|
+
optimizeDatabase(dbInstance);
|
|
33
|
+
return dbInstance;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new DatabaseError('Failed to initialize database', {
|
|
37
|
+
path,
|
|
38
|
+
error: error instanceof Error ? error.message : String(error),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Close database connection
|
|
44
|
+
*/
|
|
45
|
+
export function closeDatabase() {
|
|
46
|
+
if (dbInstance) {
|
|
47
|
+
dbInstance.close();
|
|
48
|
+
dbInstance = null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Execute a transaction
|
|
53
|
+
*/
|
|
54
|
+
export function transaction(db, fn) {
|
|
55
|
+
const txn = db.transaction(fn);
|
|
56
|
+
return txn();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Serialize metadata to JSON string
|
|
60
|
+
*/
|
|
61
|
+
export function serializeMetadata(metadata) {
|
|
62
|
+
return JSON.stringify(metadata);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Deserialize metadata from JSON string
|
|
66
|
+
*/
|
|
67
|
+
export function deserializeMetadata(json) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(json);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Generate unique ID
|
|
77
|
+
*/
|
|
78
|
+
export function generateId(prefix = 'mem') {
|
|
79
|
+
const timestamp = Date.now().toString(36);
|
|
80
|
+
const random = Math.random().toString(36).substring(2, 9);
|
|
81
|
+
return `${prefix}_${timestamp}${random}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get current timestamp in milliseconds
|
|
85
|
+
*/
|
|
86
|
+
export function now() {
|
|
87
|
+
return Date.now();
|
|
88
|
+
}
|
|
89
|
+
export function pruneMemories(db, olderThanDays = 0, dryRun = false) {
|
|
90
|
+
const threshold = now() - olderThanDays * 24 * 60 * 60 * 1000;
|
|
91
|
+
// Count expired memories
|
|
92
|
+
const expiredCount = db
|
|
93
|
+
.prepare(`
|
|
94
|
+
SELECT COUNT(*) FROM memories
|
|
95
|
+
WHERE is_deleted = 0
|
|
96
|
+
AND expires_at IS NOT NULL
|
|
97
|
+
AND expires_at <= ?
|
|
98
|
+
`)
|
|
99
|
+
.pluck()
|
|
100
|
+
.get(threshold);
|
|
101
|
+
// Count soft-deleted memories
|
|
102
|
+
const deletedCount = db
|
|
103
|
+
.prepare(`
|
|
104
|
+
SELECT COUNT(*) FROM memories
|
|
105
|
+
WHERE is_deleted = 1
|
|
106
|
+
AND created_at <= ?
|
|
107
|
+
`)
|
|
108
|
+
.pluck()
|
|
109
|
+
.get(threshold);
|
|
110
|
+
if (dryRun) {
|
|
111
|
+
return {
|
|
112
|
+
expired_count: expiredCount,
|
|
113
|
+
deleted_count: deletedCount,
|
|
114
|
+
total_pruned: 0,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Permanently delete expired memories
|
|
118
|
+
const expiredDeleted = db
|
|
119
|
+
.prepare(`
|
|
120
|
+
DELETE FROM memories
|
|
121
|
+
WHERE is_deleted = 0
|
|
122
|
+
AND expires_at IS NOT NULL
|
|
123
|
+
AND expires_at <= ?
|
|
124
|
+
`)
|
|
125
|
+
.run(threshold);
|
|
126
|
+
// Permanently delete soft-deleted memories
|
|
127
|
+
const softDeleted = db
|
|
128
|
+
.prepare(`
|
|
129
|
+
DELETE FROM memories
|
|
130
|
+
WHERE is_deleted = 1
|
|
131
|
+
AND created_at <= ?
|
|
132
|
+
`)
|
|
133
|
+
.run(threshold);
|
|
134
|
+
// Clean up orphaned entities (not linked to any memory)
|
|
135
|
+
db.prepare(`
|
|
136
|
+
DELETE FROM entities
|
|
137
|
+
WHERE id NOT IN (SELECT DISTINCT entity_id FROM memory_entities)
|
|
138
|
+
`).run();
|
|
139
|
+
return {
|
|
140
|
+
expired_count: expiredCount,
|
|
141
|
+
deleted_count: deletedCount,
|
|
142
|
+
total_pruned: expiredDeleted.changes + softDeleted.changes,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get database statistics
|
|
147
|
+
*/
|
|
148
|
+
export function getStats(db) {
|
|
149
|
+
return getDatabaseStats(db);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/database/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,gBAAgB,GAEjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,IAAI,UAAU,GAA6B,IAAI,CAAC;AAEhD;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,gBAAgB;QAChB,UAAU,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE;YAC9B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,SAAS;SAC1E,CAAC,CAAC;QAEH,oBAAoB;QACpB,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAE7B,eAAe;QACf,WAAW,CAAC,UAAU,CAAC,CAAC;QAExB,WAAW;QACX,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAE7B,OAAO,UAAU,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,aAAa,CAAC,+BAA+B,EAAE;YACvD,IAAI;YACJ,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,UAAU,EAAE,CAAC;QACf,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAI,EAAqB,EAAE,EAAW;IAC/D,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC/B,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAiC;IACjE,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB,KAAK;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1D,OAAO,GAAG,MAAM,IAAI,SAAS,GAAG,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,GAAG;IACjB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;AACpB,CAAC;AAWD,MAAM,UAAU,aAAa,CAC3B,EAAqB,EACrB,gBAAwB,CAAC,EACzB,SAAkB,KAAK;IAEvB,MAAM,SAAS,GAAG,GAAG,EAAE,GAAG,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAE9D,yBAAyB;IACzB,MAAM,YAAY,GAAG,EAAE;SACpB,OAAO,CACN;;;;;GAKH,CACE;SACA,KAAK,EAAE;SACP,GAAG,CAAC,SAAS,CAAW,CAAC;IAE5B,8BAA8B;IAC9B,MAAM,YAAY,GAAG,EAAE;SACpB,OAAO,CACN;;;;GAIH,CACE;SACA,KAAK,EAAE;SACP,GAAG,CAAC,SAAS,CAAW,CAAC;IAE5B,IAAI,MAAM,EAAE,CAAC;QACX,OAAO;YACL,aAAa,EAAE,YAAY;YAC3B,aAAa,EAAE,YAAY;YAC3B,YAAY,EAAE,CAAC;SAChB,CAAC;IACJ,CAAC;IAED,sCAAsC;IACtC,MAAM,cAAc,GAAG,EAAE;SACtB,OAAO,CACN;;;;;GAKH,CACE;SACA,GAAG,CAAC,SAAS,CAAC,CAAC;IAElB,2CAA2C;IAC3C,MAAM,WAAW,GAAG,EAAE;SACnB,OAAO,CACN;;;;GAIH,CACE;SACA,GAAG,CAAC,SAAS,CAAC,CAAC;IAElB,wDAAwD;IACxD,EAAE,CAAC,OAAO,CACR;;;GAGD,CACA,CAAC,GAAG,EAAE,CAAC;IAER,OAAO;QACL,aAAa,EAAE,YAAY;QAC3B,aAAa,EAAE,YAAY;QAC3B,YAAY,EAAE,cAAc,CAAC,OAAO,GAAG,WAAW,CAAC,OAAO;KAC3D,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAqB;IAC5C,OAAO,gBAAgB,CAAC,EAAE,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database schema definitions and migrations for Memory MCP
|
|
3
|
+
*/
|
|
4
|
+
import type Database from 'better-sqlite3';
|
|
5
|
+
export declare const SCHEMA_VERSION = 3;
|
|
6
|
+
/**
|
|
7
|
+
* Initialize database schema
|
|
8
|
+
*/
|
|
9
|
+
export declare function initializeSchema(db: Database.Database): void;
|
|
10
|
+
/**
|
|
11
|
+
* Create optimized views for common queries
|
|
12
|
+
*/
|
|
13
|
+
export declare function createViews(db: Database.Database): void;
|
|
14
|
+
/**
|
|
15
|
+
* Optimize database for performance
|
|
16
|
+
*/
|
|
17
|
+
export declare function optimizeDatabase(db: Database.Database): void;
|
|
18
|
+
/**
|
|
19
|
+
* Get database statistics
|
|
20
|
+
*/
|
|
21
|
+
export interface DatabaseStats {
|
|
22
|
+
total_memories: number;
|
|
23
|
+
active_memories: number;
|
|
24
|
+
deleted_memories: number;
|
|
25
|
+
expired_memories: number;
|
|
26
|
+
total_entities: number;
|
|
27
|
+
total_provenance_records: number;
|
|
28
|
+
database_size_bytes: number;
|
|
29
|
+
memory_avg_importance: number;
|
|
30
|
+
oldest_memory_age_days: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function getDatabaseStats(db: Database.Database): DatabaseStats;
|
|
33
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/database/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAqB5D;AAwND;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CA8BvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAU5D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB,EAAE,MAAM,CAAC;IACjC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,aAAa,CAsCrE"}
|