memento-mcp 0.3.11 → 0.3.13

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.11",
3
+ "version": "0.3.13",
4
4
  "mcpName": "io.github.myrakrusemark/memento-protocol",
5
5
  "description": "The Memento Protocol — persistent memory for AI agents",
6
6
  "type": "module",
@@ -73,7 +73,7 @@ if [ -f "$SCRIPT_DIR/../.env" ]; then
73
73
  fi
74
74
 
75
75
  MEMENTO_API="${MEMENTO_API_URL:-https://memento-api.myrakrusemark.workers.dev}"
76
- MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-protocol/.env or .memento.json}"
76
+ MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-mcp/.env or .memento.json}"
77
77
  MEMENTO_WS="${MEMENTO_WORKSPACE:-default}"
78
78
 
79
79
  # Parse transcript to readable text (use fathom's parser if available, else raw)
@@ -69,7 +69,7 @@ if [ -f "$SCRIPT_DIR/../.env" ]; then
69
69
  fi
70
70
 
71
71
  MEMENTO_API="${MEMENTO_API_URL:-https://memento-api.myrakrusemark.workers.dev}"
72
- MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-protocol/.env or .memento.json}"
72
+ MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-mcp/.env or .memento.json}"
73
73
  MEMENTO_WS="${MEMENTO_WORKSPACE:-default}"
74
74
 
75
75
  AUTH_HEADER="Authorization: Bearer $MEMENTO_KEY"
@@ -54,7 +54,7 @@ if [ -f "$SCRIPT_DIR/../.env" ]; then
54
54
  fi
55
55
 
56
56
  MEMENTO_API="${MEMENTO_API_URL:-https://memento-api.myrakrusemark.workers.dev}"
57
- MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-protocol/.env or .memento.json}"
57
+ MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-mcp/.env or .memento.json}"
58
58
  MEMENTO_WS="${MEMENTO_WORKSPACE:-default}"
59
59
 
60
60
  INPUT=$(cat)
@@ -96,8 +96,8 @@ try:
96
96
 
97
97
  memories = data.get('memories', {}).get('matches', [])
98
98
  if memories:
99
- for m in memories[:${RECALL_LIMIT:-5}]:
100
- content = m['content'][:${RECALL_MAX_LENGTH:-120}]
99
+ for m in memories[:${RECALL_LIMIT:-7}]:
100
+ content = m['content']
101
101
  t = abbrev.get(m['type'], m['type'])
102
102
  lines.append(f' 🔹 {content} [{m[\"id\"]} {t}]')
103
103
  count += 1
@@ -55,7 +55,7 @@ if [ -f "$SCRIPT_DIR/../.env" ]; then
55
55
  fi
56
56
 
57
57
  MEMENTO_API="${MEMENTO_API_URL:-https://memento-api.myrakrusemark.workers.dev}"
58
- MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-protocol/.env or .memento.json}"
58
+ MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-mcp/.env or .memento.json}"
59
59
  MEMENTO_WS="${MEMENTO_WORKSPACE:-default}"
60
60
 
61
61
  INPUT=$(cat)
@@ -88,8 +88,8 @@ try:
88
88
 
89
89
  memories = data.get('memories', {}).get('matches', [])
90
90
  if memories:
91
- for m in memories[:${RECALL_LIMIT:-5}]:
92
- content = m['content'][:${RECALL_MAX_LENGTH:-120}]
91
+ for m in memories[:${RECALL_LIMIT:-7}]:
92
+ content = m['content']
93
93
  t = abbrev.get(m['type'], m['type'])
94
94
  lines.append(f' 🔹 {content} [{m[\"id\"]} {t}]')
95
95
  count += 1
