cf-memory-mcp 3.40.0 → 3.42.0

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.
@@ -2487,7 +2487,16 @@ class CFMemoryMCP {
2487
2487
  * detection fails.
2488
2488
  */
2489
2489
  getRepoMetadata() {
2490
- if (this._repoMetaCache) return this._repoMetaCache;
2490
+ // 60s TTL: long enough to amortize git invocations across a flurry
2491
+ // of tool calls, short enough that a branch switch mid-session
2492
+ // gets picked up within a minute. Without the TTL, the bridge
2493
+ // would keep reporting the original branch for the whole process
2494
+ // lifetime even after `git checkout other-branch`.
2495
+ const TTL_MS = 60_000;
2496
+ if (this._repoMetaCache && this._repoMetaCacheTime &&
2497
+ (Date.now() - this._repoMetaCacheTime) < TTL_MS) {
2498
+ return this._repoMetaCache;
2499
+ }
2491
2500
  const result = {};
2492
2501
  try {
2493
2502
  const root = process.env.CF_MEMORY_WATCH_PATH || process.cwd();
@@ -2509,6 +2518,7 @@ class CFMemoryMCP {
2509
2518
  if (branch) result.branch = branch;
2510
2519
  } catch (_) { /* not a git repo, detached HEAD, or no branch — leave undefined */ }
2511
2520
  this._repoMetaCache = result;
2521
+ this._repoMetaCacheTime = Date.now();
2512
2522
  _mcpTrace('REPO_META', `repo_path=${result.repo_path||'?'} branch=${result.branch||'?'}`);
2513
2523
  return result;
2514
2524
  }
@@ -3880,6 +3890,42 @@ For more information, visit: https://github.com/johnlam90/cf-memory-mcp
3880
3890
  process.exit(0);
3881
3891
  }
3882
3892
 
3893
+ /**
3894
+ * Pipe a string to the platform clipboard. Returns true on success.
3895
+ * Detects the right command per platform; falls back gracefully when
3896
+ * none are installed. Bounded by a 2s timeout so a hung clipboard
3897
+ * helper can't lock the CLI.
3898
+ */
3899
+ function copyToClipboard(text) {
3900
+ const { spawnSync } = require('child_process');
3901
+ let cmd, args;
3902
+ if (process.platform === 'darwin') {
3903
+ cmd = 'pbcopy'; args = [];
3904
+ } else if (process.platform === 'win32') {
3905
+ cmd = 'clip'; args = [];
3906
+ } else {
3907
+ // Linux: try xclip first, then wl-copy (Wayland).
3908
+ const which = spawnSync('which', ['xclip']);
3909
+ if (which.status === 0) {
3910
+ cmd = 'xclip'; args = ['-selection', 'clipboard'];
3911
+ } else {
3912
+ const which2 = spawnSync('which', ['wl-copy']);
3913
+ if (which2.status === 0) {
3914
+ cmd = 'wl-copy'; args = [];
3915
+ } else {
3916
+ return { ok: false, error: 'install xclip or wl-copy to use --copy' };
3917
+ }
3918
+ }
3919
+ }
3920
+ try {
3921
+ const res = spawnSync(cmd, args, { input: text, timeout: 2000 });
3922
+ if (res.status === 0) return { ok: true };
3923
+ return { ok: false, error: `${cmd} exited ${res.status}: ${res.stderr?.toString().slice(0, 200) || ''}` };
3924
+ } catch (err) {
3925
+ return { ok: false, error: `${cmd} failed: ${err.message}` };
3926
+ }
3927
+ }
3928
+
3883
3929
  // Parse positional + flag args for CLI subcommands. Returns
3884
3930
  // { positional: string[], flags: { json, limit, md_path, older_than_days, status, repo_path, yes } }.
3885
3931
  function parseCliArgs(rest) {
@@ -3914,6 +3960,10 @@ function parseCliArgs(rest) {
3914
3960
  flags.chain = true;
3915
3961
  } else if (a === '--validate') {
3916
3962
  flags.validate = true;
3963
+ } else if (a === '--raw') {
3964
+ flags.raw = true;
3965
+ } else if (a === '--copy') {
3966
+ flags.copy = true;
3917
3967
  } else if (a === '--older-than') {
3918
3968
  // Accept "7d" / "30d" / "12h" / raw number (days).
3919
3969
  const raw = rest[++i] || '';
@@ -4067,6 +4117,15 @@ async function runResumeCli() {
4067
4117
  process.exit(0);
4068
4118
  }
4069
4119
 
4120
+ // --raw: print the bare handoff JSON (no envelope metadata).
4121
+ // Useful for migrations, direct inspection, or piping to jq.
4122
+ if (flags.raw) {
4123
+ const handoff = payload.resume_handoff?.handoff;
4124
+ if (!handoff) process.exit(3);
4125
+ process.stdout.write(JSON.stringify(handoff, null, 2) + '\n');
4126
+ process.exit(0);
4127
+ }
4128
+
4070
4129
  // --chain: walk parent_session_id back through the thread history.
4071
4130
  // Bounded at 20 iterations to avoid an infinite loop on malformed
4072
4131
  // data. Prints each handoff as "<id> [age] status — goal".
@@ -4184,6 +4243,19 @@ async function runResumeCli() {
4184
4243
  }
4185
4244
  }
4186
4245
 
4246
+ // --copy: pipe rendered markdown to platform clipboard. Quick
4247
+ // paste into another chat client or doc tool.
4248
+ if (found && flags.copy && payload.resume_prompt) {
4249
+ const result = copyToClipboard(payload.resume_prompt);
4250
+ if (result.ok) {
4251
+ process.stdout.write(`Copied ${payload.resume_prompt.length} chars to clipboard.\n`);
4252
+ process.exit(0);
4253
+ } else {
4254
+ process.stderr.write(`Failed to copy to clipboard: ${result.error}\n`);
4255
+ process.exit(1);
4256
+ }
4257
+ }
4258
+
4187
4259
  if (flags.json) {
4188
4260
  process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
4189
4261
  process.exit(found ? 0 : 3);
@@ -4658,6 +4730,7 @@ const PER_COMMAND_HELP = {
4658
4730
  Print the prior resume handoff (markdown by default).
4659
4731
  <session-id-prefix> Optional: pick a specific session (>=8 char prefix or full UUID).
4660
4732
  --md <path> Write the markdown to a file instead of stdout.
4733
+ --copy Pipe the markdown to the platform clipboard (pbcopy/xclip/wl-copy/clip).
4661
4734
  Extract flags (pick one; each exits 3 if the section is empty):
4662
4735
  --next-only First next_step only (for shell prompts).
4663
4736
  --next-steps All next_steps, numbered.
@@ -4667,6 +4740,7 @@ const PER_COMMAND_HELP = {
4667
4740
  --blockers-only open blockers, one per line.
4668
4741
  --chain Walk parent_session_id back; show the thread history.
4669
4742
  --validate Check that files_touched + code_anchors still exist locally.
4743
+ --raw Print just the raw handoff JSON (no envelope metadata).
4670
4744
  --json, -j Full bootstrap payload as JSON.
4671
4745
  Exit codes: 0 = found, 3 = no handoff / no data, 4 = --validate found missing files.`,
4672
4746
  list: `cf-memory-mcp list [--status S] [--since ISO] [--repo PATH] [--limit N] [--json]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cf-memory-mcp",
3
- "version": "3.40.0",
3
+ "version": "3.42.0",
4
4
  "description": "Cloudflare-hosted MCP server for code indexing, retrieval, and assistant memory with a direct remote MCP endpoint and local stdio bridge.",
5
5
  "main": "bin/cf-memory-mcp.js",
6
6
  "bin": {