memento-mcp 0.3.16 → 0.3.18

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.16",
3
+ "version": "0.3.18",
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
@@ -9,7 +9,6 @@ import readline from "node:readline";
9
9
  import fs from "node:fs";
10
10
  import path from "node:path";
11
11
  import https from "node:https";
12
- import { execFileSync } from "node:child_process";
13
12
  import { fileURLToPath } from "node:url";
14
13
  import { DEFAULTS } from "./config.js";
15
14
 
@@ -93,68 +92,6 @@ function httpsPost(url, body) {
93
92
  });
94
93
  }
95
94
 
96
- // ---------------------------------------------------------------------------
97
- // Instructions blob — used by headless integration and fallback print
98
- // ---------------------------------------------------------------------------
99
-
100
- const INSTRUCTIONS_BLOB = `## Memento Protocol
101
-
102
- Working memory is managed by Memento. MCP tools available:
103
- \`memento_remember\`, \`memento_recall\`, \`memento_item_list\`,
104
- \`memento_skip_add\`, \`memento_skip_check\`.
105
-
106
- **Memory discipline — notes are instructions, not logs.**
107
- Write: "Skip X until condition Y" — not "checked X, it was quiet."
108
- Every memory must answer: could a future agent with zero context
109
- read this and know exactly what to do?
110
-
111
- Use \`memento_remember\` when you learn something worth keeping.
112
- Use \`memento_skip_add\` for things to explicitly not re-investigate.
113
- Use \`memento_recall\` to search memories by keyword or tag.
114
- Hooks run automatically — recall before responses, distillation
115
- before compaction. Trust the hooks. Focus on writing good memories.`;
116
-
117
- // ---------------------------------------------------------------------------
118
- // Headless agent integration
119
- // ---------------------------------------------------------------------------
120
-
121
- const HEADLESS_CMDS = {
122
- "claude-code": (prompt) => ["claude", "-p", "--dangerously-skip-permissions", prompt],
123
- "gemini": (prompt) => ["gemini", prompt],
124
- };
125
-
126
- function buildIntegrationPrompt(blob) {
127
- return [
128
- "The following instructions were generated by memento-mcp init for this project.",
129
- "Add them to the file where you store persistent behavioral instructions",
130
- "(e.g. CLAUDE.md for Claude Code). If the file exists, read it first and",
131
- "integrate the new section without removing existing content. If a section",
132
- "with the same heading already exists, replace it. If no instructions file",
133
- "exists yet, create one.",
134
- "",
135
- "--- INSTRUCTIONS ---",
136
- blob,
137
- "--- END ---",
138
- ].join("\n");
139
- }
140
-
141
- function runAgentHeadless(agentKey, prompt) {
142
- const cmdBuilder = HEADLESS_CMDS[agentKey];
143
- if (!cmdBuilder) return null;
144
- const [cmd, ...args] = cmdBuilder(prompt);
145
- try {
146
- const result = execFileSync(cmd, args, {
147
- cwd: process.cwd(),
148
- encoding: "utf8",
149
- stdio: ["pipe", "pipe", "inherit"],
150
- timeout: 60000,
151
- });
152
- return result;
153
- } catch {
154
- return null;
155
- }
156
- }
157
-
158
95
  // ---------------------------------------------------------------------------
159
96
  // CLI flag parsing
160
97
  // ---------------------------------------------------------------------------
