memento-mcp 0.3.17 → 0.3.19
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/package.json +1 -1
- package/scripts/memento-instructions.sh +55 -0
- package/src/cli.js +39 -95
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SessionStart hook (Memento) — inject MCP tool reference into every session.
|
|
3
|
+
# Independent of identity/items injection — always runs.
|
|
4
|
+
# Output: JSON with hookSpecificOutput.additionalContext.
|
|
5
|
+
|
|
6
|
+
# Consume stdin (SessionStart sends JSON we don't need)
|
|
7
|
+
cat > /dev/null
|
|
8
|
+
|
|
9
|
+
read -r -d '' INSTRUCTIONS << 'MEMENTO_EOF'
|
|
10
|
+
# Memento MCP (`mcp__memento__*`)
|
|
11
|
+
|
|
12
|
+
**Load tools:** `ToolSearch query="+memento" max_results=20` — then READ the tool descriptions. They explain when and how to use each one.
|
|
13
|
+
|
|
14
|
+
**Primary system:** Memento SaaS API (`https://memento-api.myrakrusemark.workers.dev`)
|
|
15
|
+
**Dashboard:** `hifathom.com/dashboard`
|
|
16
|
+
|
|
17
|
+
| Tool | What it does |
|
|
18
|
+
|------|-------------|
|
|
19
|
+
| `memento_init` | Initialize workspace (one-time setup) |
|
|
20
|
+
| `memento_health` | System health — item/memory/skip counts, last updated |
|
|
21
|
+
| `memento_read` / `memento_update` | Legacy markdown working memory (sections: active_work, standing_decisions, skip_list, session_notes) |
|
|
22
|
+
| `memento_remember` | Store a memory (fact/decision/observation/instruction) with tags + expiration |
|
|
23
|
+
| `memento_recall` | Search memories by keyword/tag/type — ranked by relevance |
|
|
24
|
+
| `memento_consolidate` | Merge 3+ overlapping memories into one sharper representation |
|
|
25
|
+
| `memento_skip_add` / `memento_skip_check` | Anti-memory: things to NOT investigate right now (with expiration) |
|
|
26
|
+
| `memento_item_create` | Create structured item (active_work/standing_decision/skip_list/waiting_for/session_note) |
|
|
27
|
+
| `memento_item_update` | Update item fields (status, next_action, priority, category, tags) |
|
|
28
|
+
| `memento_item_delete` | Delete item (prefer archiving via status=archived) |
|
|
29
|
+
| `memento_item_list` | List items with filters (category, status, query) |
|
|
30
|
+
| `memento_identity` | Read identity crystal |
|
|
31
|
+
| `memento_identity_update` | Write/replace identity crystal |
|
|
32
|
+
|
|
33
|
+
**Memory discipline — notes are instructions, not logs.**
|
|
34
|
+
Write: "Skip X until condition Y" — not "checked X, it was quiet."
|
|
35
|
+
Every memory must answer: could a future agent with zero context read this and know exactly what to do?
|
|
36
|
+
|
|
37
|
+
Use `memento_remember` when you learn something worth keeping.
|
|
38
|
+
Use `memento_skip_add` for things to explicitly not re-investigate.
|
|
39
|
+
Use `memento_recall` to search memories by keyword or tag.
|
|
40
|
+
Hooks run automatically — recall before responses, distillation before compaction. Trust the hooks. Focus on writing good memories.
|
|
41
|
+
|
|
42
|
+
REMINDER: If Memento MCP tools are not loaded, run: ToolSearch query="+memento" max_results=20
|
|
43
|
+
MEMENTO_EOF
|
|
44
|
+
|
|
45
|
+
python3 -c "
|
|
46
|
+
import json, sys
|
|
47
|
+
print(json.dumps({
|
|
48
|
+
'hookSpecificOutput': {
|
|
49
|
+
'hookEventName': 'SessionStart',
|
|
50
|
+
'additionalContext': sys.argv[1]
|
|
51
|
+
}
|
|
52
|
+
}))
|
|
53
|
+
" "$INSTRUCTIONS"
|
|
54
|
+
|
|
55
|
+
exit 0
|
package/src/cli.js
CHANGED
|
@@ -92,51 +92,6 @@ function httpsPost(url, body) {
|
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
// Instructions blob — appended to CLAUDE.md during init
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
|
|
99
|
-
const INSTRUCTIONS_BLOB = `## Memento Protocol
|
|
100
|
-
|
|
101
|
-
Working memory is managed by Memento. MCP tools available:
|
|
102
|
-
\`memento_remember\`, \`memento_recall\`, \`memento_item_list\`,
|
|
103
|
-
\`memento_skip_add\`, \`memento_skip_check\`.
|
|
104
|
-
|
|
105
|
-
**Memory discipline — notes are instructions, not logs.**
|
|
106
|
-
Write: "Skip X until condition Y" — not "checked X, it was quiet."
|
|
107
|
-
Every memory must answer: could a future agent with zero context
|
|
108
|
-
read this and know exactly what to do?
|
|
109
|
-
|
|
110
|
-
Use \`memento_remember\` when you learn something worth keeping.
|
|
111
|
-
Use \`memento_skip_add\` for things to explicitly not re-investigate.
|
|
112
|
-
Use \`memento_recall\` to search memories by keyword or tag.
|
|
113
|
-
Hooks run automatically — recall before responses, distillation
|
|
114
|
-
before compaction. Trust the hooks. Focus on writing good memories.`;
|
|
115
|
-
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
// CLAUDE.md integration
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
|
|
120
|
-
function appendToClaudeMd(cwd, sectionHeading, blob) {
|
|
121
|
-
const mdPath = path.join(cwd, "CLAUDE.md");
|
|
122
|
-
let content = "";
|
|
123
|
-
try { content = fs.readFileSync(mdPath, "utf-8"); } catch { /* new file */ }
|
|
124
|
-
|
|
125
|
-
const headingEscaped = sectionHeading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
126
|
-
const sectionRe = new RegExp(
|
|
127
|
-
`(^|\\n)(#{1,3} ${headingEscaped}[^\\n]*\\n)([\\s\\S]*?)(?=\\n#{1,3} |$)`,
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
if (sectionRe.test(content)) {
|
|
131
|
-
content = content.replace(sectionRe, `$1${blob}`);
|
|
132
|
-
} else {
|
|
133
|
-
content = content.trimEnd() + "\n\n" + blob + "\n";
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
fs.writeFileSync(mdPath, content, "utf-8");
|
|
137
|
-
return mdPath;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
95
|
// ---------------------------------------------------------------------------
|
|
141
96
|
// CLI flag parsing
|
|
142
97
|
// ---------------------------------------------------------------------------
|
|
@@ -474,11 +429,9 @@ async function runInit(flags = {}) {
|
|
|
474
429
|
writeJsonFile(configPath, config);
|
|
475
430
|
created.push(".memento.json");
|
|
476
431
|
|
|
477
|
-
// 7. Copy hook scripts — gated on
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if (hasHookAgent && anyHookEnabled) {
|
|
432
|
+
// 7. Copy hook scripts — gated on hook-supporting agent
|
|
433
|
+
// Instructions script is always copied; other hooks are gated on user selection
|
|
434
|
+
if (hasHookAgent) {
|
|
482
435
|
const pkgScriptsDir = path.resolve(__dirname, "..", "scripts");
|
|
483
436
|
const localScriptsDir = path.join(cwd, ".memento", "scripts");
|
|
484
437
|
if (!fs.existsSync(localScriptsDir))
|
|
@@ -486,6 +439,7 @@ async function runInit(flags = {}) {
|
|
|
486
439
|
|
|
487
440
|
const scriptFiles = [
|
|
488
441
|
"hook-toast.sh",
|
|
442
|
+
"memento-instructions.sh",
|
|
489
443
|
enableUserPrompt && "memento-userprompt-recall.sh",
|
|
490
444
|
enableStop && "memento-stop-recall.sh",
|
|
491
445
|
enablePreCompact && "memento-precompact-distill.sh",
|
|
@@ -508,6 +462,7 @@ async function runInit(flags = {}) {
|
|
|
508
462
|
fs.writeFileSync(versionPath, pkgVersion + "\n");
|
|
509
463
|
|
|
510
464
|
// Hook script commands (absolute paths)
|
|
465
|
+
const instructionsCmd = path.join(localScriptsDir, "memento-instructions.sh");
|
|
511
466
|
const recallCmd = path.join(localScriptsDir, "memento-userprompt-recall.sh");
|
|
512
467
|
const stopCmd = path.join(localScriptsDir, "memento-stop-recall.sh");
|
|
513
468
|
const precompactCmd = path.join(localScriptsDir, "memento-precompact-distill.sh");
|
|
@@ -518,6 +473,8 @@ async function runInit(flags = {}) {
|
|
|
518
473
|
const settingsPath = path.join(cwd, ".claude", "settings.local.json");
|
|
519
474
|
const settings = readJsonFile(settingsPath) || {};
|
|
520
475
|
let changed = false;
|
|
476
|
+
// Instructions hook always registered (not gated by enableSessionStart)
|
|
477
|
+
changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
|
|
521
478
|
if (enableUserPrompt) changed = ensureHook(settings, "UserPromptSubmit", recallCmd, 5000) || changed;
|
|
522
479
|
if (enableStop) changed = ensureHook(settings, "Stop", stopCmd, 5000) || changed;
|
|
523
480
|
if (enablePreCompact) changed = ensureHook(settings, "PreCompact", precompactCmd, 30000) || changed;
|
|
@@ -533,6 +490,8 @@ async function runInit(flags = {}) {
|
|
|
533
490
|
const settingsPath = path.join(cwd, ".gemini", "settings.json");
|
|
534
491
|
const settings = readJsonFile(settingsPath) || {};
|
|
535
492
|
let changed = false;
|
|
493
|
+
// Instructions hook always registered
|
|
494
|
+
changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
|
|
536
495
|
if (enableUserPrompt) changed = ensureHook(settings, "BeforeAgent", recallCmd, 5000) || changed;
|
|
537
496
|
if (enableStop) changed = ensureHook(settings, "SessionEnd", stopCmd, 5000) || changed;
|
|
538
497
|
if (enablePreCompact) changed = ensureHook(settings, "PreCompress", precompactCmd, 30000) || changed;
|
|
@@ -592,27 +551,6 @@ async function runInit(flags = {}) {
|
|
|
592
551
|
console.log(` Non-interactive equivalent:\n ${parts.join(" ")}\n`);
|
|
593
552
|
}
|
|
594
553
|
|
|
595
|
-
// 12. Append instructions to CLAUDE.md
|
|
596
|
-
if (nonInteractive) {
|
|
597
|
-
const mdPath = appendToClaudeMd(cwd, "Memento Protocol", INSTRUCTIONS_BLOB);
|
|
598
|
-
console.log(`\n ✓ Instructions written to ${path.relative(cwd, mdPath)}\n`);
|
|
599
|
-
} else {
|
|
600
|
-
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
601
|
-
console.log("─".repeat(60));
|
|
602
|
-
const integrate = await askYesNo(
|
|
603
|
-
rl2,
|
|
604
|
-
"\n Append Memento instructions to CLAUDE.md?",
|
|
605
|
-
true,
|
|
606
|
-
);
|
|
607
|
-
rl2.close();
|
|
608
|
-
|
|
609
|
-
if (integrate) {
|
|
610
|
-
const mdPath = appendToClaudeMd(cwd, "Memento Protocol", INSTRUCTIONS_BLOB);
|
|
611
|
-
console.log(`\n ✓ Instructions written to ${path.relative(cwd, mdPath)}\n`);
|
|
612
|
-
} else {
|
|
613
|
-
printInstructionsFallback(selectedAgents);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
554
|
}
|
|
617
555
|
|
|
618
556
|
// ---------------------------------------------------------------------------
|
|
@@ -659,11 +597,25 @@ async function runUpdate() {
|
|
|
659
597
|
const versionPath = path.join(cwd, ".memento", "version");
|
|
660
598
|
fs.writeFileSync(versionPath, pkgVersion + "\n");
|
|
661
599
|
|
|
662
|
-
//
|
|
663
|
-
// Detect by config agents field or directory presence (older configs may lack agents)
|
|
600
|
+
// Read .memento.json to determine which hooks are enabled
|
|
664
601
|
const config = readJsonFile(configPath) || {};
|
|
665
602
|
const agents = config.agents || [];
|
|
603
|
+
const hooks = config.hooks || {};
|
|
604
|
+
const features = config.features || {};
|
|
605
|
+
|
|
606
|
+
// Hook script paths
|
|
607
|
+
const instructionsCmd = path.join(localScriptsDir, "memento-instructions.sh");
|
|
608
|
+
const recallCmd = path.join(localScriptsDir, "memento-userprompt-recall.sh");
|
|
609
|
+
const stopCmd = path.join(localScriptsDir, "memento-stop-recall.sh");
|
|
610
|
+
const precompactCmd = path.join(localScriptsDir, "memento-precompact-distill.sh");
|
|
666
611
|
const sessionStartCmd = path.join(localScriptsDir, "memento-sessionstart-identity.sh");
|
|
612
|
+
|
|
613
|
+
// Hook enabled flags (default to true for recall/stop/precompact if not specified)
|
|
614
|
+
const enableUserPrompt = hooks["userprompt-recall"]?.enabled !== false;
|
|
615
|
+
const enableStop = hooks["stop-recall"]?.enabled !== false;
|
|
616
|
+
const enablePreCompact = hooks["precompact-distill"]?.enabled !== false;
|
|
617
|
+
const enableSessionStart = hooks["sessionstart-identity"]?.enabled && features.identity;
|
|
618
|
+
|
|
667
619
|
const registeredHooks = [];
|
|
668
620
|
|
|
669
621
|
// Claude Code
|
|
@@ -672,7 +624,13 @@ async function runUpdate() {
|
|
|
672
624
|
if (hasClaude) {
|
|
673
625
|
const settingsPath = path.join(cwd, ".claude", "settings.local.json");
|
|
674
626
|
const settings = readJsonFile(settingsPath) || {};
|
|
675
|
-
|
|
627
|
+
let changed = false;
|
|
628
|
+
changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
|
|
629
|
+
if (enableUserPrompt) changed = ensureHook(settings, "UserPromptSubmit", recallCmd, 5000) || changed;
|
|
630
|
+
if (enableStop) changed = ensureHook(settings, "Stop", stopCmd, 5000) || changed;
|
|
631
|
+
if (enablePreCompact) changed = ensureHook(settings, "PreCompact", precompactCmd, 30000) || changed;
|
|
632
|
+
if (enableSessionStart) changed = ensureHook(settings, "SessionStart", sessionStartCmd, 10000) || changed;
|
|
633
|
+
if (changed) {
|
|
676
634
|
writeJsonFile(settingsPath, settings);
|
|
677
635
|
registeredHooks.push("Claude Code → .claude/settings.local.json");
|
|
678
636
|
}
|
|
@@ -684,7 +642,13 @@ async function runUpdate() {
|
|
|
684
642
|
if (hasGemini) {
|
|
685
643
|
const settingsPath = path.join(cwd, ".gemini", "settings.json");
|
|
686
644
|
const settings = readJsonFile(settingsPath) || {};
|
|
687
|
-
|
|
645
|
+
let changed = false;
|
|
646
|
+
changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
|
|
647
|
+
if (enableUserPrompt) changed = ensureHook(settings, "BeforeAgent", recallCmd, 5000) || changed;
|
|
648
|
+
if (enableStop) changed = ensureHook(settings, "SessionEnd", stopCmd, 5000) || changed;
|
|
649
|
+
if (enablePreCompact) changed = ensureHook(settings, "PreCompress", precompactCmd, 30000) || changed;
|
|
650
|
+
if (enableSessionStart) changed = ensureHook(settings, "SessionStart", sessionStartCmd, 10000) || changed;
|
|
651
|
+
if (changed) {
|
|
688
652
|
writeJsonFile(settingsPath, settings);
|
|
689
653
|
registeredHooks.push("Gemini CLI → .gemini/settings.json");
|
|
690
654
|
}
|
|
@@ -705,26 +669,6 @@ async function runUpdate() {
|
|
|
705
669
|
console.log(" Restart your agent session to pick up changes.\n");
|
|
706
670
|
}
|
|
707
671
|
|
|
708
|
-
function printInstructionsFallback(selectedAgents) {
|
|
709
|
-
const hasNonClaude = selectedAgents.some((k) => k !== "claude-code");
|
|
710
|
-
const docTarget = hasNonClaude
|
|
711
|
-
? "your CLAUDE.md, AGENTS.md, or equivalent"
|
|
712
|
-
: "your CLAUDE.md";
|
|
713
|
-
|
|
714
|
-
console.log("─".repeat(60));
|
|
715
|
-
console.log(`
|
|
716
|
-
One more step: paste the following into ${docTarget},
|
|
717
|
-
or hand it to your agent and ask it to add it. This teaches
|
|
718
|
-
your agent the memory discipline Memento expects.
|
|
719
|
-
|
|
720
|
-
── paste below this line ──────────────────────────────
|
|
721
|
-
|
|
722
|
-
${INSTRUCTIONS_BLOB}
|
|
723
|
-
|
|
724
|
-
── paste above this line ──────────────────────────────
|
|
725
|
-
`);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
672
|
// ---------------------------------------------------------------------------
|
|
729
673
|
// Entrypoint — only run when this module is the entry point (not imported)
|
|
730
674
|
// ---------------------------------------------------------------------------
|