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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memento-mcp",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
4
4
  "mcpName": "io.github.myrakrusemark/memento-protocol",
5
5
  "description": "The Memento Protocol — persistent memory for AI agents",
6
6
  "type": "module",
@@ -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 any hook-supporting agent
478
- const anyHookEnabled =
479
- enableUserPrompt || enableStop || enablePreCompact || enableSessionStart;
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
- // Ensure SessionStart hook is registered for agents that support hooks
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
- if (ensureHook(settings, "SessionStart", sessionStartCmd, 10000)) {
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
- if (ensureHook(settings, "SessionStart", sessionStartCmd, 10000)) {
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
  // ---------------------------------------------------------------------------