@@ -492,11 +429,9 @@ async function runInit(flags = {}) {
492
429
  writeJsonFile(configPath, config);
493
430
  created.push(".memento.json");
494
431
 
495
- // 7. Copy hook scripts — gated on any hook-supporting agent
496
- const anyHookEnabled =
497
- enableUserPrompt || enableStop || enablePreCompact || enableSessionStart;
498
-
499
- 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) {
500
435
  const pkgScriptsDir = path.resolve(__dirname, "..", "scripts");
501
436
  const localScriptsDir = path.join(cwd, ".memento", "scripts");
502
437
  if (!fs.existsSync(localScriptsDir))
@@ -504,6 +439,7 @@ async function runInit(flags = {}) {
504
439
 
505
440
  const scriptFiles = [
506
441
  "hook-toast.sh",
442
+ "memento-instructions.sh",
507
443
  enableUserPrompt && "memento-userprompt-recall.sh",
508
444
  enableStop && "memento-stop-recall.sh",
509
445
  enablePreCompact && "memento-precompact-distill.sh",
@@ -526,6 +462,7 @@ async function runInit(flags = {}) {
526
462
  fs.writeFileSync(versionPath, pkgVersion + "\n");
527
463
 
528
464
  // Hook script commands (absolute paths)
465
+ const instructionsCmd = path.join(localScriptsDir, "memento-instructions.sh");
529
466
  const recallCmd = path.join(localScriptsDir, "memento-userprompt-recall.sh");
530
467
  const stopCmd = path.join(localScriptsDir, "memento-stop-recall.sh");
531
468
  const precompactCmd = path.join(localScriptsDir, "memento-precompact-distill.sh");
@@ -536,6 +473,8 @@ async function runInit(flags = {}) {
536
473
  const settingsPath = path.join(cwd, ".claude", "settings.local.json");
537
474
  const settings = readJsonFile(settingsPath) || {};
538
475
  let changed = false;
476
+ // Instructions hook always registered (not gated by enableSessionStart)
477
+ changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
539
478
  if (enableUserPrompt) changed = ensureHook(settings, "UserPromptSubmit", recallCmd, 5000) || changed;
540
479
  if (enableStop) changed = ensureHook(settings, "Stop", stopCmd, 5000) || changed;
541
480
  if (enablePreCompact) changed = ensureHook(settings, "PreCompact", precompactCmd, 30000) || changed;
@@ -551,6 +490,8 @@ async function runInit(flags = {}) {
551
490
  const settingsPath = path.join(cwd, ".gemini", "settings.json");
552
491
  const settings = readJsonFile(settingsPath) || {};
553
492
  let changed = false;
493
+ // Instructions hook always registered
494
+ changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
554
495
  if (enableUserPrompt) changed = ensureHook(settings, "BeforeAgent", recallCmd, 5000) || changed;
555
496
  if (enableStop) changed = ensureHook(settings, "SessionEnd", stopCmd, 5000) || changed;
556
497
  if (enablePreCompact) changed = ensureHook(settings, "PreCompress", precompactCmd, 30000) || changed;
@@ -610,57 +551,6 @@ async function runInit(flags = {}) {
610
551
  console.log(` Non-interactive equivalent:\n ${parts.join(" ")}\n`);
611
552
  }
612
553
 
613
- // 12. Auto-integrate agent instructions
614
- const primaryAgent = selectedAgents[0];
615
- const prompt = buildIntegrationPrompt(INSTRUCTIONS_BLOB);
616
- const cmdParts = HEADLESS_CMDS[primaryAgent]?.(prompt);
617
-
618
- if (nonInteractive) {
619
- // Auto-run headless integration, no prompt
620
- if (cmdParts) {
621
- console.log(` Integrating instructions via ${AGENTS[primaryAgent].name}...`);
622
- const result = runAgentHeadless(primaryAgent, prompt);
623
- if (result !== null) {
624
- console.log(result);
625
- } else {
626
- // Fallback: print the blob
627
- console.log(" Agent integration failed — paste these instructions manually:\n");
628
- printInstructionsFallback(selectedAgents);
629
- }
630
- } else {
631
- printInstructionsFallback(selectedAgents);
632
- }
633
- } else {
634
- // Interactive: ask with explicit command shown
635
- if (cmdParts) {
636
- const [cmd, ...args] = cmdParts;
637
- const flagArgs = args.slice(0, -1).join(" ");
638
- const displayCmd = `${cmd} ${flagArgs} <prompt>`;
639
- const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
640
- console.log("─".repeat(60));
641
- const integrate = await askYesNo(
642
- rl2,
643
- `\n Auto-integrate instructions into your project?\n This will run: ${displayCmd}\n\n ⚠ This uses --dangerously-skip-permissions so the agent can\n write to CLAUDE.md without prompting. If you prefer, decline\n and we'll print the instructions for you to add manually.\n\n Proceed?`,
644
- true,
645
- );
646
- rl2.close();
647
-
648
- if (integrate) {
649
- console.log(`\n Running ${AGENTS[primaryAgent].name}...`);
650
- const result = runAgentHeadless(primaryAgent, prompt);
651
- if (result !== null) {
652
- console.log(result);
653
- } else {
654
- console.log(" Agent integration failed — paste these instructions manually:\n");
655
- printInstructionsFallback(selectedAgents);
656
- }
657
- } else {
658
- printInstructionsFallback(selectedAgents);
659
- }
660
- } else {
661
- printInstructionsFallback(selectedAgents);
662
- }
663
- }
664
554
  }
665
555
 
666
556
  // ---------------------------------------------------------------------------
@@ -707,10 +597,11 @@ async function runUpdate() {
707
597
  const versionPath = path.join(cwd, ".memento", "version");
708
598
  fs.writeFileSync(versionPath, pkgVersion + "\n");
709
599
 
710
- // Ensure SessionStart hook is registered for agents that support hooks
600
+ // Ensure SessionStart hooks are registered for agents that support hooks
711
601
  // Detect by config agents field or directory presence (older configs may lack agents)
712
602
  const config = readJsonFile(configPath) || {};
713
603
  const agents = config.agents || [];
604
+ const instructionsCmd = path.join(localScriptsDir, "memento-instructions.sh");
714
605
  const sessionStartCmd = path.join(localScriptsDir, "memento-sessionstart-identity.sh");
715
606
  const registeredHooks = [];
716
607
 
@@ -720,7 +611,9 @@ async function runUpdate() {
720
611
  if (hasClaude) {
721
612
  const settingsPath = path.join(cwd, ".claude", "settings.local.json");
722
613
  const settings = readJsonFile(settingsPath) || {};
723
- if (ensureHook(settings, "SessionStart", sessionStartCmd, 10000)) {
614
+ let changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000);
615
+ changed = ensureHook(settings, "SessionStart", sessionStartCmd, 10000) || changed;
616
+ if (changed) {
724
617
  writeJsonFile(settingsPath, settings);
725
618
  registeredHooks.push("Claude Code → .claude/settings.local.json");
726
619
  }
@@ -732,7 +625,9 @@ async function runUpdate() {
732
625
  if (hasGemini) {
733
626
  const settingsPath = path.join(cwd, ".gemini", "settings.json");
734
627
  const settings = readJsonFile(settingsPath) || {};
735
- if (ensureHook(settings, "SessionStart", sessionStartCmd, 10000)) {
628
+ let changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000);
629
+ changed = ensureHook(settings, "SessionStart", sessionStartCmd, 10000) || changed;
630
+ if (changed) {
736
631
  writeJsonFile(settingsPath, settings);
737
632
  registeredHooks.push("Gemini CLI → .gemini/settings.json");
738
633
  }
@@ -753,26 +648,6 @@ async function runUpdate() {
753
648
  console.log(" Restart your agent session to pick up changes.\n");
754
649
  }
755
650
 
756
- function printInstructionsFallback(selectedAgents) {
757
- const hasNonClaude = selectedAgents.some((k) => k !== "claude-code");
758
- const docTarget = hasNonClaude
759
- ? "your CLAUDE.md, AGENTS.md, or equivalent"
760
- : "your CLAUDE.md";
761
-
762
- console.log("─".repeat(60));
763
- console.log(`
764
- One more step: paste the following into ${docTarget},
765
- or hand it to your agent and ask it to add it. This teaches
766
- your agent the memory discipline Memento expects.
767
-
768
- ── paste below this line ──────────────────────────────
769
-
770
- ${INSTRUCTIONS_BLOB}
771
-
772
- ── paste above this line ──────────────────────────────
773
- `);
774
- }
775
-
776
651
  // ---------------------------------------------------------------------------
777
652
  // Entrypoint — only run when this module is the entry point (not imported)
778
653
  // ---------------------------------------------------------------------------