package/src/cli.js CHANGED
@@ -120,9 +120,7 @@ before compaction. Trust the hooks. Focus on writing good memories.`;
120
120
 
121
121
  const HEADLESS_CMDS = {
122
122
  "claude-code": (prompt) => ["claude", "-p", "--dangerously-skip-permissions", prompt],
123
- "codex": (prompt) => ["codex", "exec", prompt],
124
123
  "gemini": (prompt) => ["gemini", prompt],
125
- "opencode": (prompt) => ["opencode", "run", prompt],
126
124
  };
127
125
 
128
126
  function buildIntegrationPrompt(blob) {
@@ -162,13 +160,16 @@ function runAgentHeadless(agentKey, prompt) {
162
160
  // ---------------------------------------------------------------------------
163
161
 
164
162
  function parseFlags(argv) {
165
- const flags = { nonInteractive: false, apiKey: null };
163
+ const flags = { nonInteractive: false, apiKey: null, agent: null };
166
164
  for (let i = 0; i < argv.length; i++) {
167
165
  if (argv[i] === "-y" || argv[i] === "--yes") {
168
166
  flags.nonInteractive = true;
169
167
  } else if (argv[i] === "--api-key" && argv[i + 1]) {
170
168
  flags.apiKey = argv[i + 1];
171
169
  i++;
170
+ } else if (argv[i] === "--agent" && argv[i + 1]) {
171
+ flags.agent = argv[i + 1];
172
+ i++;
172
173
  }
173
174
  }
174
175
  // Also check environment variable
@@ -244,29 +245,6 @@ function writeMcpJson(cwd) {
244
245
  return ".mcp.json";
245
246
  }
246
247
 
247
- function writeCodexToml(cwd) {
248
- const dir = path.join(cwd, ".codex");
249
- fs.mkdirSync(dir, { recursive: true });
250
- const filePath = path.join(dir, "config.toml");
251
-
252
- let content = "";
253
- try {
254
- content = fs.readFileSync(filePath, "utf8");
255
- } catch {
256
- /* file doesn't exist */
257
- }
258
-
259
- // Skip if memento section already exists
260
- if (/\[mcp_servers\.memento\]/.test(content)) {
261
- return ".codex/config.toml (already configured)";
262
- }
263
-
264
- const section = `\n[mcp_servers.memento]\ncommand = "npx"\nargs = ["-y", "memento-mcp"]\n`;
265
- const separator = content && !content.endsWith("\n") ? "\n" : "";
266
- fs.writeFileSync(filePath, content + separator + section);
267
- return ".codex/config.toml";
268
- }
269
-
270
248
  function writeGeminiJson(cwd) {
271
249
  const dir = path.join(cwd, ".gemini");
272
250
  fs.mkdirSync(dir, { recursive: true });
@@ -277,22 +255,6 @@ function writeGeminiJson(cwd) {
277
255
  return ".gemini/settings.json";
278
256
  }
279
257
 
280
- function writeOpencodeJson(cwd) {
281
- const filePath = path.join(cwd, "opencode.json");
282
- const existing = readJsonFile(filePath) || {};
283
- deepMerge(existing, {
284
- mcp: {
285
- memento: {
286
- type: "local",
287
- command: ["npx", "-y", "memento-mcp"],
288
- enabled: true,
289
- },
290
- },
291
- });
292
- writeJsonFile(filePath, existing);
293
- return "opencode.json";
294
- }
295
-
296
258
  const AGENTS = {
297
259
  "claude-code": {
298
260
  name: "Claude Code",
@@ -301,38 +263,31 @@ const AGENTS = {
301
263
  hasHooks: true,
302
264
  nextSteps: "Restart Claude Code to activate.",
303
265
  },
304
- codex: {
305
- name: "OpenAI Codex",
306
- detect: (cwd) => fs.existsSync(path.join(cwd, ".codex")),
307
- configWriter: writeCodexToml,
308
- hasHooks: false,
309
- nextSteps: "Run `codex` in this directory — memento tools load automatically.",
310
- },
311
266
  gemini: {
312
267
  name: "Gemini CLI",
313
268
  detect: (cwd) => fs.existsSync(path.join(cwd, ".gemini")),
314
269
  configWriter: writeGeminiJson,
315
- hasHooks: false,
270
+ hasHooks: true,
316
271
  nextSteps: "Run `gemini` in this directory — memento tools load automatically.",
317
272
  },
318
- opencode: {
319
- name: "OpenCode",
320
- detect: (cwd) => fs.existsSync(path.join(cwd, "opencode.json")),
321
- configWriter: writeOpencodeJson,
273
+ manual: {
274
+ name: "I'll set up my agent myself",
275
+ detect: () => false,
276
+ configWriter: () => "(skipped — manual setup)",
322
277
  hasHooks: false,
323
- nextSteps: "Run `opencode` in this directory memento tools load automatically.",
278
+ nextSteps: "Point your agent's MCP config at: npx -y memento-mcp",
324
279
  },
325
280
  };
326
281
 
327
282
  // Exported for testing
328
- export { AGENTS, writeMcpJson, writeCodexToml, writeGeminiJson, writeOpencodeJson };
283
+ export { AGENTS, writeMcpJson, writeGeminiJson };
329
284
 
330
285
  // ---------------------------------------------------------------------------
331
286
  // CLI
332
287
  // ---------------------------------------------------------------------------
333
288
 
334
289
  async function runInit(flags = {}) {
335
- const { nonInteractive = false, apiKey: flagApiKey = null } = flags;
290
+ const { nonInteractive = false, apiKey: flagApiKey = null, agent: flagAgent = null } = flags;
336
291
  const cwd = process.cwd();
337
292
  const projectName = path.basename(cwd);
338
293
 
@@ -420,16 +375,25 @@ async function runInit(flags = {}) {
420
375
 
421
376
  let selectedAgents;
422
377
  if (nonInteractive) {
423
- // Auto-detect: use first detected agent, or default to claude-code
424
- selectedAgents = detected.length > 0 ? [detected[0]] : ["claude-code"];
425
- console.log(` Agent: ${AGENTS[selectedAgents[0]].name} (auto-detected)`);
378
+ if (flagAgent) {
379
+ // Validate --agent value
380
+ if (!AGENTS[flagAgent]) {
381
+ const valid = Object.keys(AGENTS).join(", ");
382
+ console.error(` Error: unknown agent "${flagAgent}". Valid agents: ${valid}`);
383
+ process.exit(1);
384
+ }
385
+ selectedAgents = [flagAgent];
386
+ console.log(` Agent: ${AGENTS[flagAgent].name} (--agent flag)`);
387
+ } else {
388
+ // Auto-detect: use first detected agent, or default to claude-code
389
+ selectedAgents = detected.length > 0 ? [detected[0]] : ["claude-code"];
390
+ console.log(` Agent: ${AGENTS[selectedAgents[0]].name} (auto-detected)`);
391
+ }
426
392
  } else {
427
393
  console.log("\nDetected agents:");
428
394
  const markers = {
429
395
  "claude-code": ".claude/",
430
- codex: ".codex/",
431
396
  gemini: ".gemini/",
432
- opencode: "opencode.json",
433
397
  };
434
398
  for (const key of agentKeys) {
435
399
  const agent = AGENTS[key];
@@ -464,8 +428,6 @@ async function runInit(flags = {}) {
464
428
  }
465
429
 
466
430
  const hasClaude = selectedAgents.includes("claude-code");
467
-
468
- // 5. Hooks — if any hook-supporting agent is selected (Claude Code, Gemini CLI)
469
431
  const hasGemini = selectedAgents.includes("gemini");
470
432
  const hasHookAgent = hasClaude || hasGemini;
471
433
 
@@ -531,7 +493,6 @@ async function runInit(flags = {}) {
531
493
  created.push(".memento.json");
532
494
 
533
495
  // 7. Copy hook scripts — gated on any hook-supporting agent
534
- const hasCodex = selectedAgents.includes("codex");
535
496
  const anyHookEnabled =
536
497
  enableUserPrompt || enableStop || enablePreCompact || enableSessionStart;
537
498
 
@@ -549,9 +510,6 @@ async function runInit(flags = {}) {
549
510
  enableSessionStart && "memento-sessionstart-identity.sh",
550
511
  ].filter(Boolean);
551
512
 
552
- // Also copy Codex notify script if Codex is selected
553
- if (hasCodex) scriptFiles.push("memento-codex-notify.sh");
554
-
555
513
  for (const name of scriptFiles) {
556
514
  const src = path.join(pkgScriptsDir, name);
557
515
  if (!fs.existsSync(src)) continue; // skip if script doesn't exist yet
@@ -604,31 +562,7 @@ async function runInit(flags = {}) {
604
562
  }
605
563
  }
606
564
 
607
- // 8c. Codex CLI notify — .codex/config.toml (fire-and-forget, post-turn memory storage)
608
- if (hasCodex) {
609
- const pkgScriptsDir = path.resolve(__dirname, "..", "scripts");
610
- const localScriptsDir = path.join(cwd, ".memento", "scripts");
611
- // Ensure the notify script is copied (may not have been copied above if no hook agent)
612
- const notifySrc = path.join(pkgScriptsDir, "memento-codex-notify.sh");
613
- const notifyDest = path.join(localScriptsDir, "memento-codex-notify.sh");
614
- if (fs.existsSync(notifySrc) && !fs.existsSync(notifyDest)) {
615
- fs.mkdirSync(localScriptsDir, { recursive: true });
616
- fs.copyFileSync(notifySrc, notifyDest);
617
- fs.chmodSync(notifyDest, 0o755);
618
- }
619
- const notifyScript = notifyDest;
620
- const codexTomlPath = path.join(cwd, ".codex", "config.toml");
621
- let tomlContent = "";
622
- try { tomlContent = fs.readFileSync(codexTomlPath, "utf-8"); } catch { /* doesn't exist yet */ }
623
- if (!tomlContent.includes("notify")) {
624
- const notifyLine = `\nnotify = ["bash", "${notifyScript}"]\n`;
625
- const separator = tomlContent && !tomlContent.endsWith("\n") ? "\n" : "";
626
- fs.writeFileSync(codexTomlPath, tomlContent + separator + notifyLine);
627
- created.push(".codex/config.toml (notify)");
628
- }
629
- }
630
-
631
- // 9. Per-agent config files
565
+ // 8c. Per-agent config files
632
566
  for (const agentKey of selectedAgents) {
633
567
  const agent = AGENTS[agentKey];
634
568
  const result = agent.configWriter(cwd);
@@ -641,16 +575,15 @@ async function runInit(flags = {}) {
641
575
  if (appendToGitignore(cwd, ".memento/scripts/")) gitignoreUpdated = true;
642
576
  if (gitignoreUpdated) created.push(".gitignore (updated)");
643
577
 
644
- // 11. Summary
578
+ // 10. Summary
645
579
  const labels = {
646
580
  ".memento.json": "workspace config + credentials",
647
581
  ".memento/scripts/": "hook scripts (recall + distillation)",
648
582
  ".claude/settings.local.json": "hooks registered with Claude Code",
649
583
  ".mcp.json": "MCP server registered (Claude Code)",
650
- ".codex/config.toml": "MCP server registered (Codex)",
651
- ".codex/config.toml (already configured)": "MCP server (Codex, skipped)",
652
584
  ".gemini/settings.json": "MCP server registered (Gemini CLI)",
653
- "opencode.json": "MCP server registered (OpenCode)",
585
+ ".gemini/settings.json (hooks)": "hooks registered with Gemini CLI",
586
+ "(skipped — manual setup)": "MCP config skipped (manual setup)",
654
587
  ".gitignore (updated)": "credentials excluded from git",
655
588
  };
656
589
  const colWidth = Math.max(...created.map((f) => f.length)) + 2;
@@ -669,6 +602,14 @@ async function runInit(flags = {}) {
669
602
  }
670
603
  console.log(" Your agent will wake up remembering.\n");
671
604
 
605
+ // Show non-interactive equivalent
606
+ if (!nonInteractive) {
607
+ const parts = ["npx memento-mcp init -y"];
608
+ if (apiKey) parts.push(`--api-key ${apiKey}`);
609
+ parts.push(`--agent ${selectedAgents[0]}`);
610
+ console.log(` Non-interactive equivalent:\n ${parts.join(" ")}\n`);
611
+ }
612
+
672
613
  // 12. Auto-integrate agent instructions
673
614
  const primaryAgent = selectedAgents[0];
674
615
  const prompt = buildIntegrationPrompt(INSTRUCTIONS_BLOB);
@@ -797,23 +738,6 @@ async function runUpdate() {
797
738
  }
798
739
  }
799
740
 
800
- // Codex CLI — ensure notify is configured
801
- const hasCodex = agents.includes("codex")
802
- || fs.existsSync(path.join(cwd, ".codex"));
803
- if (hasCodex) {
804
- const notifyScript = path.join(localScriptsDir, "memento-codex-notify.sh");
805
- const codexTomlPath = path.join(cwd, ".codex", "config.toml");
806
- let tomlContent = "";
807
- try { tomlContent = fs.readFileSync(codexTomlPath, "utf-8"); } catch { /* doesn't exist yet */ }
808
- if (!tomlContent.includes("notify") && fs.existsSync(notifyScript)) {
809
- const notifyLine = `\nnotify = ["bash", "${notifyScript}"]\n`;
810
- const separator = tomlContent && !tomlContent.endsWith("\n") ? "\n" : "";
811
- fs.mkdirSync(path.dirname(codexTomlPath), { recursive: true });
812
- fs.writeFileSync(codexTomlPath, tomlContent + separator + notifyLine);
813
- registeredHooks.push("Codex CLI → .codex/config.toml (notify)");
814
- }
815
- }
816
-
817
741
  console.log(`\n ✓ Memento hooks updated to v${pkgVersion}\n`);
818
742
  console.log(" Updated scripts:");
819
743
  for (const name of updated) {
@@ -882,16 +806,22 @@ if (isMain) {
882
806
  Memento Protocol CLI
883
807
 
884
808
  Usage:
885
- npx memento-mcp init Set up Memento in the current project
886
- npx memento-mcp init -y Non-interactive setup (uses defaults)
887
- npx memento-mcp init --api-key KEY Provide API key (skips signup)
888
- npx memento-mcp update Update hook scripts to latest version
889
- npx memento-mcp Start the MCP server (used by .mcp.json)
890
-
891
- The -y flag enables fully non-interactive setup for CI/scripting.
892
- Combine with --api-key to skip auto-signup.
893
-
894
- Supports Claude Code, Codex, Gemini CLI, and OpenCode.
809
+ npx memento-mcp init Set up Memento in the current project
810
+ npx memento-mcp init -y Non-interactive setup (uses defaults)
811
+ npx memento-mcp init -y --agent gemini Non-interactive with specific agent
812
+ npx memento-mcp init --api-key KEY Provide API key (skips signup)
813
+ npx memento-mcp update Update hook scripts to latest version
814
+ npx memento-mcp Start the MCP server (used by .mcp.json)
815
+
816
+ Flags:
817
+ -y, --yes Non-interactive mode (uses defaults, for CI/scripting)
818
+ --api-key KEY Provide API key (skips signup prompt)
819
+ --agent AGENT Select agent: claude-code, gemini, or manual
820
+
821
+ The -y flag enables fully non-interactive setup. Combine with --agent
822
+ to select a specific agent (defaults to auto-detect, then claude-code).
823
+
824
+ Supports Claude Code, Gemini CLI, and manual setup for any agent.
895
825
  `);
896
826
  process.exit(1);
897
827
  }