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.
- package/bin/cf-memory-mcp.js +75 -1
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -2487,7 +2487,16 @@ class CFMemoryMCP {
|
|
|
2487
2487
|
* detection fails.
|
|
2488
2488
|
*/
|
|
2489
2489
|
getRepoMetadata() {
|
|
2490
|
-
|
|
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.
|
|
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": {
|