@aman_asmuei/amem 0.1.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/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env node
2
+ import { createDatabase } from "./database.js";
3
+ import { recallMemories, MemoryType } from "./memory.js";
4
+ import { generateEmbedding } from "./embeddings.js";
5
+ import path from "node:path";
6
+ import os from "node:os";
7
+ import fs from "node:fs";
8
+ const AMEM_DIR = process.env.AMEM_DIR || path.join(os.homedir(), ".amem");
9
+ const DB_PATH = process.env.AMEM_DB || path.join(AMEM_DIR, "memory.db");
10
+ const args = process.argv.slice(2);
11
+ const command = args[0];
12
+ if (!command || command === "help" || command === "--help" || command === "-h") {
13
+ printHelp();
14
+ process.exit(0);
15
+ }
16
+ if (!fs.existsSync(DB_PATH)) {
17
+ console.error(`No memory database found at ${DB_PATH}`);
18
+ console.error("Start the Amem MCP server first, or set AMEM_DB to your database path.");
19
+ process.exit(1);
20
+ }
21
+ const db = createDatabase(DB_PATH);
22
+ try {
23
+ switch (command) {
24
+ case "recall":
25
+ case "search":
26
+ await handleRecall(args.slice(1));
27
+ break;
28
+ case "stats":
29
+ handleStats();
30
+ break;
31
+ case "export":
32
+ handleExport(args.slice(1));
33
+ break;
34
+ case "forget":
35
+ case "delete":
36
+ handleForget(args.slice(1));
37
+ break;
38
+ case "list":
39
+ case "ls":
40
+ handleList(args.slice(1));
41
+ break;
42
+ default:
43
+ console.error(`Unknown command: ${command}`);
44
+ printHelp();
45
+ process.exit(1);
46
+ }
47
+ }
48
+ finally {
49
+ db.close();
50
+ }
51
+ function printHelp() {
52
+ console.log(`
53
+ amem — The memory layer for AI coding tools
54
+
55
+ USAGE
56
+ amem <command> [options]
57
+
58
+ COMMANDS
59
+ recall <query> Search memories semantically
60
+ stats Show memory statistics
61
+ export [--file path] Export all memories as markdown
62
+ list [--type TYPE] List memories, optionally filtered by type
63
+ forget <id> Delete a memory by ID
64
+ help Show this help
65
+
66
+ MEMORY TYPES
67
+ correction Don't do X (highest priority)
68
+ decision Architectural choices + rationale
69
+ pattern Coding style / habits
70
+ preference Tool / style preferences
71
+ topology Where things are in the codebase
72
+ fact General knowledge (lowest priority)
73
+
74
+ EXAMPLES
75
+ amem recall "authentication approach"
76
+ amem stats
77
+ amem list --type correction
78
+ amem export --file memories.md
79
+ amem forget abc12345
80
+ `.trim());
81
+ }
82
+ async function handleRecall(args) {
83
+ const query = args.join(" ");
84
+ if (!query) {
85
+ console.error("Usage: amem recall <query>");
86
+ process.exit(1);
87
+ }
88
+ console.log(`Searching for: "${query}"\n`);
89
+ const queryEmbedding = await generateEmbedding(query);
90
+ const results = recallMemories(db, {
91
+ query,
92
+ queryEmbedding,
93
+ limit: 20,
94
+ });
95
+ if (results.length === 0) {
96
+ console.log("No memories found.");
97
+ return;
98
+ }
99
+ for (const r of results) {
100
+ const age = formatAge(r.createdAt);
101
+ const conf = (r.confidence * 100).toFixed(0);
102
+ const typeTag = r.type.toUpperCase().padEnd(11);
103
+ console.log(` ${typeTag} ${r.content}`);
104
+ console.log(` Score: ${r.score.toFixed(3)} | Confidence: ${conf}% | Age: ${age} | ID: ${r.id.slice(0, 8)}`);
105
+ if (r.tags.length > 0) {
106
+ console.log(` Tags: ${r.tags.join(", ")}`);
107
+ }
108
+ console.log();
109
+ }
110
+ console.log(`${results.length} memories found.`);
111
+ }
112
+ function handleStats() {
113
+ const stats = db.getStats();
114
+ const all = db.getAll();
115
+ console.log("Amem Memory Statistics\n");
116
+ console.log(` Total memories: ${stats.total}`);
117
+ console.log(` Database: ${DB_PATH}`);
118
+ console.log();
119
+ if (stats.total === 0) {
120
+ console.log(" No memories stored yet.");
121
+ return;
122
+ }
123
+ console.log(" By type:");
124
+ const typeOrder = ["correction", "decision", "pattern", "preference", "topology", "fact"];
125
+ for (const t of typeOrder) {
126
+ const count = stats.byType[t] || 0;
127
+ if (count > 0) {
128
+ const bar = "\u2588".repeat(Math.min(count, 40));
129
+ console.log(` ${t.padEnd(12)} ${bar} ${count}`);
130
+ }
131
+ }
132
+ console.log();
133
+ // Confidence distribution
134
+ const highConf = all.filter(m => m.confidence >= 0.8).length;
135
+ const medConf = all.filter(m => m.confidence >= 0.5 && m.confidence < 0.8).length;
136
+ const lowConf = all.filter(m => m.confidence < 0.5).length;
137
+ console.log(" Confidence:");
138
+ console.log(` High (\u226580%) ${highConf}`);
139
+ console.log(` Medium (50-79%) ${medConf}`);
140
+ console.log(` Low (<50%) ${lowConf}`);
141
+ console.log();
142
+ // Embedding coverage
143
+ const withEmbeddings = db.getAllWithEmbeddings().length;
144
+ console.log(` Embeddings: ${withEmbeddings}/${stats.total} memories have embeddings`);
145
+ // Age stats
146
+ if (all.length > 0) {
147
+ const oldest = Math.min(...all.map(m => m.createdAt));
148
+ const newest = Math.max(...all.map(m => m.createdAt));
149
+ console.log(` Oldest memory: ${formatAge(oldest)}`);
150
+ console.log(` Newest memory: ${formatAge(newest)}`);
151
+ }
152
+ }
153
+ function handleExport(args) {
154
+ let outputPath = null;
155
+ for (let i = 0; i < args.length; i++) {
156
+ if ((args[i] === "--file" || args[i] === "-f") && args[i + 1]) {
157
+ outputPath = args[i + 1];
158
+ break;
159
+ }
160
+ }
161
+ const all = db.getAll();
162
+ if (all.length === 0) {
163
+ console.log("No memories to export.");
164
+ return;
165
+ }
166
+ const typeOrder = ["correction", "decision", "pattern", "preference", "topology", "fact"];
167
+ let md = `# Amem Memory Export\n\n`;
168
+ md += `*Exported: ${new Date().toISOString()}*\n`;
169
+ md += `*Total: ${all.length} memories*\n\n`;
170
+ for (const t of typeOrder) {
171
+ const memories = all.filter(m => m.type === t);
172
+ if (memories.length === 0)
173
+ continue;
174
+ md += `## ${t.charAt(0).toUpperCase() + t.slice(1)}s\n\n`;
175
+ for (const m of memories) {
176
+ const conf = (m.confidence * 100).toFixed(0);
177
+ const age = formatAge(m.createdAt);
178
+ md += `- **${m.content}**\n`;
179
+ md += ` Confidence: ${conf}% | Age: ${age} | Tags: [${m.tags.join(", ")}] | ID: ${m.id.slice(0, 8)}\n\n`;
180
+ }
181
+ }
182
+ if (outputPath) {
183
+ fs.writeFileSync(outputPath, md);
184
+ console.log(`Exported ${all.length} memories to ${outputPath}`);
185
+ }
186
+ else {
187
+ process.stdout.write(md);
188
+ }
189
+ }
190
+ function handleList(args) {
191
+ let typeFilter;
192
+ for (let i = 0; i < args.length; i++) {
193
+ if ((args[i] === "--type" || args[i] === "-t") && args[i + 1]) {
194
+ typeFilter = args[i + 1];
195
+ break;
196
+ }
197
+ }
198
+ let memories;
199
+ if (typeFilter) {
200
+ const validTypes = Object.values(MemoryType);
201
+ if (!validTypes.includes(typeFilter)) {
202
+ console.error(`Invalid type: ${typeFilter}. Valid types: ${validTypes.join(", ")}`);
203
+ process.exit(1);
204
+ }
205
+ memories = db.searchByType(typeFilter);
206
+ }
207
+ else {
208
+ memories = db.getAll();
209
+ }
210
+ if (memories.length === 0) {
211
+ console.log("No memories found.");
212
+ return;
213
+ }
214
+ for (const m of memories) {
215
+ const conf = (m.confidence * 100).toFixed(0);
216
+ const typeTag = m.type.toUpperCase().padEnd(11);
217
+ console.log(` ${m.id.slice(0, 8)} ${typeTag} ${m.content} (${conf}%)`);
218
+ }
219
+ console.log(`\n${memories.length} memories.`);
220
+ }
221
+ function handleForget(args) {
222
+ const id = args[0];
223
+ if (!id) {
224
+ console.error("Usage: amem forget <memory-id>");
225
+ console.error("Use 'amem list' to see memory IDs.");
226
+ process.exit(1);
227
+ }
228
+ // Support short IDs (first 8 chars)
229
+ const all = db.getAll();
230
+ const match = all.find(m => m.id.startsWith(id));
231
+ if (!match) {
232
+ console.error(`No memory found matching ID: ${id}`);
233
+ process.exit(1);
234
+ }
235
+ db.deleteMemory(match.id);
236
+ console.log(`Deleted: "${match.content}" (${match.type})`);
237
+ }
238
+ function formatAge(timestamp) {
239
+ const ms = Date.now() - timestamp;
240
+ const minutes = Math.floor(ms / 60000);
241
+ if (minutes < 60)
242
+ return `${minutes}m ago`;
243
+ const hours = Math.floor(minutes / 60);
244
+ if (hours < 24)
245
+ return `${hours}h ago`;
246
+ const days = Math.floor(hours / 24);
247
+ if (days < 30)
248
+ return `${days}d ago`;
249
+ const months = Math.floor(days / 30);
250
+ return `${months}mo ago`;
251
+ }
252
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Memory, MemoryTypeValue } from "./memory.js";
2
+ export interface MemoryInput {
3
+ content: string;
4
+ type: MemoryTypeValue;
5
+ tags: string[];
6
+ confidence: number;
7
+ source: string;
8
+ embedding: Float32Array | null;
9
+ }
10
+ export interface MemoryStats {
11
+ total: number;
12
+ byType: Record<string, number>;
13
+ }
14
+ export interface AmemDatabase {
15
+ insertMemory(input: MemoryInput): string;
16
+ getById(id: string): Memory | null;
17
+ searchByType(type: MemoryTypeValue): Memory[];
18
+ searchByTag(tag: string): Memory[];
19
+ getAllWithEmbeddings(): Memory[];
20
+ getAll(): Memory[];
21
+ updateConfidence(id: string, confidence: number): void;
22
+ updateEmbedding(id: string, embedding: Float32Array): void;
23
+ touchAccess(id: string): void;
24
+ deleteMemory(id: string): void;
25
+ getStats(): MemoryStats;
26
+ listTables(): string[];
27
+ close(): void;
28
+ }
29
+ export declare function createDatabase(dbPath: string): AmemDatabase;
@@ -0,0 +1,124 @@
1
+ import Database from "better-sqlite3";
2
+ import { randomUUID } from "node:crypto";
3
+ function rowToMemory(row) {
4
+ return {
5
+ id: row.id,
6
+ content: row.content,
7
+ type: row.type,
8
+ tags: JSON.parse(row.tags),
9
+ confidence: row.confidence,
10
+ accessCount: row.access_count,
11
+ createdAt: row.created_at,
12
+ lastAccessed: row.last_accessed,
13
+ source: row.source,
14
+ embedding: row.embedding
15
+ ? new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4)
16
+ : null,
17
+ };
18
+ }
19
+ export function createDatabase(dbPath) {
20
+ const db = new Database(dbPath);
21
+ db.pragma("journal_mode = WAL");
22
+ db.exec(`
23
+ CREATE TABLE IF NOT EXISTS memories (
24
+ id TEXT PRIMARY KEY,
25
+ content TEXT NOT NULL,
26
+ type TEXT NOT NULL,
27
+ tags TEXT NOT NULL DEFAULT '[]',
28
+ confidence REAL NOT NULL DEFAULT 1.0,
29
+ access_count INTEGER NOT NULL DEFAULT 0,
30
+ created_at INTEGER NOT NULL,
31
+ last_accessed INTEGER NOT NULL,
32
+ source TEXT NOT NULL,
33
+ embedding BLOB
34
+ );
35
+
36
+ CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
37
+ CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at);
38
+ CREATE INDEX IF NOT EXISTS idx_memories_confidence ON memories(confidence);
39
+ `);
40
+ const stmts = {
41
+ insert: db.prepare(`
42
+ INSERT INTO memories (id, content, type, tags, confidence, access_count, created_at, last_accessed, source, embedding)
43
+ VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, ?)
44
+ `),
45
+ getById: db.prepare(`SELECT * FROM memories WHERE id = ?`),
46
+ searchByType: db.prepare(`SELECT * FROM memories WHERE type = ? ORDER BY last_accessed DESC`),
47
+ searchByTag: db.prepare(`SELECT * FROM memories WHERE tags LIKE ? ORDER BY last_accessed DESC`),
48
+ getAllWithEmbeddings: db.prepare(`SELECT * FROM memories WHERE embedding IS NOT NULL`),
49
+ getAll: db.prepare(`SELECT * FROM memories ORDER BY last_accessed DESC`),
50
+ updateConfidence: db.prepare(`
51
+ UPDATE memories SET confidence = ?, access_count = access_count + 1, last_accessed = ? WHERE id = ?
52
+ `),
53
+ updateEmbedding: db.prepare(`UPDATE memories SET embedding = ? WHERE id = ?`),
54
+ touchAccess: db.prepare(`
55
+ UPDATE memories SET access_count = access_count + 1, last_accessed = ? WHERE id = ?
56
+ `),
57
+ deleteMemory: db.prepare(`DELETE FROM memories WHERE id = ?`),
58
+ countAll: db.prepare(`SELECT COUNT(*) as count FROM memories`),
59
+ countByType: db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`),
60
+ listTables: db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name`),
61
+ };
62
+ return {
63
+ insertMemory(input) {
64
+ const id = randomUUID();
65
+ const now = Date.now();
66
+ const embeddingBuffer = input.embedding
67
+ ? Buffer.from(input.embedding.buffer, input.embedding.byteOffset, input.embedding.byteLength)
68
+ : null;
69
+ stmts.insert.run(id, input.content, input.type, JSON.stringify(input.tags), input.confidence, now, now, input.source, embeddingBuffer);
70
+ return id;
71
+ },
72
+ getById(id) {
73
+ const row = stmts.getById.get(id);
74
+ return row ? rowToMemory(row) : null;
75
+ },
76
+ searchByType(type) {
77
+ const rows = stmts.searchByType.all(type);
78
+ return rows.map(rowToMemory);
79
+ },
80
+ searchByTag(tag) {
81
+ const pattern = `%"${tag}"%`;
82
+ const rows = stmts.searchByTag.all(pattern);
83
+ return rows.map(rowToMemory);
84
+ },
85
+ getAllWithEmbeddings() {
86
+ const rows = stmts.getAllWithEmbeddings.all();
87
+ return rows.map(rowToMemory);
88
+ },
89
+ getAll() {
90
+ const rows = stmts.getAll.all();
91
+ return rows.map(rowToMemory);
92
+ },
93
+ updateConfidence(id, confidence) {
94
+ stmts.updateConfidence.run(confidence, Date.now(), id);
95
+ },
96
+ updateEmbedding(id, embedding) {
97
+ const buffer = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
98
+ stmts.updateEmbedding.run(buffer, id);
99
+ },
100
+ touchAccess(id) {
101
+ stmts.touchAccess.run(Date.now(), id);
102
+ },
103
+ deleteMemory(id) {
104
+ stmts.deleteMemory.run(id);
105
+ },
106
+ getStats() {
107
+ const total = stmts.countAll.get().count;
108
+ const typeCounts = stmts.countByType.all();
109
+ const byType = {};
110
+ for (const row of typeCounts) {
111
+ byType[row.type] = row.count;
112
+ }
113
+ return { total, byType };
114
+ },
115
+ listTables() {
116
+ const rows = stmts.listTables.all();
117
+ return rows.map((r) => r.name);
118
+ },
119
+ close() {
120
+ db.close();
121
+ },
122
+ };
123
+ }
124
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare function cosineSimilarity(a: Float32Array, b: Float32Array): number;
2
+ export interface EmbeddingCandidate<T> {
3
+ id: string;
4
+ embedding: Float32Array;
5
+ data: T;
6
+ }
7
+ export interface SimilarityResult<T> {
8
+ id: string;
9
+ similarity: number;
10
+ data: T;
11
+ }
12
+ export declare function findTopK<T>(query: Float32Array, candidates: EmbeddingCandidate<T>[], k: number): SimilarityResult<T>[];
13
+ export declare function generateEmbedding(text: string): Promise<Float32Array | null>;
14
+ export declare function isEmbeddingAvailable(): Promise<boolean>;
@@ -0,0 +1,54 @@
1
+ export function cosineSimilarity(a, b) {
2
+ let dot = 0;
3
+ let normA = 0;
4
+ let normB = 0;
5
+ for (let i = 0; i < a.length; i++) {
6
+ dot += a[i] * b[i];
7
+ normA += a[i] * a[i];
8
+ normB += b[i] * b[i];
9
+ }
10
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
11
+ if (denom === 0)
12
+ return 0;
13
+ return dot / denom;
14
+ }
15
+ export function findTopK(query, candidates, k) {
16
+ const scored = candidates.map((c) => ({
17
+ id: c.id,
18
+ similarity: cosineSimilarity(query, c.embedding),
19
+ data: c.data,
20
+ }));
21
+ scored.sort((a, b) => b.similarity - a.similarity);
22
+ return scored.slice(0, k);
23
+ }
24
+ let pipelineInstance = null;
25
+ let pipelineLoading = null;
26
+ async function getEmbeddingPipeline() {
27
+ if (pipelineInstance)
28
+ return pipelineInstance;
29
+ if (pipelineLoading)
30
+ return pipelineLoading;
31
+ pipelineLoading = (async () => {
32
+ try {
33
+ const mod = await import("@huggingface/transformers");
34
+ pipelineInstance = await mod.pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
35
+ return pipelineInstance;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ })();
41
+ return pipelineLoading;
42
+ }
43
+ export async function generateEmbedding(text) {
44
+ const extractor = await getEmbeddingPipeline();
45
+ if (!extractor)
46
+ return null;
47
+ const result = await extractor(text, { pooling: "mean", normalize: true });
48
+ return new Float32Array(result.data);
49
+ }
50
+ export async function isEmbeddingAvailable() {
51
+ const extractor = await getEmbeddingPipeline();
52
+ return extractor !== null;
53
+ }
54
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,CAAe,EAAE,CAAe;IAC/D,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC1B,OAAO,GAAG,GAAG,KAAK,CAAC;AACrB,CAAC;AAcD,MAAM,UAAU,QAAQ,CACtB,KAAmB,EACnB,UAAmC,EACnC,CAAS;IAET,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpC,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,UAAU,EAAE,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,SAAS,CAAC;QAChD,IAAI,EAAE,CAAC,CAAC,IAAI;KACb,CAAC,CAAC,CAAC;IACJ,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,IAAI,gBAAgB,GAAQ,IAAI,CAAC;AACjC,IAAI,eAAe,GAAwB,IAAI,CAAC;AAEhD,KAAK,UAAU,oBAAoB;IACjC,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAC;IAC9C,IAAI,eAAe;QAAE,OAAO,eAAe,CAAC;IAE5C,eAAe,GAAG,CAAC,KAAK,IAAI,EAAE;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;YACtD,gBAAgB,GAAG,MAAM,GAAG,CAAC,QAAQ,CACnC,oBAAoB,EACpB,yBAAyB,CAC1B,CAAC;YACF,OAAO,gBAAgB,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAY;IAEZ,MAAM,SAAS,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,SAAS,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAC/C,OAAO,SAAS,KAAK,IAAI,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { createDatabase } from "./database.js";
5
+ import { registerTools } from "./tools.js";
6
+ import path from "node:path";
7
+ import os from "node:os";
8
+ import fs from "node:fs";
9
+ const AMEM_DIR = process.env.AMEM_DIR || path.join(os.homedir(), ".amem");
10
+ const DB_PATH = process.env.AMEM_DB || path.join(AMEM_DIR, "memory.db");
11
+ fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
12
+ const db = createDatabase(DB_PATH);
13
+ const server = new McpServer({
14
+ name: "amem",
15
+ version: "0.1.0",
16
+ });
17
+ registerTools(server, db);
18
+ // Register MCP prompts — these teach AI clients how to use Amem effectively
19
+ server.prompt("extraction-guide", "Guidelines for what to extract from conversations into Amem memory", () => ({
20
+ messages: [{
21
+ role: "user",
22
+ content: {
23
+ type: "text",
24
+ text: `You have access to Amem, a persistent memory system. Use it to remember important information across conversations.
25
+
26
+ ## What to Extract
27
+
28
+ Watch for these during conversation and extract them using memory_extract:
29
+
30
+ | Signal | Type | Confidence | Example |
31
+ |--------|------|------------|---------|
32
+ | User corrects you | correction | 1.0 | "Don't mock the DB in integration tests" |
33
+ | Architecture/design choice made | decision | 0.9 | "Chose event sourcing for audit trail" |
34
+ | User shows preferred coding style | pattern | 0.7 | "Prefers early returns over nested ifs" |
35
+ | Tool or workflow preference expressed | preference | 0.8 | "Uses pnpm, not npm" |
36
+ | Codebase location revealed | topology | 0.7 | "Auth module is in src/auth/" |
37
+ | Project fact established | fact | 0.6 | "API uses REST, not GraphQL" |
38
+
39
+ ## When to Extract
40
+
41
+ - After every ~10 exchanges
42
+ - After any significant decision or correction
43
+ - Before the conversation ends
44
+ - When you notice something the user would want remembered
45
+
46
+ ## How to Extract
47
+
48
+ Call memory_extract with an array of memories. Each memory should be:
49
+ - **Self-contained**: Understandable without conversation context
50
+ - **Specific**: "Uses Tailwind with custom theme" not "Has a CSS framework"
51
+ - **Actionable**: Useful for future coding decisions
52
+
53
+ ## What NOT to Extract
54
+
55
+ - Ephemeral task details ("currently debugging X")
56
+ - Things obvious from the code itself
57
+ - Sensitive data (API keys, passwords)
58
+ - Exact file contents (just reference the path)`,
59
+ },
60
+ }],
61
+ }));
62
+ // Register MCP resources — proactive context that clients can read automatically
63
+ server.resource("corrections", "amem://corrections", { mimeType: "text/plain", description: "All active corrections — hard constraints that should always be followed" }, () => {
64
+ const corrections = db.searchByType("correction");
65
+ if (corrections.length === 0) {
66
+ return { contents: [{ uri: "amem://corrections", mimeType: "text/plain", text: "No corrections stored." }] };
67
+ }
68
+ const text = corrections
69
+ .sort((a, b) => b.confidence - a.confidence)
70
+ .map(c => `- ${c.content} (${(c.confidence * 100).toFixed(0)}% confidence)`)
71
+ .join("\n");
72
+ return {
73
+ contents: [{ uri: "amem://corrections", mimeType: "text/plain", text: `# Corrections (${corrections.length})\n\n${text}` }],
74
+ };
75
+ });
76
+ server.resource("decisions", "amem://decisions", { mimeType: "text/plain", description: "Active architectural decisions and their rationale" }, () => {
77
+ const decisions = db.searchByType("decision");
78
+ if (decisions.length === 0) {
79
+ return { contents: [{ uri: "amem://decisions", mimeType: "text/plain", text: "No decisions stored." }] };
80
+ }
81
+ const text = decisions
82
+ .sort((a, b) => b.confidence - a.confidence)
83
+ .map(d => `- ${d.content} (${(d.confidence * 100).toFixed(0)}% confidence)`)
84
+ .join("\n");
85
+ return {
86
+ contents: [{ uri: "amem://decisions", mimeType: "text/plain", text: `# Decisions (${decisions.length})\n\n${text}` }],
87
+ };
88
+ });
89
+ server.resource("profile", "amem://profile", { mimeType: "text/plain", description: "Developer profile — preferences, patterns, and tool choices" }, () => {
90
+ const preferences = db.searchByType("preference");
91
+ const patterns = db.searchByType("pattern");
92
+ const all = [...preferences, ...patterns].sort((a, b) => b.confidence - a.confidence);
93
+ if (all.length === 0) {
94
+ return { contents: [{ uri: "amem://profile", mimeType: "text/plain", text: "No profile data stored." }] };
95
+ }
96
+ const prefText = preferences.length > 0
97
+ ? "## Preferences\n\n" + preferences.map(p => `- ${p.content}`).join("\n")
98
+ : "";
99
+ const patText = patterns.length > 0
100
+ ? "## Patterns\n\n" + patterns.map(p => `- ${p.content}`).join("\n")
101
+ : "";
102
+ return {
103
+ contents: [{ uri: "amem://profile", mimeType: "text/plain", text: [prefText, patText].filter(Boolean).join("\n\n") }],
104
+ };
105
+ });
106
+ server.resource("summary", "amem://summary", { mimeType: "text/plain", description: "Quick summary of all stored memories" }, () => {
107
+ const stats = db.getStats();
108
+ if (stats.total === 0) {
109
+ return { contents: [{ uri: "amem://summary", mimeType: "text/plain", text: "No memories stored yet." }] };
110
+ }
111
+ const typeOrder = ["correction", "decision", "pattern", "preference", "topology", "fact"];
112
+ const lines = typeOrder
113
+ .filter(t => (stats.byType[t] || 0) > 0)
114
+ .map(t => ` ${t}: ${stats.byType[t]}`);
115
+ const text = `Amem: ${stats.total} memories\n\n${lines.join("\n")}`;
116
+ return {
117
+ contents: [{ uri: "amem://summary", mimeType: "text/plain", text }],
118
+ };
119
+ });
120
+ server.prompt("session-start", "Load relevant context at the start of a conversation", () => ({
121
+ messages: [{
122
+ role: "user",
123
+ content: {
124
+ type: "text",
125
+ text: `You have access to Amem memory. At the start of this conversation:
126
+
127
+ 1. Call memory_context with the likely topic (based on what the user asks about)
128
+ 2. Use any corrections as hard constraints — they override other context
129
+ 3. Use decisions and patterns to inform your approach
130
+ 4. Mention relevant memories naturally: "I remember you prefer X" not "According to my memory database..."
131
+
132
+ If the user seems to be continuing previous work, call memory_recall to find relevant history.`,
133
+ },
134
+ }],
135
+ }));
136
+ process.on("SIGINT", () => {
137
+ db.close();
138
+ process.exit(0);
139
+ });
140
+ process.on("SIGTERM", () => {
141
+ db.close();
142
+ process.exit(0);
143
+ });
144
+ const transport = new StdioServerTransport();
145
+ await server.connect(transport);
146
+ console.error("Amem running. DB: " + DB_PATH);
147
+ //# sourceMappingURL=index.js.map