cf-memory-mcp 3.28.0 → 3.29.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.
Files changed (2) hide show
  1. package/bin/cf-memory-mcp.js +165 -10
  2. package/package.json +1 -1
@@ -3778,7 +3778,12 @@ if (process.argv.includes('--version') || process.argv.includes('-v')) {
3778
3778
  process.exit(0);
3779
3779
  }
3780
3780
 
3781
- if (process.argv.includes('--help') || process.argv.includes('-h')) {
3781
+ // Global --help only when no subcommand is present. With a subcommand, fall
3782
+ // through to the per-command help dispatch below.
3783
+ const SUBCOMMANDS = new Set(['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion']);
3784
+ const hasSubcommand = process.argv[2] && SUBCOMMANDS.has(process.argv[2]);
3785
+
3786
+ if (!hasSubcommand && (process.argv.includes('--help') || process.argv.includes('-h'))) {
3782
3787
  console.log(`
3783
3788
  CF Memory MCP v${PACKAGE_VERSION}
3784
3789
 
@@ -3795,6 +3800,8 @@ Usage:
3795
3800
  npx cf-memory-mcp export <id> Print a session's handoff as JSON bundle (backup)
3796
3801
  npx cf-memory-mcp import <file> Restore a handoff bundle (cross-machine sync); use "-" for stdin
3797
3802
  npx cf-memory-mcp doctor Diagnose common setup issues
3803
+ npx cf-memory-mcp completion bash Output shell completion script (bash|zsh|fish)
3804
+ npx cf-memory-mcp <cmd> --help Show flags for a specific command
3798
3805
  npx cf-memory-mcp --version Show version
3799
3806
 
3800
3807
  Short alias: \`cfm\` works as a drop-in for \`cf-memory-mcp\` (e.g., \`cfm resume\`).
@@ -4003,20 +4010,147 @@ async function runListCli() {
4003
4010
  }
4004
4011
  }
4005
4012
 
4013
+ function runCompletionCli() {
4014
+ const shell = process.argv[3] || 'bash';
4015
+ const commands = ['resume', 'list', 'checkpoint', 'status', 'clean', 'export', 'import', 'doctor', 'completion'];
4016
+ const flags = ['--json', '-j', '--limit', '-n', '--md', '--all', '--force', '-f', '--version', '-v', '--help', '-h', '--diagnose'];
4017
+ if (shell === 'bash') {
4018
+ process.stdout.write(`# cf-memory-mcp bash completion
4019
+ # Install: cf-memory-mcp completion bash > /usr/local/etc/bash_completion.d/cf-memory-mcp
4020
+ # Or for the current shell: source <(cf-memory-mcp completion bash)
4021
+ _cf_memory_mcp_complete() {
4022
+ local cur prev words
4023
+ COMPREPLY=()
4024
+ cur="\${COMP_WORDS[COMP_CWORD]}"
4025
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
4026
+ if [ "\$COMP_CWORD" -eq 1 ]; then
4027
+ COMPREPLY=( $(compgen -W "${commands.join(' ')}" -- "\$cur") )
4028
+ return 0
4029
+ fi
4030
+ case "\$cur" in
4031
+ --*)
4032
+ COMPREPLY=( $(compgen -W "${flags.filter(f => f.startsWith('--')).join(' ')}" -- "\$cur") )
4033
+ ;;
4034
+ esac
4035
+ }
4036
+ complete -F _cf_memory_mcp_complete cf-memory-mcp
4037
+ complete -F _cf_memory_mcp_complete cfm
4038
+ `);
4039
+ } else if (shell === 'zsh') {
4040
+ process.stdout.write(`# cf-memory-mcp zsh completion
4041
+ # Install: cf-memory-mcp completion zsh > "\${fpath[1]}/_cf-memory-mcp" && compinit
4042
+ # Or for the current shell: source <(cf-memory-mcp completion zsh)
4043
+ #compdef cf-memory-mcp cfm
4044
+ _cf_memory_mcp() {
4045
+ local -a commands
4046
+ commands=(
4047
+ ${commands.map(c => `'${c}:${c} command'`).join('\n ')}
4048
+ )
4049
+ if (( CURRENT == 2 )); then
4050
+ _describe 'command' commands
4051
+ else
4052
+ case "\$words[2]" in
4053
+ resume|export) _files ;;
4054
+ import) _files -g '*.json' ;;
4055
+ esac
4056
+ fi
4057
+ }
4058
+ _cf_memory_mcp "\$@"
4059
+ `);
4060
+ } else if (shell === 'fish') {
4061
+ process.stdout.write(`# cf-memory-mcp fish completion
4062
+ # Install: cf-memory-mcp completion fish > ~/.config/fish/completions/cf-memory-mcp.fish
4063
+ ${commands.map(c => `complete -c cf-memory-mcp -n '__fish_use_subcommand' -a '${c}' -d '${c} command'`).join('\n')}
4064
+ ${commands.map(c => `complete -c cfm -n '__fish_use_subcommand' -a '${c}' -d '${c} command'`).join('\n')}
4065
+ complete -c cf-memory-mcp -l json -s j -d 'Emit JSON for scripts'
4066
+ complete -c cf-memory-mcp -l limit -s n -d 'Limit number of results'
4067
+ complete -c cf-memory-mcp -l md -d 'Write markdown to file'
4068
+ complete -c cf-memory-mcp -l force -s f -d 'Bypass duplicate detection'
4069
+ complete -c cf-memory-mcp -l help -s h -d 'Show help'
4070
+ complete -c cf-memory-mcp -l version -s v -d 'Show version'
4071
+ `);
4072
+ } else {
4073
+ process.stderr.write(`Unknown shell "${shell}". Supported: bash, zsh, fish.\n`);
4074
+ process.exit(1);
4075
+ }
4076
+ process.exit(0);
4077
+ }
4078
+
4079
+ // Per-command help texts. Used when "cf-memory-mcp <cmd> --help" is invoked.
4080
+ const PER_COMMAND_HELP = {
4081
+ resume: `cf-memory-mcp resume [<session-id-prefix>] [--md path] [--json]
4082
+ Print the prior resume handoff (markdown by default).
4083
+ <session-id-prefix> Optional: pick a specific session (>=8 char prefix or full UUID).
4084
+ --md <path> Write the markdown to a file instead of stdout.
4085
+ --json, -j Emit the full bootstrap payload as JSON for scripts.
4086
+ Exit codes: 0 = handoff found, 3 = no handoff found.`,
4087
+ list: `cf-memory-mcp list [--limit N] [--json]
4088
+ List recent handoffs for the current cwd, status-ranked.
4089
+ --limit N, -n N Max number of entries (default 5, max 50).
4090
+ --json, -j Emit a JSON array for scripts.`,
4091
+ checkpoint: `cf-memory-mcp checkpoint ["<goal>"] [--force] [--json]
4092
+ Snapshot current state to a fresh handoff with keep_open:true. The
4093
+ session stays active for future checkpoints. The final end_session (or
4094
+ bridge shutdown) finalizes.
4095
+ <goal> Explicit goal string. Defaults to synthesized.
4096
+ --force, -f Bypass duplicate-session detection.
4097
+ --json, -j Emit a JSON status object.
4098
+ Exit codes: 0 = saved, 2 = not stored, 4 = duplicate detected.`,
4099
+ status: `cf-memory-mcp status [--json]
4100
+ Show bridge + server state for the current cwd: version, repo/branch,
4101
+ disk-cache age, server resume availability, and recent-handoff count.
4102
+ --json, -j Emit a JSON status object.`,
4103
+ clean: `cf-memory-mcp clean [--all] [--json]
4104
+ Delete the local disk cache for the current cwd.
4105
+ --all Delete ALL cf-memory disk caches.
4106
+ --json, -j Emit a JSON list of removed paths.`,
4107
+ export: `cf-memory-mcp export <session-id-or-prefix> [--md path]
4108
+ Print a handoff as a JSON bundle to stdout (or write to file). For
4109
+ backup or cross-machine sync.
4110
+ <session-id> Full UUID or short prefix (>=8 chars).
4111
+ --md <path> Write the JSON to a file.`,
4112
+ import: `cf-memory-mcp import [<file>|-] [--json]
4113
+ Restore a handoff bundle into a NEW session (keep_open). Cross-machine
4114
+ sync. Use "-" to read from stdin.
4115
+ <file> Bundle file path; "-" for stdin.
4116
+ --json, -j Emit a JSON status object.`,
4117
+ doctor: `cf-memory-mcp doctor [--json]
4118
+ Diagnose common setup issues. Checks API key, git repo/branch, disk-
4119
+ cache writability, worker reachability, project indexing, resume
4120
+ availability. Exit nonzero if any check fails.
4121
+ --json, -j Emit a JSON list of checks.`,
4122
+ completion: `cf-memory-mcp completion [bash|zsh|fish]
4123
+ Output shell completion script. Pipe to your shell's completion dir.`,
4124
+ };
4125
+
4126
+ function printPerCommandHelp(cmd) {
4127
+ const help = PER_COMMAND_HELP[cmd];
4128
+ if (help) {
4129
+ process.stdout.write(help + '\n');
4130
+ process.exit(0);
4131
+ }
4132
+ }
4133
+
4006
4134
  async function runDoctorCli() {
4007
4135
  const { flags } = parseCliArgs(process.argv.slice(3));
4008
4136
  const server = new CFMemoryMCP();
4009
4137
  server.logDebug = () => {};
4010
4138
  const checks = [];
4011
- const add = (label, ok, detail) => checks.push({ label, ok, detail });
4139
+ const add = (label, ok, detail, fix) => checks.push({ label, ok, detail, ...(fix && !ok ? { fix } : {}) });
4012
4140
 
4013
4141
  // 1. API key set?
4014
- add('CF_MEMORY_API_KEY set', !!API_KEY, API_KEY ? '(redacted)' : 'unset — most commands will fail');
4142
+ add('CF_MEMORY_API_KEY set', !!API_KEY,
4143
+ API_KEY ? '(redacted)' : 'unset — most commands will fail',
4144
+ 'export CF_MEMORY_API_KEY=<your-key> # get one at https://memcp.ai');
4015
4145
 
4016
4146
  // 2. Cwd is in a git repo?
4017
4147
  const meta = server.getRepoMetadata();
4018
- add('git repo detected', !!meta.repo_path, meta.repo_path || 'no .git in cwd; resume metadata will be empty');
4019
- add('git branch detected', !!meta.branch, meta.branch || 'detached HEAD or no commits');
4148
+ add('git repo detected', !!meta.repo_path,
4149
+ meta.repo_path || 'no .git in cwd; resume metadata will be empty',
4150
+ 'cd into a repo, or run: git init');
4151
+ add('git branch detected', !!meta.branch,
4152
+ meta.branch || 'detached HEAD or no commits',
4153
+ meta.repo_path ? 'git checkout -b main # or commit something first' : null);
4020
4154
 
4021
4155
  // 3. Disk cache writable?
4022
4156
  const cachePath = server.getDiskCachePath();
@@ -4030,7 +4164,8 @@ async function runDoctorCli() {
4030
4164
  fs.unlinkSync(probe);
4031
4165
  diskWritable = true;
4032
4166
  } catch (err) {
4033
- add('disk cache writable', false, `failed: ${err.message}`);
4167
+ add('disk cache writable', false, `failed: ${err.message}`,
4168
+ `chmod -R u+w ${path.dirname(cachePath)} # or set CF_MEMORY_DISK_CACHE=off to disable`);
4034
4169
  }
4035
4170
  }
