cf-memory-mcp 3.26.0 → 3.27.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.
@@ -3792,6 +3792,8 @@ Usage:
3792
3792
  npx cf-memory-mcp status Show bridge state + server resume availability
3793
3793
  npx cf-memory-mcp clean Delete local disk cache for current cwd
3794
3794
  npx cf-memory-mcp clean --all Delete ALL local disk caches
3795
+ npx cf-memory-mcp export <id> Print a session's handoff as JSON bundle (backup)
3796
+ npx cf-memory-mcp import <file> Restore a handoff bundle (cross-machine sync); use "-" for stdin
3795
3797
  npx cf-memory-mcp --version Show version
3796
3798
  npx cf-memory-mcp --help Show this help
3797
3799
  npx cf-memory-mcp --diagnose Test connectivity and report issues
@@ -3998,6 +4000,153 @@ async function runListCli() {
3998
4000
  }
3999
4001
  }
4000
4002
 
4003
+ async function runExportCli() {
4004
+ if (!API_KEY) {
4005
+ console.error('Error: CF_MEMORY_API_KEY environment variable is required');
4006
+ process.exit(1);
4007
+ }
4008
+ const { positional, flags } = parseCliArgs(process.argv.slice(3));
4009
+ const sessionArg = positional[0];
4010
+ if (!sessionArg) {
4011
+ console.error('Usage: cf-memory-mcp export <session-id-or-prefix> [--md path]');
4012
+ process.exit(1);
4013
+ }
4014
+ const server = new CFMemoryMCP();
4015
+ server.logDebug = () => {};
4016
+ try {
4017
+ const args = { resume: true, session_id_hint: sessionArg };
4018
+ const response = await server.makeRequest({
4019
+ jsonrpc: '2.0',
4020
+ id: `cli-export-${Date.now()}`,
4021
+ method: 'tools/call',
4022
+ params: { name: 'get_context_bootstrap', arguments: args },
4023
+ });
4024
+ const text = response?.result?.content?.[0]?.text;
4025
+ const payload = JSON.parse(text || '{}');
4026
+ const envelope = payload.resume_handoff;
4027
+ if (!envelope?.handoff) {
4028
+ process.stderr.write((payload.empty_hint || `No handoff found for "${sessionArg}".`) + '\n');
4029
+ process.exit(3);
4030
+ }
4031
+ // Build an exportable bundle: enough to fully reconstruct via import.
4032
+ const bundle = {
4033
+ kind: 'cf-memory-handoff',
4034
+ version: 1,
4035
+ exported_at: new Date().toISOString(),
4036
+ session_id: envelope.session_id,
4037
+ started_at: envelope.started_at,
4038
+ ended_at: envelope.ended_at,
4039
+ handoff: envelope.handoff,
4040
+ };
4041
+ const output = JSON.stringify(bundle, null, 2);
4042
+ if (flags.md_path) {
4043
+ fs.writeFileSync(flags.md_path, output);
4044
+ process.stdout.write(`Wrote ${output.length} bytes to ${flags.md_path}\n`);
4045
+ } else {
4046
+ process.stdout.write(output + '\n');
4047
+ }
4048
+ process.exit(0);
4049
+ } catch (err) {
4050
+ console.error('export command failed:', err.message);
4051
+ process.exit(1);
4052
+ }
4053
+ }
4054
+
4055
+ async function runImportCli() {
4056
+ if (!API_KEY) {
4057
+ console.error('Error: CF_MEMORY_API_KEY environment variable is required');
4058
+ process.exit(1);
4059
+ }
4060
+ const { positional, flags } = parseCliArgs(process.argv.slice(3));
4061
+ const sourcePath = positional[0];
4062
+ let raw;
4063
+ try {
4064
+ if (sourcePath === '-' || sourcePath === undefined) {
4065
+ // Read from stdin so `cat handoff.json | cf-memory-mcp import` works.
4066
+ raw = fs.readFileSync(0, 'utf8'); // fd 0 = stdin
4067
+ } else {
4068
+ raw = fs.readFileSync(sourcePath, 'utf8');
4069
+ }
4070
+ } catch (err) {
4071
+ console.error('import: cannot read input:', err.message);
4072
+ process.exit(1);
4073
+ }
4074
+ let bundle;
4075
+ try { bundle = JSON.parse(raw); } catch (err) {
4076
+ console.error('import: input is not valid JSON:', err.message);
4077
+ process.exit(1);
4078
+ }
4079
+ if (bundle.kind !== 'cf-memory-handoff' || !bundle.handoff) {
4080
+ console.error('import: input is not a cf-memory-handoff bundle (expected kind="cf-memory-handoff" + handoff field).');
4081
+ process.exit(1);
4082
+ }
4083
+ const server = new CFMemoryMCP();
4084
+ server.logDebug = () => {};
4085
+ try {
4086
+ // Imports always create a fresh session and write the imported
4087
+ // handoff to it. The original session_id is preserved in
4088
+ // handoff.notes so the link to the source isn't lost.
4089
+ const meta = server.getRepoMetadata();
4090
+ const startArgs = { context: 'main' };
4091
+ if (meta.repo_path) startArgs.repo_path = meta.repo_path;
4092
+ if (meta.branch) startArgs.branch = meta.branch;
4093
+ const fake = { params: { name: 'retrieve_context', arguments: {} } };
4094
+ await server.maybeFillProjectId(fake);
4095
+ if (fake.params.arguments.project_id) startArgs.project_id = fake.params.arguments.project_id;
4096
+
4097
+ const startRes = await server.makeRequest({
4098
+ jsonrpc: '2.0', id: `cli-import-start-${Date.now()}`,
4099
+ method: 'tools/call', params: { name: 'start_session', arguments: startArgs },
4100
+ });
4101
+ const startText = startRes?.result?.content?.[0]?.text;
4102
+ const startPayload = JSON.parse(startText || '{}');
4103
+ const newSessionId = startPayload.session_id;
4104
+ if (!newSessionId) {
4105
+ console.error('import: failed to create new session:', startText);
4106
+ process.exit(1);
4107
+ }
4108
+
4109
+ // Build the handoff: take the imported one, append import note.
4110
+ const importNote = `[imported from session ${bundle.session_id} on ${new Date().toISOString()}; originally started ${bundle.started_at}]`;
4111
+ const handoff = { ...bundle.handoff };
4112
+ handoff.notes = handoff.notes ? `${handoff.notes}\n\n${importNote}` : importNote;
4113
+ // Fill repo metadata from current context if the imported handoff
4114
+ // didn't specify (cross-machine sync use case).
4115
+ if (!handoff.repo_path && meta.repo_path) handoff.repo_path = meta.repo_path;
4116
+ if (!handoff.branch && meta.branch) handoff.branch = meta.branch;
4117
+ if (!handoff.project_id && fake.params.arguments.project_id) handoff.project_id = fake.params.arguments.project_id;
4118
+
4119
+ const endRes = await server.makeRequest({
4120
+ jsonrpc: '2.0', id: `cli-import-end-${Date.now()}`,
4121
+ method: 'tools/call', params: { name: 'end_session', arguments: {
4122
+ session_id: newSessionId,
4123
+ keep_open: true,
4124
+ handoff,
4125
+ } },
4126
+ });
4127
+ const endText = endRes?.result?.content?.[0]?.text;
4128
+ const endPayload = JSON.parse(endText || '{}');
4129
+ if (flags.json) {
4130
+ process.stdout.write(JSON.stringify({
4131
+ imported_from: bundle.session_id,
4132
+ new_session_id: newSessionId,
4133
+ short_id: newSessionId.slice(0, 8),
4134
+ handoff_stored: !!endPayload.handoff_stored,
4135
+ resume_command: `npx cf-memory-mcp resume ${newSessionId.slice(0, 8)}`,
4136
+ }, null, 2) + '\n');
4137
+ } else {
4138
+ process.stdout.write(`Imported handoff into session ${newSessionId.slice(0, 8)} (kept_open).\n`);
4139
+ process.stdout.write(`Original: ${bundle.session_id}\n`);
4140
+ process.stdout.write(`Goal: ${handoff.goal}\n`);
4141
+ process.stdout.write(`To resume: npx cf-memory-mcp resume ${newSessionId.slice(0, 8)}\n`);
4142
+ }
4143
+ process.exit(endPayload.handoff_stored ? 0 : 2);
4144
+ } catch (err) {
4145
+ console.error('import command failed:', err.message);
4146
+ process.exit(1);
4147
+ }
4148
+ }
4149
+
4001
4150
  async function runCleanCli() {
4002
4151
  const { flags, positional } = parseCliArgs(process.argv.slice(3));
4003
4152
  const all = positional.includes('--all') || process.argv.includes('--all');
@@ -4230,6 +4379,16 @@ if (process.argv[2] === 'clean') {
4230
4379
  return;
4231
4380
  }
4232
4381
 
4382
+ if (process.argv[2] === 'export') {
4383
+ runExportCli();
4384
+ return;
4385
+ }
4386
+
4387
+ if (process.argv[2] === 'import') {
4388
+ runImportCli();
4389
+ return;
4390
+ }
4391
+
4233
4392
  if (process.argv.includes('--diagnose')) {
4234
4393
  (async () => {
4235
4394
  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.26.0",
3
+ "version": "3.27.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": {