cf-memory-mcp 3.53.0 → 3.55.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.
@@ -4030,6 +4030,8 @@ function parseCliArgs(rest) {
4030
4030
  flags.files_only = true;
4031
4031
  } else if (a === '--anchors-only') {
4032
4032
  flags.anchors_only = true;
4033
+ } else if (a === '--absolute') {
4034
+ flags.absolute = true;
4033
4035
  } else if (a === '--decisions-only') {
4034
4036
  flags.decisions_only = true;
4035
4037
  } else if (a === '--blockers-only') {
@@ -4196,11 +4198,15 @@ async function runResumeCli() {
4196
4198
  // --files-only: list files_touched paths, one per line. Designed
4197
4199
  // for xargs / cat pipelines:
4198
4200
  // $ cat $(cf-memory-mcp resume --files-only)
4201
+ // --absolute: prepend handoff.repo_path so paths work from any cwd.
4199
4202
  if (flags.files_only) {
4200
4203
  const files = payload.resume_handoff?.handoff?.files_touched || [];
4201
4204
  if (files.length === 0) process.exit(3);
4205
+ const repoRoot = payload.resume_handoff?.handoff?.repo_path;
4206
+ const toAbs = (p) => (flags.absolute && repoRoot && !path.isAbsolute(p))
4207
+ ? path.join(repoRoot, p) : p;
4202
4208
  for (const f of files) {
4203
- if (f.path) process.stdout.write(f.path + '\n');
4209
+ if (f.path) process.stdout.write(toAbs(f.path) + '\n');
4204
4210
  }
4205
4211
  process.exit(0);
4206
4212
  }
@@ -4212,8 +4218,12 @@ async function runResumeCli() {
4212
4218
  || payload.resume_handoff?.handoff?.code_anchors
4213
4219
  || [];
4214
4220
  if (anchors.length === 0) process.exit(3);
4221
+ const repoRoot = payload.resume_handoff?.handoff?.repo_path;
4222
+ const toAbs = (p) => (flags.absolute && repoRoot && !path.isAbsolute(p))
4223
+ ? path.join(repoRoot, p) : p;
4215
4224
  for (const a of anchors) {
4216
- const where = a.lines ? `${a.file_path}:${a.lines}` : a.file_path;
4225
+ const filePath = toAbs(a.file_path);
4226
+ const where = a.lines ? `${filePath}:${a.lines}` : filePath;
4217
4227
  const sym = a.name ? ` ${a.name}` : '';
4218
4228
  const staleMarker = a.stale ? ' [STALE]' : '';
4219
4229
  process.stdout.write(`${where}${sym}${staleMarker}\n`);
@@ -4464,25 +4474,54 @@ async function runResumeCli() {
4464
4474
 
4465
4475
  const aShort = (payload.resume_handoff.session_id || '').slice(0, 8);
4466
4476
  const bShort = (otherPayload.resume_handoff.session_id || '').slice(0, 8);
4467
- const lines = [`Diff: ${aShort} (this) vs ${bShort} (other)`, ''];
4468
- // Scalar fields
4469
- const scalars = ['goal', 'status', 'branch', 'repo_path'];
4470
- for (const f of scalars) {
4477
+
4478
+ // Build a structured diff first; render either as JSON or
4479
+ // as the human-readable +/- output.
4480
+ const scalarDiff = {};
4481
+ for (const f of ['goal', 'status', 'branch', 'repo_path']) {
4471
4482
  if (h[f] !== otherHandoff[f]) {
4472
- lines.push(` ~ ${f}: "${otherHandoff[f] || ''}" "${h[f] || ''}"`);
4483
+ scalarDiff[f] = { from: otherHandoff[f] ?? null, to: h[f] ?? null };
4473
4484
  }
4474
4485
  }
4475
- // Array fields
4476
- const arrDiff = diffArr('next_steps', h.next_steps, otherHandoff.next_steps);
4477
- if (arrDiff) lines.push(arrDiff);
4478
- const blockerDiff = diffArr('blockers', h.blockers, otherHandoff.blockers);
4479
- if (blockerDiff) lines.push(blockerDiff);
4480
- const decisionDiff = diffArr('decisions', h.decisions, otherHandoff.decisions);
4481
- if (decisionDiff) lines.push(decisionDiff);
4482
- const fileDiff = diffArr('files_touched', h.files_touched, otherHandoff.files_touched, 'path');
4483
- if (fileDiff) lines.push(fileDiff);
4484
- const anchorDiff = diffArr('code_anchors', h.code_anchors, otherHandoff.code_anchors, 'file_path');
4485
- if (anchorDiff) lines.push(anchorDiff);
4486
+ const arrayDiffObj = (a, b, key) => {
4487
+ const A = setOf(a, key); const B = setOf(b, key);
4488
+ return {
4489
+ added: [...A].filter(x => !B.has(x)),
4490
+ removed: [...B].filter(x => !A.has(x)),
4491
+ };
4492
+ };
4493
+ const arrayDiffs = {
4494
+ next_steps: arrayDiffObj(h.next_steps, otherHandoff.next_steps),
4495
+ blockers: arrayDiffObj(h.blockers, otherHandoff.blockers),
4496
+ decisions: arrayDiffObj(h.decisions, otherHandoff.decisions),
4497
+ files_touched: arrayDiffObj(h.files_touched, otherHandoff.files_touched, 'path'),
4498
+ code_anchors: arrayDiffObj(h.code_anchors, otherHandoff.code_anchors, 'file_path'),
4499
+ };
4500
+
4501
+ if (flags.json) {
4502
+ // Strip empty arrays from arrayDiffs for compactness.
4503
+ const compactArrays = Object.fromEntries(
4504
+ Object.entries(arrayDiffs)
4505
+ .filter(([, v]) => v.added.length > 0 || v.removed.length > 0)
4506
+ );
4507
+ process.stdout.write(JSON.stringify({
4508
+ this: payload.resume_handoff.session_id,
4509
+ other: otherPayload.resume_handoff.session_id,
4510
+ scalars: scalarDiff,
4511
+ arrays: compactArrays,
4512
+ unchanged: Object.keys(scalarDiff).length === 0 && Object.keys(compactArrays).length === 0,
4513
+ }, null, 2) + '\n');
4514
+ process.exit(0);
4515
+ }
4516
+
4517
+ const lines = [`Diff: ${aShort} (this) vs ${bShort} (other)`, ''];
4518
+ for (const [f, v] of Object.entries(scalarDiff)) {
4519
+ lines.push(` ~ ${f}: "${v.from || ''}" → "${v.to || ''}"`);
4520
+ }
4521
+ for (const [label, v] of Object.entries(arrayDiffs)) {
4522
+ if (v.added.length > 0) lines.push(` + ${label}: ${v.added.join(', ')}`);
4523
+ if (v.removed.length > 0) lines.push(` - ${label}: ${v.removed.join(', ')}`);
4524
+ }
4486
4525
  if (lines.length === 2) lines.push(' (no differences)');
4487
4526
  process.stdout.write(lines.join('\n') + '\n');
4488
4527
  process.exit(0);
@@ -5147,6 +5186,31 @@ function runCompletionCli() {
5147
5186
  const shell = process.argv[3] || 'bash';
5148
5187
  const install = process.argv.includes('--install');
5149
5188
  const uninstall = process.argv.includes('--uninstall');
5189
+ const allShells = process.argv.includes('--all-shells');
5190
+
5191
+ // --install --all-shells: iterate every shell whose config dir is
5192
+ // detectable and install completion for each. Convenience for users
5193
+ // who use multiple shells. Re-spawns runCompletionCli per shell so
5194
+ // we get clean per-shell install messages.
5195
+ if (install && allShells) {
5196
+ const shells = ['bash', 'zsh', 'fish', 'powershell'];
5197
+ const { execFileSync } = require('child_process');
5198
+ let installed = 0;
5199
+ for (const s of shells) {
5200
+ try {
5201
+ const out = execFileSync(process.execPath, [__filename, 'completion', s, '--install'], {
5202
+ encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
5203
+ });
5204
+ if (out) process.stdout.write(out);
5205
+ process.stderr.write(` installed ${s}\n`);
5206
+ installed++;
5207
+ } catch (err) {
5208
+ process.stderr.write(` ${s}: ${err.message.split('\n')[0]}\n`);
5209
+ }
5210
+ }
5211
+ process.stderr.write(`\nDone. Installed completion for ${installed} shell${installed === 1 ? '' : 's'}.\n`);
5212
+ process.exit(installed > 0 ? 0 : 1);
5213
+ }
5150
5214
  const commands = ['resume', 'list', 'history', 'checkpoint', 'link', 'explain', 'status', 'clean', 'export', 'import', 'delete', 'doctor', 'env', 'completion'];
5151
5215
  const flags = ['--json', '-j', '--limit', '-n', '--md', '--all', '--force', '-f', '--version', '-v', '--help', '-h', '--diagnose'];
5152
5216
 
@@ -5322,6 +5386,8 @@ const PER_COMMAND_HELP = {
5322
5386
  --next-steps All next_steps, numbered.
5323
5387
  --files-only files_touched paths, one per line (xargs-friendly).
5324
5388
  --anchors-only code_anchors as "file:lines symbol".
5389
+ --absolute With --files-only/--anchors-only: prepend repo_path
5390
+ so paths work from any cwd.
5325
5391
  --decisions-only decisions, one per line.
5326
5392
  --blockers-only open blockers, one per line.
5327
5393
  --chain Walk parent_session_id back; show the thread history.
@@ -5382,8 +5448,11 @@ const PER_COMMAND_HELP = {
5382
5448
  cache writability, worker reachability, project indexing, resume
5383
5449
  availability. Exit nonzero if any check fails.
5384
5450
  --json, -j Emit a JSON list of checks.`,
5385
- completion: `cf-memory-mcp completion [bash|zsh|fish|powershell]
5386
- Output shell completion script. Pipe to your shell's completion dir.`,
5451
+ completion: `cf-memory-mcp completion [bash|zsh|fish|powershell] [--install [--all-shells] | --uninstall]
5452
+ Output shell completion script (or install/uninstall it).
5453
+ --install Write to user-local config dir (no sudo).
5454
+ --uninstall Remove a previously-installed script.
5455
+ --all-shells With --install: install for every shell at once.`,
5387
5456
  delete: `cf-memory-mcp delete <session-id-or-prefix> [--json]
5388
5457
  cf-memory-mcp delete [--status STATUS] [--older-than 30d] [--repo PATH] --yes [--json]
5389
5458
  Delete session row(s) and any session_summary memories tied to them.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cf-memory-mcp",
3
- "version": "3.53.0",
3
+ "version": "3.55.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": {