4036
4171
  if (diskWritable) add('disk cache writable', true, path.dirname(cachePath));
@@ -4048,14 +4183,18 @@ async function runDoctorCli() {
4048
4183
  workerReachable = !res?.error;
4049
4184
  workerMs = Date.now() - t0;
4050
4185
  } catch (_) { /* unreachable */ }
4051
- add('worker reachable', workerReachable, workerReachable ? `${workerMs}ms` : `failed`);
4186
+ add('worker reachable', workerReachable,
4187
+ workerReachable ? `${workerMs}ms` : `failed`,
4188
+ `curl -I ${BASE_URL}/health # check the worker URL and your network`);
4052
4189
 
4053
4190
  // 5. Project indexed?
4054
4191
  if (workerReachable) {
4055
4192
  const fake = { params: { name: 'retrieve_context', arguments: {} } };
4056
4193
  await server.maybeFillProjectId(fake);
4057
4194
  const pid = fake.params.arguments.project_id;
4058
- add('project indexed', !!pid, pid || 'no project matched cwd — run index_project to enable retrieve_context');
4195
+ add('project indexed', !!pid,
4196
+ pid || 'no project matched cwd — run index_project to enable retrieve_context',
4197
+ 'In your MCP client: call index_project({project_path:"' + (meta.repo_path || process.cwd()) + '"})');
4059
4198
 
4060
4199
  // 6. Resume handoff available?
4061
4200
  if (meta.repo_path) {
@@ -4073,7 +4212,8 @@ async function runDoctorCli() {
4073
4212
  add('resume handoff available', hasHandoff,
4074
4213
  hasHandoff
4075
4214
  ? `${(probePayload.resume_handoff.session_id||'').slice(0,8)} (${probePayload.resume_handoff.handoff_age_minutes}m old)`
4076
- : 'none for this context');
4215
+ : 'none for this context',
4216
+ 'cf-memory-mcp checkpoint "what you are working on" # or end_session({handoff:...}) in your MCP client');
4077
4217
  } catch (_) { /* skip */ }
4078
4218
  }
