cf-memory-mcp 3.42.0 → 3.43.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 +123 -2
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -3843,7 +3843,7 @@ if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
|
3843
3843
|
|
|
3844
3844
|
// Global --help only when no subcommand is present. With a subcommand, fall
|
|
3845
3845
|
// through to the per-command help dispatch below.
|
|
3846
|
-
const SUBCOMMANDS = new Set(['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion', 'delete', 'env', 'history']);
|
|
3846
|
+
const SUBCOMMANDS = new Set(['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion', 'delete', 'env', 'history', 'link']);
|
|
3847
3847
|
const hasSubcommand = process.argv[2] && SUBCOMMANDS.has(process.argv[2]);
|
|
3848
3848
|
|
|
3849
3849
|
if (!hasSubcommand && (process.argv.includes('--help') || process.argv.includes('-h'))) {
|
|
@@ -3858,6 +3858,7 @@ Usage:
|
|
|
3858
3858
|
npx cf-memory-mcp list List recent handoffs for cwd (status-ranked)
|
|
3859
3859
|
npx cf-memory-mcp history List all handoffs for cwd, chronological
|
|
3860
3860
|
npx cf-memory-mcp checkpoint ["<goal>"] Snapshot current state (keep_open)
|
|
3861
|
+
npx cf-memory-mcp link <child> --parent <id> Retroactively link a child session to a parent
|
|
3861
3862
|
npx cf-memory-mcp status Show bridge state + server resume availability
|
|
3862
3863
|
npx cf-memory-mcp clean Delete local disk cache for current cwd
|
|
3863
3864
|
npx cf-memory-mcp clean --all Delete ALL local disk caches
|
|
@@ -3964,6 +3965,8 @@ function parseCliArgs(rest) {
|
|
|
3964
3965
|
flags.raw = true;
|
|
3965
3966
|
} else if (a === '--copy') {
|
|
3966
3967
|
flags.copy = true;
|
|
3968
|
+
} else if (a === '--card') {
|
|
3969
|
+
flags.card = true;
|
|
3967
3970
|
} else if (a === '--older-than') {
|
|
3968
3971
|
// Accept "7d" / "30d" / "12h" / raw number (days).
|
|
3969
3972
|
const raw = rest[++i] || '';
|
|
@@ -4126,6 +4129,24 @@ async function runResumeCli() {
|
|
|
4126
4129
|
process.exit(0);
|
|
4127
4130
|
}
|
|
4128
4131
|
|
|
4132
|
+
// --card: compact 2-3 line summary card for status widgets.
|
|
4133
|
+
// Format: [status · age · q=score] goal / → next_step
|
|
4134
|
+
if (flags.card) {
|
|
4135
|
+
const envelope = payload.resume_handoff;
|
|
4136
|
+
if (!envelope) process.exit(3);
|
|
4137
|
+
const h = envelope.handoff || {};
|
|
4138
|
+
const ageMin = envelope.handoff_age_minutes;
|
|
4139
|
+
const fmtAge = (m) => m == null ? '?' : m < 60 ? `${m}m` : m < 1440 ? `${Math.round(m/60)}h` : `${Math.round(m/1440)}d`;
|
|
4140
|
+
const status = h.status || '?';
|
|
4141
|
+
const q = typeof envelope.quality_score === 'number' ? ` · q=${envelope.quality_score}` : '';
|
|
4142
|
+
const staleMarker = envelope.stale ? ' · STALE' : '';
|
|
4143
|
+
process.stdout.write(`[${status} · ${fmtAge(ageMin)} ago${q}${staleMarker}]\n`);
|
|
4144
|
+
process.stdout.write(`${h.goal || '(no goal)'}\n`);
|
|
4145
|
+
const next = h.next_steps?.[0];
|
|
4146
|
+
if (next) process.stdout.write(`→ ${next}\n`);
|
|
4147
|
+
process.exit(0);
|
|
4148
|
+
}
|
|
4149
|
+
|
|
4129
4150
|
// --chain: walk parent_session_id back through the thread history.
|
|
4130
4151
|
// Bounded at 20 iterations to avoid an infinite loop on malformed
|
|
4131
4152
|
// data. Prints each handoff as "<id> [age] status — goal".
|
|
@@ -4383,6 +4404,95 @@ async function runListCli() {
|
|
|
4383
4404
|
}
|
|
4384
4405
|
}
|
|
4385
4406
|
|
|
4407
|
+
async function runLinkCli() {
|
|
4408
|
+
if (!API_KEY) {
|
|
4409
|
+
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
4410
|
+
process.exit(1);
|
|
4411
|
+
}
|
|
4412
|
+
const { positional, flags } = parseCliArgs(process.argv.slice(3));
|
|
4413
|
+
const childArg = positional[0];
|
|
4414
|
+
// --parent <id> is parsed positionally too; grab it from process.argv.
|
|
4415
|
+
let parentId = null;
|
|
4416
|
+
const parentIdx = process.argv.indexOf('--parent');
|
|
4417
|
+
if (parentIdx !== -1 && process.argv[parentIdx + 1]) parentId = process.argv[parentIdx + 1];
|
|
4418
|
+
for (const a of process.argv) {
|
|
4419
|
+
if (a.startsWith('--parent=')) parentId = a.slice('--parent='.length);
|
|
4420
|
+
}
|
|
4421
|
+
if (!childArg || !parentId) {
|
|
4422
|
+
console.error('Usage: cf-memory-mcp link <child-id-or-prefix> --parent <parent-id-or-prefix>');
|
|
4423
|
+
process.exit(1);
|
|
4424
|
+
}
|
|
4425
|
+
const server = new CFMemoryMCP();
|
|
4426
|
+
server.logDebug = () => {};
|
|
4427
|
+
try {
|
|
4428
|
+
// Resolve child + parent prefixes to full UUIDs via get_context_bootstrap.
|
|
4429
|
+
const resolveId = async (idHint) => {
|
|
4430
|
+
if (idHint.length >= 36) return idHint;
|
|
4431
|
+
const r = await server.makeRequest({
|
|
4432
|
+
jsonrpc: '2.0', id: `cli-link-resolve-${Date.now()}`,
|
|
4433
|
+
method: 'tools/call',
|
|
4434
|
+
params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: idHint } },
|
|
4435
|
+
});
|
|
4436
|
+
const t = r?.result?.content?.[0]?.text;
|
|
4437
|
+
const p = JSON.parse(t || '{}');
|
|
4438
|
+
return p.resume_handoff?.session_id || null;
|
|
4439
|
+
};
|
|
4440
|
+
const fullChild = await resolveId(childArg);
|
|
4441
|
+
const fullParent = await resolveId(parentId);
|
|
4442
|
+
if (!fullChild) {
|
|
4443
|
+
process.stderr.write(`Could not resolve child "${childArg}" to a session.\n`);
|
|
4444
|
+
process.exit(3);
|
|
4445
|
+
}
|
|
4446
|
+
if (!fullParent) {
|
|
4447
|
+
process.stderr.write(`Could not resolve parent "${parentId}" to a session.\n`);
|
|
4448
|
+
process.exit(3);
|
|
4449
|
+
}
|
|
4450
|
+
// Fetch current child handoff, set parent_session_id, write back via end_session keep_open.
|
|
4451
|
+
const childRes = await server.makeRequest({
|
|
4452
|
+
jsonrpc: '2.0', id: `cli-link-fetch-${Date.now()}`,
|
|
4453
|
+
method: 'tools/call',
|
|
4454
|
+
params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: fullChild } },
|
|
4455
|
+
});
|
|
4456
|
+
const childText = childRes?.result?.content?.[0]?.text;
|
|
4457
|
+
const childPayload = JSON.parse(childText || '{}');
|
|
4458
|
+
const handoff = childPayload.resume_handoff?.handoff;
|
|
4459
|
+
if (!handoff) {
|
|
4460
|
+
process.stderr.write(`Child session has no handoff stored; cannot link.\n`);
|
|
4461
|
+
process.exit(3);
|
|
4462
|
+
}
|
|
4463
|
+
// Update with parent_session_id.
|
|
4464
|
+
const updated = { ...handoff, parent_session_id: fullParent };
|
|
4465
|
+
const updateRes = await server.makeRequest({
|
|
4466
|
+
jsonrpc: '2.0', id: `cli-link-update-${Date.now()}`,
|
|
4467
|
+
method: 'tools/call',
|
|
4468
|
+
params: { name: 'end_session', arguments: {
|
|
4469
|
+
session_id: fullChild,
|
|
4470
|
+
keep_open: true, // don't accidentally finalize
|
|
4471
|
+
handoff: updated,
|
|
4472
|
+
} },
|
|
4473
|
+
});
|
|
4474
|
+
const updateText = updateRes?.result?.content?.[0]?.text;
|
|
4475
|
+
const updatePayload = JSON.parse(updateText || '{}');
|
|
4476
|
+
if (flags.json) {
|
|
4477
|
+
process.stdout.write(JSON.stringify({
|
|
4478
|
+
child: fullChild,
|
|
4479
|
+
parent: fullParent,
|
|
4480
|
+
handoff_stored: !!updatePayload.handoff_stored,
|
|
4481
|
+
}, null, 2) + '\n');
|
|
4482
|
+
process.exit(updatePayload.handoff_stored ? 0 : 2);
|
|
4483
|
+
}
|
|
4484
|
+
if (updatePayload.handoff_stored) {
|
|
4485
|
+
process.stdout.write(`Linked ${fullChild.slice(0,8)} → parent ${fullParent.slice(0,8)}\n`);
|
|
4486
|
+
process.exit(0);
|
|
4487
|
+
}
|
|
4488
|
+
process.stderr.write(`Update failed: ${updateText}\n`);
|
|
4489
|
+
process.exit(2);
|
|
4490
|
+
} catch (err) {
|
|
4491
|
+
console.error('link command failed:', err.message);
|
|
4492
|
+
process.exit(1);
|
|
4493
|
+
}
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4386
4496
|
async function runHistoryCli() {
|
|
4387
4497
|
if (!API_KEY) {
|
|
4388
4498
|
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
@@ -4640,7 +4750,7 @@ function runEnvCli() {
|
|
|
4640
4750
|
|
|
4641
4751
|
function runCompletionCli() {
|
|
4642
4752
|
const shell = process.argv[3] || 'bash';
|
|
4643
|
-
const commands = ['resume', 'list', 'history', 'checkpoint', 'status', 'clean', 'export', 'import', 'delete', 'doctor', 'env', 'completion'];
|
|
4753
|
+
const commands = ['resume', 'list', 'history', 'checkpoint', 'link', 'status', 'clean', 'export', 'import', 'delete', 'doctor', 'env', 'completion'];
|
|
4644
4754
|
const flags = ['--json', '-j', '--limit', '-n', '--md', '--all', '--force', '-f', '--version', '-v', '--help', '-h', '--diagnose'];
|
|
4645
4755
|
if (shell === 'bash') {
|
|
4646
4756
|
process.stdout.write(`# cf-memory-mcp bash completion
|
|
@@ -4731,6 +4841,7 @@ const PER_COMMAND_HELP = {
|
|
|
4731
4841
|
<session-id-prefix> Optional: pick a specific session (>=8 char prefix or full UUID).
|
|
4732
4842
|
--md <path> Write the markdown to a file instead of stdout.
|
|
4733
4843
|
--copy Pipe the markdown to the platform clipboard (pbcopy/xclip/wl-copy/clip).
|
|
4844
|
+
--card Compact 2-3 line status card (for terminal status widgets).
|
|
4734
4845
|
Extract flags (pick one; each exits 3 if the section is empty):
|
|
4735
4846
|
--next-only First next_step only (for shell prompts).
|
|
4736
4847
|
--next-steps All next_steps, numbered.
|
|
@@ -4806,6 +4917,11 @@ const PER_COMMAND_HELP = {
|
|
|
4806
4917
|
--repo PATH Override the cwd's repo.
|
|
4807
4918
|
--since ISO Lower bound on handoff timestamp.
|
|
4808
4919
|
--json, -j Emit JSON.`,
|
|
4920
|
+
link: `cf-memory-mcp link <child-id-or-prefix> --parent <parent-id-or-prefix> [--json]
|
|
4921
|
+
Retroactively set parent_session_id on a child session, linking it to
|
|
4922
|
+
a parent in the chain. Useful when you forgot --force on checkpoint
|
|
4923
|
+
or want to manually chain sessions across repos.
|
|
4924
|
+
--json, -j Emit a JSON status object.`,
|
|
4809
4925
|
};
|
|
4810
4926
|
|
|
4811
4927
|
function printPerCommandHelp(cmd) {
|
|
@@ -5414,6 +5530,11 @@ if (process.argv[2] === 'history') {
|
|
|
5414
5530
|
return;
|
|
5415
5531
|
}
|
|
5416
5532
|
|
|
5533
|
+
if (process.argv[2] === 'link') {
|
|
5534
|
+
runLinkCli();
|
|
5535
|
+
return;
|
|
5536
|
+
}
|
|
5537
|
+
|
|
5417
5538
|
if (process.argv.includes('--diagnose')) {
|
|
5418
5539
|
(async () => {
|
|
5419
5540
|
console.log(`CF Memory MCP v${PACKAGE_VERSION} - Diagnostics`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.43.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": {
|