cf-memory-mcp 3.54.0 → 3.56.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.
@@ -4038,6 +4038,12 @@ function parseCliArgs(rest) {
4038
4038
  flags.blockers_only = true;
4039
4039
  } else if (a === '--chain') {
4040
4040
  flags.chain = true;
4041
+ } else if (a === '--include-chain') {
4042
+ const n = parseInt(rest[++i], 10);
4043
+ flags.include_chain = Number.isFinite(n) && n > 0 ? Math.min(n, 10) : 3;
4044
+ } else if (a.startsWith('--include-chain=')) {
4045
+ const n = parseInt(a.slice('--include-chain='.length), 10);
4046
+ flags.include_chain = Number.isFinite(n) && n > 0 ? Math.min(n, 10) : 3;
4041
4047
  } else if (a === '--validate') {
4042
4048
  flags.validate = true;
4043
4049
  } else if (a === '--raw') {
@@ -4474,25 +4480,54 @@ async function runResumeCli() {
4474
4480
 
4475
4481
  const aShort = (payload.resume_handoff.session_id || '').slice(0, 8);
4476
4482
  const bShort = (otherPayload.resume_handoff.session_id || '').slice(0, 8);
4477
- const lines = [`Diff: ${aShort} (this) vs ${bShort} (other)`, ''];
4478
- // Scalar fields
4479
- const scalars = ['goal', 'status', 'branch', 'repo_path'];
4480
- for (const f of scalars) {
4483
+
4484
+ // Build a structured diff first; render either as JSON or
4485
+ // as the human-readable +/- output.
4486
+ const scalarDiff = {};
4487
+ for (const f of ['goal', 'status', 'branch', 'repo_path']) {
4481
4488
  if (h[f] !== otherHandoff[f]) {
4482
- lines.push(` ~ ${f}: "${otherHandoff[f] || ''}" "${h[f] || ''}"`);
4489
+ scalarDiff[f] = { from: otherHandoff[f] ?? null, to: h[f] ?? null };
4483
4490
  }
4484
4491
  }
4485
- // Array fields
4486
- const arrDiff = diffArr('next_steps', h.next_steps, otherHandoff.next_steps);
4487
- if (arrDiff) lines.push(arrDiff);
4488
- const blockerDiff = diffArr('blockers', h.blockers, otherHandoff.blockers);
4489
- if (blockerDiff) lines.push(blockerDiff);
4490
- const decisionDiff = diffArr('decisions', h.decisions, otherHandoff.decisions);
4491
- if (decisionDiff) lines.push(decisionDiff);
4492
- const fileDiff = diffArr('files_touched', h.files_touched, otherHandoff.files_touched, 'path');
4493
- if (fileDiff) lines.push(fileDiff);
4494
- const anchorDiff = diffArr('code_anchors', h.code_anchors, otherHandoff.code_anchors, 'file_path');
4495
- if (anchorDiff) lines.push(anchorDiff);
4492
+ const arrayDiffObj = (a, b, key) => {
4493
+ const A = setOf(a, key); const B = setOf(b, key);
4494
+ return {
4495
+ added: [...A].filter(x => !B.has(x)),
4496
+ removed: [...B].filter(x => !A.has(x)),
4497
+ };
4498
+ };
4499
+ const arrayDiffs = {
4500
+ next_steps: arrayDiffObj(h.next_steps, otherHandoff.next_steps),
4501
+ blockers: arrayDiffObj(h.blockers, otherHandoff.blockers),
4502
+ decisions: arrayDiffObj(h.decisions, otherHandoff.decisions),
4503
+ files_touched: arrayDiffObj(h.files_touched, otherHandoff.files_touched, 'path'),
4504
+ code_anchors: arrayDiffObj(h.code_anchors, otherHandoff.code_anchors, 'file_path'),
4505
+ };
4506
+
4507
+ if (flags.json) {
4508
+ // Strip empty arrays from arrayDiffs for compactness.
4509
+ const compactArrays = Object.fromEntries(
4510
+ Object.entries(arrayDiffs)
4511
+ .filter(([, v]) => v.added.length > 0 || v.removed.length > 0)
4512
+ );
4513
+ process.stdout.write(JSON.stringify({
4514
+ this: payload.resume_handoff.session_id,
4515
+ other: otherPayload.resume_handoff.session_id,
4516
+ scalars: scalarDiff,
4517
+ arrays: compactArrays,
4518
+ unchanged: Object.keys(scalarDiff).length === 0 && Object.keys(compactArrays).length === 0,
4519
+ }, null, 2) + '\n');
4520
+ process.exit(0);
4521
+ }
4522
+
4523
+ const lines = [`Diff: ${aShort} (this) vs ${bShort} (other)`, ''];
4524
+ for (const [f, v] of Object.entries(scalarDiff)) {
4525
+ lines.push(` ~ ${f}: "${v.from || ''}" → "${v.to || ''}"`);
4526
+ }
4527
+ for (const [label, v] of Object.entries(arrayDiffs)) {
4528
+ if (v.added.length > 0) lines.push(` + ${label}: ${v.added.join(', ')}`);
4529
+ if (v.removed.length > 0) lines.push(` - ${label}: ${v.removed.join(', ')}`);
4530
+ }
4496
4531
  if (lines.length === 2) lines.push(' (no differences)');
4497
4532
  process.stdout.write(lines.join('\n') + '\n');
4498
4533
  process.exit(0);
@@ -4585,6 +4620,32 @@ async function runResumeCli() {
4585
4620
  } else {
4586
4621
  process.stdout.write(JSON.stringify(payload.resume_handoff, null, 2) + '\n');
4587
4622
  }
4623
+ // --include-chain N: walk parent_session_id back N times and
4624
+ // append each parent's resume_prompt inline so the agent sees
4625
+ // the full thread arc in one output.
4626
+ if (flags.include_chain && flags.include_chain > 0) {
4627
+ let cur = payload.resume_handoff;
4628
+ for (let i = 0; i < flags.include_chain; i++) {
4629
+ const parentId = cur?.handoff?.parent_session_id;
4630
+ if (!parentId) break;
4631
+ const parentRes = await server.makeRequest({
4632
+ jsonrpc: '2.0', id: `cli-include-chain-${i}-${Date.now()}`,
4633
+ method: 'tools/call',
4634
+ params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: parentId } },
4635
+ });
4636
+ const parentText = parentRes?.result?.content?.[0]?.text;
4637
+ const parentPayload = JSON.parse(parentText || '{}');
4638
+ if (!parentPayload.resume_handoff) break;
4639
+ process.stdout.write(`\n---\n## ↑ Parent ${i + 1}: ${(parentPayload.resume_handoff.session_id||'').slice(0,8)}\n\n`);
4640
+ if (parentPayload.resume_prompt) {
4641
+ // Strip the parent's own "## Resume context" header
4642
+ // to avoid duplicated h2s.
4643
+ const cleaned = parentPayload.resume_prompt.replace(/^## Resume context from previous session\n+/, '');
4644
+ process.stdout.write(cleaned + '\n');
4645
+ }
4646
+ cur = parentPayload.resume_handoff;
4647
+ }
4648
+ }
4588
4649
  if (Array.isArray(payload.recent_handoffs) && payload.recent_handoffs.length > 1) {
4589
4650
  process.stdout.write('\n---\nOther recent handoffs:\n');
4590
4651
  for (const h of payload.recent_handoffs.slice(0, 4)) {
@@ -5362,6 +5423,7 @@ const PER_COMMAND_HELP = {
5362
5423
  --decisions-only decisions, one per line.
5363
5424
  --blockers-only open blockers, one per line.
5364
5425
  --chain Walk parent_session_id back; show the thread history.
5426
+ --include-chain N Inline the last N parent handoffs in the rendered output (default 3, max 10).
5365
5427
  --diff <other-id> Compare this handoff against another (added/removed/changed fields).
5366
5428
  --validate Check that files_touched + code_anchors still exist locally.
5367
5429
  --raw Print just the raw handoff JSON (no envelope metadata).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cf-memory-mcp",
3
- "version": "3.54.0",
3
+ "version": "3.56.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": {