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 +1 -1
- package/scripts/memento-instructions.sh +55 -0
- package/src/cli.js +17 -142
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
|
@@ -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
|
|
496
|
-
|
|
497
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
// ---------------------------------------------------------------------------
|