4079
4219
  }
@@ -4089,9 +4229,12 @@ async function runDoctorCli() {
4089
4229
  const mark = c.ok ? '✓' : '✗';
4090
4230
  if (!c.ok) anyFailed = true;
4091
4231
  process.stdout.write(` ${mark} ${c.label.padEnd(28)} ${c.detail || ''}\n`);
4232
+ if (!c.ok && c.fix) {
4233
+ process.stdout.write(` → ${c.fix}\n`);
4234
+ }
4092
4235
  }
4093
4236
  process.stdout.write('\n');
4094
- process.stdout.write(anyFailed ? 'Some checks failed. See details above.\n' : 'All checks passed.\n');
4237
+ process.stdout.write(anyFailed ? 'Some checks failed. See suggestions above.\n' : 'All checks passed.\n');
4095
4238
  process.exit(anyFailed ? 1 : 0);
4096
4239
  }
4097
4240
 
@@ -4498,6 +4641,13 @@ async function runCheckpointCli() {
4498
4641
  }
4499
4642
  }
4500
4643
 
4644
+ // Per-command --help: intercept BEFORE any subcommand dispatch so the
4645
+ // dispatched function doesn't see --help as a positional arg.
4646
+ if (process.argv[2] && process.argv.slice(3).some(a => a === '--help' || a === '-h')) {
4647
+ printPerCommandHelp(process.argv[2]);
4648
+ // If not a known command, fall through to general help.
4649
+ }
4650
+
4501
4651
  if (process.argv[2] === 'resume') {
4502
4652
  runResumeCli();
4503
4653
  return;
@@ -4538,6 +4688,11 @@ if (process.argv[2] === 'doctor') {
4538
4688
  return;
4539
4689
  }
4540
4690
 
4691
+ if (process.argv[2] === 'completion') {
4692
+ runCompletionCli();
4693
+ return;
4694
+ }
4695
+
4541
4696
  if (process.argv.includes('--diagnose')) {
4542
4697
  (async () => {
4543
4698
  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.28.0",
3
+ "version": "3.29.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": {