cf-memory-mcp 3.48.0 → 3.50.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 +112 -1
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -4061,6 +4061,10 @@ function parseCliArgs(rest) {
|
|
|
4061
4061
|
flags.fields = rest[++i];
|
|
4062
4062
|
} else if (a.startsWith('--fields=')) {
|
|
4063
4063
|
flags.fields = a.slice('--fields='.length);
|
|
4064
|
+
} else if (a === '--diff') {
|
|
4065
|
+
flags.diff = rest[++i];
|
|
4066
|
+
} else if (a.startsWith('--diff=')) {
|
|
4067
|
+
flags.diff = a.slice('--diff='.length);
|
|
4064
4068
|
} else if (a === '--older-than') {
|
|
4065
4069
|
// Accept "7d" / "30d" / "12h" / raw number (days).
|
|
4066
4070
|
const raw = rest[++i] || '';
|
|
@@ -4392,6 +4396,78 @@ async function runResumeCli() {
|
|
|
4392
4396
|
process.exit(0);
|
|
4393
4397
|
}
|
|
4394
4398
|
|
|
4399
|
+
// --diff <other-id>: compare two handoffs. Shows added/removed
|
|
4400
|
+
// next_steps, branch shift, status change, files diff. Useful
|
|
4401
|
+
// for "what changed between yesterday's session and today's?".
|
|
4402
|
+
// Special value "--parent" diffs against the chain parent.
|
|
4403
|
+
if (flags.diff) {
|
|
4404
|
+
if (!found) {
|
|
4405
|
+
process.stderr.write('No source handoff available to diff against.\n');
|
|
4406
|
+
process.exit(3);
|
|
4407
|
+
}
|
|
4408
|
+
let diffTarget = flags.diff;
|
|
4409
|
+
// --diff --parent: resolve to the parent_session_id from the
|
|
4410
|
+
// current handoff so users can do "what's new since the
|
|
4411
|
+
// last checkpoint" without typing the parent's id.
|
|
4412
|
+
if (diffTarget === '--parent' || diffTarget === 'parent') {
|
|
4413
|
+
const parentId = payload.resume_handoff.handoff?.parent_session_id;
|
|
4414
|
+
if (!parentId) {
|
|
4415
|
+
process.stderr.write('This handoff has no parent_session_id to diff against.\n');
|
|
4416
|
+
process.exit(3);
|
|
4417
|
+
}
|
|
4418
|
+
diffTarget = parentId;
|
|
4419
|
+
}
|
|
4420
|
+
const otherRes = await server.makeRequest({
|
|
4421
|
+
jsonrpc: '2.0', id: `cli-diff-${Date.now()}`,
|
|
4422
|
+
method: 'tools/call',
|
|
4423
|
+
params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: diffTarget } },
|
|
4424
|
+
});
|
|
4425
|
+
const otherText = otherRes?.result?.content?.[0]?.text;
|
|
4426
|
+
const otherPayload = JSON.parse(otherText || '{}');
|
|
4427
|
+
const otherHandoff = otherPayload.resume_handoff?.handoff;
|
|
4428
|
+
if (!otherHandoff) {
|
|
4429
|
+
process.stderr.write(`Could not fetch handoff "${diffTarget}" to diff against.\n`);
|
|
4430
|
+
process.exit(3);
|
|
4431
|
+
}
|
|
4432
|
+
const h = payload.resume_handoff.handoff;
|
|
4433
|
+
const setOf = (arr, key) =>
|
|
4434
|
+
new Set((arr || []).map(x => typeof x === 'string' ? x : x[key]).filter(Boolean));
|
|
4435
|
+
const diffArr = (label, a, b, key) => {
|
|
4436
|
+
const A = setOf(a, key); const B = setOf(b, key);
|
|
4437
|
+
const added = [...A].filter(x => !B.has(x));
|
|
4438
|
+
const removed = [...B].filter(x => !A.has(x));
|
|
4439
|
+
const lines = [];
|
|
4440
|
+
if (added.length) lines.push(` + ${label}: ${added.join(', ')}`);
|
|
4441
|
+
if (removed.length) lines.push(` - ${label}: ${removed.join(', ')}`);
|
|
4442
|
+
return lines.join('\n');
|
|
4443
|
+
};
|
|
4444
|
+
|
|
4445
|
+
const aShort = (payload.resume_handoff.session_id || '').slice(0, 8);
|
|
4446
|
+
const bShort = (otherPayload.resume_handoff.session_id || '').slice(0, 8);
|
|
4447
|
+
const lines = [`Diff: ${aShort} (this) vs ${bShort} (other)`, ''];
|
|
4448
|
+
// Scalar fields
|
|
4449
|
+
const scalars = ['goal', 'status', 'branch', 'repo_path'];
|
|
4450
|
+
for (const f of scalars) {
|
|
4451
|
+
if (h[f] !== otherHandoff[f]) {
|
|
4452
|
+
lines.push(` ~ ${f}: "${otherHandoff[f] || ''}" → "${h[f] || ''}"`);
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
// Array fields
|
|
4456
|
+
const arrDiff = diffArr('next_steps', h.next_steps, otherHandoff.next_steps);
|
|
4457
|
+
if (arrDiff) lines.push(arrDiff);
|
|
4458
|
+
const blockerDiff = diffArr('blockers', h.blockers, otherHandoff.blockers);
|
|
4459
|
+
if (blockerDiff) lines.push(blockerDiff);
|
|
4460
|
+
const decisionDiff = diffArr('decisions', h.decisions, otherHandoff.decisions);
|
|
4461
|
+
if (decisionDiff) lines.push(decisionDiff);
|
|
4462
|
+
const fileDiff = diffArr('files_touched', h.files_touched, otherHandoff.files_touched, 'path');
|
|
4463
|
+
if (fileDiff) lines.push(fileDiff);
|
|
4464
|
+
const anchorDiff = diffArr('code_anchors', h.code_anchors, otherHandoff.code_anchors, 'file_path');
|
|
4465
|
+
if (anchorDiff) lines.push(anchorDiff);
|
|
4466
|
+
if (lines.length === 2) lines.push(' (no differences)');
|
|
4467
|
+
process.stdout.write(lines.join('\n') + '\n');
|
|
4468
|
+
process.exit(0);
|
|
4469
|
+
}
|
|
4470
|
+
|
|
4395
4471
|
// --validate: verify the handoff's file references still exist
|
|
4396
4472
|
// on disk. Resolves each path relative to the handoff's repo_path
|
|
4397
4473
|
// (or cwd). Reports per-path status. Useful before resuming to
|
|
@@ -5098,6 +5174,7 @@ const PER_COMMAND_HELP = {
|
|
|
5098
5174
|
--decisions-only decisions, one per line.
|
|
5099
5175
|
--blockers-only open blockers, one per line.
|
|
5100
5176
|
--chain Walk parent_session_id back; show the thread history.
|
|
5177
|
+
--diff <other-id> Compare this handoff against another (added/removed/changed fields).
|
|
5101
5178
|
--validate Check that files_touched + code_anchors still exist locally.
|
|
5102
5179
|
--raw Print just the raw handoff JSON (no envelope metadata).
|
|
5103
5180
|
--age Print handoff_age_minutes (single integer).
|
|
@@ -5295,8 +5372,25 @@ async function runDoctorCli() {
|
|
|
5295
5372
|
}
|
|
5296
5373
|
}
|
|
5297
5374
|
|
|
5375
|
+
// Optional: handoff stats summary at the bottom (visibility into
|
|
5376
|
+
// how much resume context is captured for the current user).
|
|
5377
|
+
let handoffStats = null;
|
|
5378
|
+
if (API_KEY) {
|
|
5379
|
+
try {
|
|
5380
|
+
const statsRes = await server.makeRequestOnce({
|
|
5381
|
+
jsonrpc: '2.0', id: `doctor-stats-${Date.now()}`,
|
|
5382
|
+
method: 'tools/call', params: { name: 'get_stats', arguments: {} },
|
|
5383
|
+
});
|
|
5384
|
+
const statsText = statsRes?.result?.content?.[0]?.text;
|
|
5385
|
+
if (statsText) {
|
|
5386
|
+
const statsPayload = JSON.parse(statsText);
|
|
5387
|
+
if (statsPayload?.handoffs) handoffStats = statsPayload.handoffs;
|
|
5388
|
+
}
|
|
5389
|
+
} catch (_) { /* skip on failure */ }
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5298
5392
|
if (flags.json) {
|
|
5299
|
-
process.stdout.write(JSON.stringify({ checks }, null, 2) + '\n');
|
|
5393
|
+
process.stdout.write(JSON.stringify({ checks, ...(handoffStats ? { handoffs: handoffStats } : {}) }, null, 2) + '\n');
|
|
5300
5394
|
process.exit(checks.every(c => c.ok) ? 0 : 1);
|
|
5301
5395
|
}
|
|
5302
5396
|
process.stdout.write(`cf-memory-mcp v${PACKAGE_VERSION} — doctor\n\n`);
|
|
@@ -5309,6 +5403,23 @@ async function runDoctorCli() {
|
|
|
5309
5403
|
process.stdout.write(` → ${c.fix}\n`);
|
|
5310
5404
|
}
|
|
5311
5405
|
}
|
|
5406
|
+
if (handoffStats) {
|
|
5407
|
+
process.stdout.write('\nHandoff stats:\n');
|
|
5408
|
+
process.stdout.write(` total: ${handoffStats.total}\n`);
|
|
5409
|
+
if (handoffStats.by_status) {
|
|
5410
|
+
const byStatus = Object.entries(handoffStats.by_status)
|
|
5411
|
+
.map(([s, n]) => `${s}=${n}`).join(', ');
|
|
5412
|
+
process.stdout.write(` by_status: ${byStatus}\n`);
|
|
5413
|
+
}
|
|
5414
|
+
if (handoffStats.oldest_in_progress) {
|
|
5415
|
+
const o = handoffStats.oldest_in_progress;
|
|
5416
|
+
const shortId = (o.session_id || '').slice(0, 8);
|
|
5417
|
+
process.stdout.write(` oldest in_progress: ${shortId} (${o.age_minutes}m ago)\n`);
|
|
5418
|
+
}
|
|
5419
|
+
if (handoffStats.by_repo && handoffStats.by_repo.length > 0) {
|
|
5420
|
+
process.stdout.write(` top repos: ${handoffStats.by_repo.slice(0, 3).map(r => `${r.repo_path.split('/').pop()}=${r.count}`).join(', ')}\n`);
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5312
5423
|
process.stdout.write('\n');
|
|
5313
5424
|
process.stdout.write(anyFailed ? 'Some checks failed. See suggestions above.\n' : 'All checks passed.\n');
|
|
5314
5425
|
process.exit(anyFailed ? 1 : 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.50.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": {
|