cf-memory-mcp 3.51.0 → 3.53.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 +77 -27
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -4091,6 +4091,14 @@ function parseCliArgs(rest) {
|
|
|
4091
4091
|
flags.repo_path = rest[++i];
|
|
4092
4092
|
} else if (a.startsWith('--repo=')) {
|
|
4093
4093
|
flags.repo_path = a.slice('--repo='.length);
|
|
4094
|
+
} else if (a === '--project-id') {
|
|
4095
|
+
flags.project_id = rest[++i];
|
|
4096
|
+
} else if (a.startsWith('--project-id=')) {
|
|
4097
|
+
flags.project_id = a.slice('--project-id='.length);
|
|
4098
|
+
} else if (a === '--branch') {
|
|
4099
|
+
flags.branch = rest[++i];
|
|
4100
|
+
} else if (a.startsWith('--branch=')) {
|
|
4101
|
+
flags.branch = a.slice('--branch='.length);
|
|
4094
4102
|
} else if (a === '--since') {
|
|
4095
4103
|
flags.since = rest[++i];
|
|
4096
4104
|
} else if (a.startsWith('--since=')) {
|
|
@@ -4121,9 +4129,20 @@ async function runResumeCli() {
|
|
|
4121
4129
|
// Optional positional session_id argument.
|
|
4122
4130
|
const sessionArg = positional[0];
|
|
4123
4131
|
if (sessionArg) args.session_id_hint = sessionArg;
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4132
|
+
// Cross-laptop overrides: --repo and --project-id let users bypass
|
|
4133
|
+
// cwd-based matching when paths differ across machines. --project-id
|
|
4134
|
+
// is the most reliable cross-machine anchor since it survives
|
|
4135
|
+
// path differences.
|
|
4136
|
+
if (flags.repo_path) {
|
|
4137
|
+
args.repo_path = flags.repo_path;
|
|
4138
|
+
// Don't auto-fill project_id from the local cwd when --repo
|
|
4139
|
+
// overrides (would otherwise short-circuit to a wrong session).
|
|
4140
|
+
} else {
|
|
4141
|
+
const fake = { params: { name: 'retrieve_context', arguments: {} } };
|
|
4142
|
+
await server.maybeFillProjectId(fake);
|
|
4143
|
+
if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
|
|
4144
|
+
}
|
|
4145
|
+
if (flags.project_id) args.project_id = flags.project_id;
|
|
4127
4146
|
|
|
4128
4147
|
const response = await server.makeRequest({
|
|
4129
4148
|
jsonrpc: '2.0',
|
|
@@ -4700,6 +4719,8 @@ async function runListCli() {
|
|
|
4700
4719
|
await server.maybeFillProjectId(fake);
|
|
4701
4720
|
if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
|
|
4702
4721
|
}
|
|
4722
|
+
// --project-id explicit override (overrides any auto-fill above).
|
|
4723
|
+
if (flags.project_id) args.project_id = flags.project_id;
|
|
4703
4724
|
|
|
4704
4725
|
const response = await server.makeRequest({
|
|
4705
4726
|
jsonrpc: '2.0',
|
|
@@ -4879,6 +4900,9 @@ async function runHistoryCli() {
|
|
|
4879
4900
|
await server.maybeFillProjectId(fake);
|
|
4880
4901
|
if (fake.params.arguments.project_id) args.project_id = fake.params.arguments.project_id;
|
|
4881
4902
|
}
|
|
4903
|
+
// --project-id overrides cwd-derived project_id. Useful when
|
|
4904
|
+
// resuming a project you haven't indexed on this machine.
|
|
4905
|
+
if (flags.project_id) args.project_id = flags.project_id;
|
|
4882
4906
|
|
|
4883
4907
|
const response = await server.makeRequest({
|
|
4884
4908
|
jsonrpc: '2.0',
|
|
@@ -4888,7 +4912,13 @@ async function runHistoryCli() {
|
|
|
4888
4912
|
});
|
|
4889
4913
|
const text = response?.result?.content?.[0]?.text;
|
|
4890
4914
|
const payload = JSON.parse(text || '{}');
|
|
4891
|
-
|
|
4915
|
+
let all = (payload.recent_handoffs || []).slice();
|
|
4916
|
+
// Client-side branch filter: server doesn't filter recent_handoffs
|
|
4917
|
+
// by branch (only uses it for confidence scoring on the primary
|
|
4918
|
+
// match), so we apply the filter here.
|
|
4919
|
+
if (flags.branch) {
|
|
4920
|
+
all = all.filter(h => h.branch === flags.branch);
|
|
4921
|
+
}
|
|
4892
4922
|
// Chronological order (oldest first).
|
|
4893
4923
|
all.sort((a, b) => {
|
|
4894
4924
|
const ta = new Date(a.ended_at || a.started_at).getTime();
|
|
@@ -5282,6 +5312,8 @@ const PER_COMMAND_HELP = {
|
|
|
5282
5312
|
resume: `cf-memory-mcp resume [<session-id-prefix>] [--md path] [<extract-flag>] [--json]
|
|
5283
5313
|
Print the prior resume handoff (markdown by default).
|
|
5284
5314
|
<session-id-prefix> Optional: pick a specific session (>=8 char prefix or full UUID).
|
|
5315
|
+
--repo <path> Override cwd's repo (for cross-laptop or workspace-switch).
|
|
5316
|
+
--project-id <id> Override cwd's project_id (best for cross-laptop continuity).
|
|
5285
5317
|
--md <path> Write the markdown to a file instead of stdout.
|
|
5286
5318
|
--copy Pipe the markdown to the platform clipboard (pbcopy/xclip/wl-copy/clip).
|
|
5287
5319
|
--card Compact 2-3 line status card (for terminal status widgets).
|
|
@@ -5366,12 +5398,13 @@ const PER_COMMAND_HELP = {
|
|
|
5366
5398
|
Print all CF_MEMORY_* env vars the bridge reads, with their current
|
|
5367
5399
|
values + descriptions. Useful for discovering knobs.
|
|
5368
5400
|
--json, -j Emit JSON for scripts.`,
|
|
5369
|
-
history: `cf-memory-mcp history [--limit N] [--repo PATH] [--since ISO] [--json]
|
|
5401
|
+
history: `cf-memory-mcp history [--limit N] [--repo PATH] [--branch BR] [--since ISO] [--json]
|
|
5370
5402
|
Print all handoffs for the current cwd in chronological order (oldest
|
|
5371
5403
|
first). Unlike 'list' (status-ranked, default 5), this is a flat
|
|
5372
5404
|
timeline view.
|
|
5373
5405
|
--limit N Max number of handoffs (default 25, max 50).
|
|
5374
5406
|
--repo PATH Override the cwd's repo.
|
|
5407
|
+
--branch BR Filter to a specific branch.
|
|
5375
5408
|
--since ISO Lower bound on handoff timestamp.
|
|
5376
5409
|
--json, -j Emit JSON.`,
|
|
5377
5410
|
link: `cf-memory-mcp link <child-id-or-prefix> --parent <parent-id-or-prefix> [--json]
|
|
@@ -5448,6 +5481,7 @@ async function runDoctorCli() {
|
|
|
5448
5481
|
if (diskWritable) add('disk cache writable', true, path.dirname(cachePath));
|
|
5449
5482
|
|
|
5450
5483
|
// 4. Worker reachable?
|
|
5484
|
+
let handoffStatsForHint = null;
|
|
5451
5485
|
if (API_KEY) {
|
|
5452
5486
|
const t0 = Date.now();
|
|
5453
5487
|
let workerReachable = false;
|
|
@@ -5464,6 +5498,19 @@ async function runDoctorCli() {
|
|
|
5464
5498
|
workerReachable ? `${workerMs}ms` : `failed`,
|
|
5465
5499
|
`curl -I ${BASE_URL}/health # check the worker URL and your network`);
|
|
5466
5500
|
|
|
5501
|
+
// Pre-fetch handoff stats so the "resume handoff available" check
|
|
5502
|
+
// can suggest cross-laptop workflows when relevant.
|
|
5503
|
+
if (workerReachable) {
|
|
5504
|
+
try {
|
|
5505
|
+
const statsRes = await server.makeRequestOnce({
|
|
5506
|
+
jsonrpc: '2.0', id: `doctor-stats-pre-${Date.now()}`,
|
|
5507
|
+
method: 'tools/call', params: { name: 'get_stats', arguments: {} },
|
|
5508
|
+
});
|
|
5509
|
+
const statsText = statsRes?.result?.content?.[0]?.text;
|
|
5510
|
+
if (statsText) handoffStatsForHint = JSON.parse(statsText)?.handoffs || null;
|
|
5511
|
+
} catch (_) { /* skip */ }
|
|
5512
|
+
}
|
|
5513
|
+
|
|
5467
5514
|
// 5. Project indexed?
|
|
5468
5515
|
if (workerReachable) {
|
|
5469
5516
|
const fake = { params: { name: 'retrieve_context', arguments: {} } };
|
|
@@ -5485,33 +5532,36 @@ async function runDoctorCli() {
|
|
|
5485
5532
|
});
|
|
5486
5533
|
const probeText = probeRes?.result?.content?.[0]?.text;
|
|
5487
5534
|
const probePayload = JSON.parse(probeText || '{}');
|
|
5488
|
-
const
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5535
|
+
const handoff = probePayload.resume_handoff;
|
|
5536
|
+
const hasHandoff = !!handoff;
|
|
5537
|
+
// Cross-laptop / wrong-repo detection: the returned
|
|
5538
|
+
// handoff is for a DIFFERENT repo than cwd's. Most
|
|
5539
|
+
// commonly this is a tier-4 fallback or repo_path_prefix
|
|
5540
|
+
// hit. Either way the user is probably resuming the
|
|
5541
|
+
// "wrong" thread by accident.
|
|
5542
|
+
const handoffRepo = handoff?.handoff?.repo_path;
|
|
5543
|
+
const seemsCrossLaptop = hasHandoff
|
|
5544
|
+
&& handoffRepo
|
|
5545
|
+
&& handoffRepo !== meta.repo_path;
|
|
5546
|
+
let fixHint = 'cf-memory-mcp checkpoint "what you are working on" # or end_session({handoff:...}) in your MCP client';
|
|
5547
|
+
let ok = hasHandoff;
|
|
5548
|
+
let detail = hasHandoff
|
|
5549
|
+
? `${(handoff.session_id||'').slice(0,8)} (${handoff.handoff_age_minutes}m old)`
|
|
5550
|
+
: 'none for this context';
|
|
5551
|
+
if (seemsCrossLaptop) {
|
|
5552
|
+
// Soft warning — we matched, but cross-repo.
|
|
5553
|
+
ok = false;
|
|
5554
|
+
detail = `cross-repo match (cwd=${meta.repo_path}, handoff repo=${handoffRepo}); confidence ${handoff.match_confidence}`;
|
|
5555
|
+
fixHint = `Cross-laptop or path-mismatch case. Try: cf-memory-mcp resume --repo "${handoffRepo}" # or use --project-id from "cfm list"`;
|
|
5556
|
+
}
|
|
5557
|
+
add('resume handoff available', ok, detail, fixHint);
|
|
5494
5558
|
} catch (_) { /* skip */ }
|
|
5495
5559
|
}
|
|
5496
5560
|
}
|
|
5497
5561
|
}
|
|
5498
5562
|
|
|
5499
|
-
//
|
|
5500
|
-
|
|
5501
|
-
let handoffStats = null;
|
|
5502
|
-
if (API_KEY) {
|
|
5503
|
-
try {
|
|
5504
|
-
const statsRes = await server.makeRequestOnce({
|
|
5505
|
-
jsonrpc: '2.0', id: `doctor-stats-${Date.now()}`,
|
|
5506
|
-
method: 'tools/call', params: { name: 'get_stats', arguments: {} },
|
|
5507
|
-
});
|
|
5508
|
-
const statsText = statsRes?.result?.content?.[0]?.text;
|
|
5509
|
-
if (statsText) {
|
|
5510
|
-
const statsPayload = JSON.parse(statsText);
|
|
5511
|
-
if (statsPayload?.handoffs) handoffStats = statsPayload.handoffs;
|
|
5512
|
-
}
|
|
5513
|
-
} catch (_) { /* skip on failure */ }
|
|
5514
|
-
}
|
|
5563
|
+
// Reuse the stats already fetched for the cross-laptop hint above.
|
|
5564
|
+
const handoffStats = handoffStatsForHint;
|
|
5515
5565
|
|
|
5516
5566
|
if (flags.json) {
|
|
5517
5567
|
process.stdout.write(JSON.stringify({ checks, ...(handoffStats ? { handoffs: handoffStats } : {}) }, null, 2) + '\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.53.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": {
|