@jungjaehoon/mama-server 1.10.0 → 1.11.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/README.md
CHANGED
|
@@ -231,7 +231,7 @@ Interactive visualization of your reasoning graph.
|
|
|
231
231
|
## Technical Details
|
|
232
232
|
|
|
233
233
|
- **Database:** SQLite + pure-TS cosine similarity
|
|
234
|
-
- **Embeddings:** Transformers.js (Xenova/multilingual-e5-
|
|
234
|
+
- **Embeddings:** Transformers.js (Xenova/multilingual-e5-large, 1024-dim)
|
|
235
235
|
- **Transport:** stdio-based MCP protocol (default) + optional HTTP embedding server (port 3849)
|
|
236
236
|
- **Storage:** ~/.claude/mama-memory.db (configurable via MAMA_DB_PATH)
|
|
237
237
|
- **Port File:** ~/.mama-embedding-port (for client discovery)
|
package/package.json
CHANGED
|
@@ -119,7 +119,7 @@ CREATE INDEX IF NOT EXISTS idx_sessions_last_active ON sessions(last_active_at);
|
|
|
119
119
|
-- because sqlite-vss requires extension loading first
|
|
120
120
|
--
|
|
121
121
|
-- CREATE VIRTUAL TABLE vss_memories USING vss0(
|
|
122
|
-
-- embedding(
|
|
122
|
+
-- embedding(1024) -- multilingual-e5-large embeddings
|
|
123
123
|
-- );
|
|
124
124
|
|
|
125
125
|
-- ══════════════════════════════════════════════════════════════
|
|
@@ -33,7 +33,7 @@ CREATE TABLE IF NOT EXISTS error_patterns (
|
|
|
33
33
|
first_seen INTEGER NOT NULL, -- First occurrence timestamp
|
|
34
34
|
|
|
35
35
|
-- Vector Embedding (for semantic matching)
|
|
36
|
-
embedding BLOB, --
|
|
36
|
+
embedding BLOB, -- 1024-dim embedding (multilingual-e5-large)
|
|
37
37
|
|
|
38
38
|
-- Metadata
|
|
39
39
|
created_at INTEGER DEFAULT (unixepoch()),
|
|
@@ -56,7 +56,7 @@ const FIX_INSTRUCTIONS = {
|
|
|
56
56
|
steps: [
|
|
57
57
|
'1. Install Transformers.js: npm install @xenova/transformers',
|
|
58
58
|
'2. Configure model in ~/.mama/config.json:',
|
|
59
|
-
' { "embeddingModel": "Xenova/multilingual-e5-
|
|
59
|
+
' { "embeddingModel": "Xenova/multilingual-e5-large" }',
|
|
60
60
|
'3. Restart Claude Code to reload configuration',
|
|
61
61
|
],
|
|
62
62
|
impact: 'Without embeddings, MAMA falls back to keyword search (30% less accurate)',
|
package/src/server.js
CHANGED
|
@@ -28,9 +28,9 @@ const {
|
|
|
28
28
|
} = require('@modelcontextprotocol/sdk/types.js');
|
|
29
29
|
const path = require('path');
|
|
30
30
|
|
|
31
|
-
// Import MAMA tools
|
|
32
|
-
|
|
33
|
-
const
|
|
31
|
+
// Import all MAMA tools from src/tools/ — single source of truth for tool definitions
|
|
32
|
+
const { createMemoryTools } = require('./tools/index.js');
|
|
33
|
+
const memoryTools = createMemoryTools();
|
|
34
34
|
const mama = require('@jungjaehoon/mama-core/mama-api');
|
|
35
35
|
|
|
36
36
|
// Import core modules from mama-core
|
|
@@ -248,6 +248,28 @@ type='checkpoint': session state for resumption (ALSO requires search first!)`,
|
|
|
248
248
|
minimum: 0,
|
|
249
249
|
maximum: 1,
|
|
250
250
|
},
|
|
251
|
+
// Scope & temporal fields
|
|
252
|
+
scopes: {
|
|
253
|
+
type: 'array',
|
|
254
|
+
items: {
|
|
255
|
+
type: 'object',
|
|
256
|
+
properties: {
|
|
257
|
+
kind: {
|
|
258
|
+
type: 'string',
|
|
259
|
+
enum: ['global', 'user', 'channel', 'project'],
|
|
260
|
+
},
|
|
261
|
+
id: { type: 'string' },
|
|
262
|
+
},
|
|
263
|
+
required: ['kind', 'id'],
|
|
264
|
+
},
|
|
265
|
+
description:
|
|
266
|
+
'[Decision] Memory scopes for isolation. Example: [{"kind": "project", "id": "/path/to/project"}]',
|
|
267
|
+
},
|
|
268
|
+
event_date: {
|
|
269
|
+
type: 'string',
|
|
270
|
+
description:
|
|
271
|
+
'[Decision] ISO 8601 date when the event occurred (e.g., "2024-01-15"). Defaults to now.',
|
|
272
|
+
},
|
|
251
273
|
// Checkpoint fields
|
|
252
274
|
summary: {
|
|
253
275
|
type: 'string',
|
|
@@ -311,6 +333,21 @@ When presenting search results to the user or agent, include a brief **Reasoning
|
|
|
311
333
|
type: 'number',
|
|
312
334
|
description: 'Maximum results. Default: 10',
|
|
313
335
|
},
|
|
336
|
+
scopes: {
|
|
337
|
+
type: 'array',
|
|
338
|
+
items: {
|
|
339
|
+
type: 'object',
|
|
340
|
+
properties: {
|
|
341
|
+
kind: {
|
|
342
|
+
type: 'string',
|
|
343
|
+
enum: ['global', 'user', 'channel', 'project'],
|
|
344
|
+
},
|
|
345
|
+
id: { type: 'string' },
|
|
346
|
+
},
|
|
347
|
+
required: ['kind', 'id'],
|
|
348
|
+
},
|
|
349
|
+
description: 'Filter search results by scope.',
|
|
350
|
+
},
|
|
314
351
|
},
|
|
315
352
|
},
|
|
316
353
|
},
|
|
@@ -409,6 +446,14 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
|
|
|
409
446
|
properties: {},
|
|
410
447
|
},
|
|
411
448
|
},
|
|
449
|
+
// === v2 tools from src/tools/ ===
|
|
450
|
+
...Object.values(memoryTools)
|
|
451
|
+
.filter((t) => t.name && t.inputSchema)
|
|
452
|
+
.map((t) => ({
|
|
453
|
+
name: t.name,
|
|
454
|
+
description: t.description,
|
|
455
|
+
inputSchema: t.inputSchema,
|
|
456
|
+
})),
|
|
412
457
|
],
|
|
413
458
|
}));
|
|
414
459
|
|
|
@@ -435,10 +480,15 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
|
|
|
435
480
|
result = await this.handleSearchDecisionsAndContracts(args);
|
|
436
481
|
break;
|
|
437
482
|
case 'load_checkpoint':
|
|
438
|
-
result = await
|
|
483
|
+
result = await memoryTools.load_checkpoint.handler(args);
|
|
439
484
|
break;
|
|
440
485
|
default:
|
|
441
|
-
|
|
486
|
+
// Route to src/tools/ handlers
|
|
487
|
+
if (memoryTools[name] && typeof memoryTools[name].handler === 'function') {
|
|
488
|
+
result = await memoryTools[name].handler(args);
|
|
489
|
+
} else {
|
|
490
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
491
|
+
}
|
|
442
492
|
}
|
|
443
493
|
|
|
444
494
|
const shouldInjectLegacyNotice =
|
|
@@ -490,11 +540,19 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
|
|
|
490
540
|
const { type } = args;
|
|
491
541
|
|
|
492
542
|
if (type === 'decision') {
|
|
493
|
-
const { topic, decision, reasoning, confidence = 0.5 } = args;
|
|
543
|
+
const { topic, decision, reasoning, confidence = 0.5, scopes, event_date } = args;
|
|
494
544
|
if (!topic || !decision || !reasoning) {
|
|
495
545
|
return { success: false, message: '❌ Decision requires: topic, decision, reasoning' };
|
|
496
546
|
}
|
|
497
|
-
const id = await mama.save({
|
|
547
|
+
const id = await mama.save({
|
|
548
|
+
type: 'user_decision',
|
|
549
|
+
topic,
|
|
550
|
+
decision,
|
|
551
|
+
reasoning,
|
|
552
|
+
confidence,
|
|
553
|
+
...(scopes && { scopes }),
|
|
554
|
+
...(event_date && { event_date }),
|
|
555
|
+
});
|
|
498
556
|
return {
|
|
499
557
|
success: true,
|
|
500
558
|
id,
|
|
@@ -524,7 +582,7 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
|
|
|
524
582
|
* Handle unified search (decisions + checkpoints)
|
|
525
583
|
*/
|
|
526
584
|
async handleSearch(args) {
|
|
527
|
-
const { query, type = 'all', limit = 10 } = args;
|
|
585
|
+
const { query, type = 'all', limit = 10, scopes } = args;
|
|
528
586
|
|
|
529
587
|
const results = [];
|
|
530
588
|
|
|
@@ -532,12 +590,13 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
|
|
|
532
590
|
if (type === 'all' || type === 'decision') {
|
|
533
591
|
let decisions;
|
|
534
592
|
if (query) {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
593
|
+
const suggestResult = await mama.suggest(query, {
|
|
594
|
+
limit,
|
|
595
|
+
...(scopes && { scopes }),
|
|
596
|
+
});
|
|
538
597
|
decisions = suggestResult?.results || [];
|
|
539
598
|
} else {
|
|
540
|
-
decisions = await mama.list(limit);
|
|
599
|
+
decisions = await mama.list({ limit, ...(scopes && { scopes }) });
|
|
541
600
|
}
|
|
542
601
|
// Ensure decisions is an array
|
|
543
602
|
if (Array.isArray(decisions)) {
|
|
@@ -564,9 +623,13 @@ Returns: summary (4-section), next_steps (DoD + commands), open_files
|
|
|
564
623
|
);
|
|
565
624
|
}
|
|
566
625
|
|
|
567
|
-
//
|
|
568
|
-
|
|
569
|
-
const
|
|
626
|
+
// Decisions are already sorted by similarity from suggest().
|
|
627
|
+
// Only sort checkpoints by time. Keep decisions first (relevance), checkpoints after (recency).
|
|
628
|
+
const decisions = results.filter((r) => r._type === 'decision');
|
|
629
|
+
const checkpoints = results
|
|
630
|
+
.filter((r) => r._type === 'checkpoint')
|
|
631
|
+
.sort((a, b) => (b.created_at || 0) - (a.created_at || 0));
|
|
632
|
+
const limited = [...decisions, ...checkpoints].slice(0, limit);
|
|
570
633
|
|
|
571
634
|
return {
|
|
572
635
|
success: true,
|