cf-memory-mcp 3.42.0 → 3.44.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 +198 -6
- 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,10 @@ 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;
|
|
3970
|
+
} else if (a === '--short') {
|
|
3971
|
+
flags.short = true;
|
|
3967
3972
|
} else if (a === '--older-than') {
|
|
3968
3973
|
// Accept "7d" / "30d" / "12h" / raw number (days).
|
|
3969
3974
|
const raw = rest[++i] || '';
|
|
@@ -4126,6 +4131,37 @@ async function runResumeCli() {
|
|
|
4126
4131
|
process.exit(0);
|
|
4127
4132
|
}
|
|
4128
4133
|
|
|
4134
|
+
// --short: single line for tmux/status bars. "goal · status"
|
|
4135
|
+
// truncated to terminal-friendly length.
|
|
4136
|
+
if (flags.short) {
|
|
4137
|
+
const envelope = payload.resume_handoff;
|
|
4138
|
+
if (!envelope) process.exit(3);
|
|
4139
|
+
const h = envelope.handoff || {};
|
|
4140
|
+
const goal = (h.goal || '(no goal)').slice(0, 60);
|
|
4141
|
+
const status = h.status || '?';
|
|
4142
|
+
const stale = envelope.stale ? ' [STALE]' : '';
|
|
4143
|
+
process.stdout.write(`${goal} · ${status}${stale}\n`);
|
|
4144
|
+
process.exit(0);
|
|
4145
|
+
}
|
|
4146
|
+
|
|
4147
|
+
// --card: compact 2-3 line summary card for status widgets.
|
|
4148
|
+
// Format: [status · age · q=score] goal / → next_step
|
|
4149
|
+
if (flags.card) {
|
|
4150
|
+
const envelope = payload.resume_handoff;
|
|
4151
|
+
if (!envelope) process.exit(3);
|
|
4152
|
+
const h = envelope.handoff || {};
|
|
4153
|
+
const ageMin = envelope.handoff_age_minutes;
|
|
4154
|
+
const fmtAge = (m) => m == null ? '?' : m < 60 ? `${m}m` : m < 1440 ? `${Math.round(m/60)}h` : `${Math.round(m/1440)}d`;
|
|
4155
|
+
const status = h.status || '?';
|
|
4156
|
+
const q = typeof envelope.quality_score === 'number' ? ` · q=${envelope.quality_score}` : '';
|
|
4157
|
+
const staleMarker = envelope.stale ? ' · STALE' : '';
|
|
4158
|
+
process.stdout.write(`[${status} · ${fmtAge(ageMin)} ago${q}${staleMarker}]\n`);
|
|
4159
|
+
process.stdout.write(`${h.goal || '(no goal)'}\n`);
|
|
4160
|
+
const next = h.next_steps?.[0];
|
|
4161
|
+
if (next) process.stdout.write(`→ ${next}\n`);
|
|
4162
|
+
process.exit(0);
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4129
4165
|
// --chain: walk parent_session_id back through the thread history.
|
|
4130
4166
|
// Bounded at 20 iterations to avoid an infinite loop on malformed
|
|
4131
4167
|
// data. Prints each handoff as "<id> [age] status — goal".
|
|
@@ -4383,6 +4419,95 @@ async function runListCli() {
|
|
|
4383
4419
|
}
|
|
4384
4420
|
}
|
|
4385
4421
|
|
|
4422
|
+
async function runLinkCli() {
|
|
4423
|
+
if (!API_KEY) {
|
|
4424
|
+
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
4425
|
+
process.exit(1);
|
|
4426
|
+
}
|
|
4427
|
+
const { positional, flags } = parseCliArgs(process.argv.slice(3));
|
|
4428
|
+
const childArg = positional[0];
|
|
4429
|
+
// --parent <id> is parsed positionally too; grab it from process.argv.
|
|
4430
|
+
let parentId = null;
|
|
4431
|
+
const parentIdx = process.argv.indexOf('--parent');
|
|
4432
|
+
if (parentIdx !== -1 && process.argv[parentIdx + 1]) parentId = process.argv[parentIdx + 1];
|
|
4433
|
+
for (const a of process.argv) {
|
|
4434
|
+
if (a.startsWith('--parent=')) parentId = a.slice('--parent='.length);
|
|
4435
|
+
}
|
|
4436
|
+
if (!childArg || !parentId) {
|
|
4437
|
+
console.error('Usage: cf-memory-mcp link <child-id-or-prefix> --parent <parent-id-or-prefix>');
|
|
4438
|
+
process.exit(1);
|
|
4439
|
+
}
|
|
4440
|
+
const server = new CFMemoryMCP();
|
|
4441
|
+
server.logDebug = () => {};
|
|
4442
|
+
try {
|
|
4443
|
+
// Resolve child + parent prefixes to full UUIDs via get_context_bootstrap.
|
|
4444
|
+
const resolveId = async (idHint) => {
|
|
4445
|
+
if (idHint.length >= 36) return idHint;
|
|
4446
|
+
const r = await server.makeRequest({
|
|
4447
|
+
jsonrpc: '2.0', id: `cli-link-resolve-${Date.now()}`,
|
|
4448
|
+
method: 'tools/call',
|
|
4449
|
+
params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: idHint } },
|
|
4450
|
+
});
|
|
4451
|
+
const t = r?.result?.content?.[0]?.text;
|
|
4452
|
+
const p = JSON.parse(t || '{}');
|
|
4453
|
+
return p.resume_handoff?.session_id || null;
|
|
4454
|
+
};
|
|
4455
|
+
const fullChild = await resolveId(childArg);
|
|
4456
|
+
const fullParent = await resolveId(parentId);
|
|
4457
|
+
if (!fullChild) {
|
|
4458
|
+
process.stderr.write(`Could not resolve child "${childArg}" to a session.\n`);
|
|
4459
|
+
process.exit(3);
|
|
4460
|
+
}
|
|
4461
|
+
if (!fullParent) {
|
|
4462
|
+
process.stderr.write(`Could not resolve parent "${parentId}" to a session.\n`);
|
|
4463
|
+
process.exit(3);
|
|
4464
|
+
}
|
|
4465
|
+
// Fetch current child handoff, set parent_session_id, write back via end_session keep_open.
|
|
4466
|
+
const childRes = await server.makeRequest({
|
|
4467
|
+
jsonrpc: '2.0', id: `cli-link-fetch-${Date.now()}`,
|
|
4468
|
+
method: 'tools/call',
|
|
4469
|
+
params: { name: 'get_context_bootstrap', arguments: { resume: true, session_id_hint: fullChild } },
|
|
4470
|
+
});
|
|
4471
|
+
const childText = childRes?.result?.content?.[0]?.text;
|
|
4472
|
+
const childPayload = JSON.parse(childText || '{}');
|
|
4473
|
+
const handoff = childPayload.resume_handoff?.handoff;
|
|
4474
|
+
if (!handoff) {
|
|
4475
|
+
process.stderr.write(`Child session has no handoff stored; cannot link.\n`);
|
|
4476
|
+
process.exit(3);
|
|
4477
|
+
}
|
|
4478
|
+
// Update with parent_session_id.
|
|
4479
|
+
const updated = { ...handoff, parent_session_id: fullParent };
|
|
4480
|
+
const updateRes = await server.makeRequest({
|
|
4481
|
+
jsonrpc: '2.0', id: `cli-link-update-${Date.now()}`,
|
|
4482
|
+
method: 'tools/call',
|
|
4483
|
+
params: { name: 'end_session', arguments: {
|
|
4484
|
+
session_id: fullChild,
|
|
4485
|
+
keep_open: true, // don't accidentally finalize
|
|
4486
|
+
handoff: updated,
|
|
4487
|
+
} },
|
|
4488
|
+
});
|
|
4489
|
+
const updateText = updateRes?.result?.content?.[0]?.text;
|
|
4490
|
+
const updatePayload = JSON.parse(updateText || '{}');
|
|
4491
|
+
if (flags.json) {
|
|
4492
|
+
process.stdout.write(JSON.stringify({
|
|
4493
|
+
child: fullChild,
|
|
4494
|
+
parent: fullParent,
|
|
4495
|
+
handoff_stored: !!updatePayload.handoff_stored,
|
|
4496
|
+
}, null, 2) + '\n');
|
|
4497
|
+
process.exit(updatePayload.handoff_stored ? 0 : 2);
|
|
4498
|
+
}
|
|
4499
|
+
if (updatePayload.handoff_stored) {
|
|
4500
|
+
process.stdout.write(`Linked ${fullChild.slice(0,8)} → parent ${fullParent.slice(0,8)}\n`);
|
|
4501
|
+
process.exit(0);
|
|
4502
|
+
}
|
|
4503
|
+
process.stderr.write(`Update failed: ${updateText}\n`);
|
|
4504
|
+
process.exit(2);
|
|
4505
|
+
} catch (err) {
|
|
4506
|
+
console.error('link command failed:', err.message);
|
|
4507
|
+
process.exit(1);
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
|
|
4386
4511
|
async function runHistoryCli() {
|
|
4387
4512
|
if (!API_KEY) {
|
|
4388
4513
|
console.error('Error: CF_MEMORY_API_KEY environment variable is required');
|
|
@@ -4640,10 +4765,41 @@ function runEnvCli() {
|
|
|
4640
4765
|
|
|
4641
4766
|
function runCompletionCli() {
|
|
4642
4767
|
const shell = process.argv[3] || 'bash';
|
|
4643
|
-
const
|
|
4768
|
+
const install = process.argv.includes('--install');
|
|
4769
|
+
const commands = ['resume', 'list', 'history', 'checkpoint', 'link', 'status', 'clean', 'export', 'import', 'delete', 'doctor', 'env', 'completion'];
|
|
4644
4770
|
const flags = ['--json', '-j', '--limit', '-n', '--md', '--all', '--force', '-f', '--version', '-v', '--help', '-h', '--diagnose'];
|
|
4771
|
+
|
|
4772
|
+
// Determine the install target for each shell. Use user-local paths
|
|
4773
|
+
// only (no sudo). Caller can override via stdout-redirect when
|
|
4774
|
+
// --install isn't used.
|
|
4775
|
+
const installTarget = (() => {
|
|
4776
|
+
const home = os.homedir();
|
|
4777
|
+
if (shell === 'bash') {
|
|
4778
|
+
// Prefer ~/.bash_completion.d/ if it exists; fall back to ~/.bash_completion.
|
|
4779
|
+
const dir = path.join(home, '.bash_completion.d');
|
|
4780
|
+
return fs.existsSync(dir) ? path.join(dir, 'cf-memory-mcp') : path.join(home, '.bash_completion');
|
|
4781
|
+
}
|
|
4782
|
+
if (shell === 'zsh') {
|
|
4783
|
+
// Honor $ZSH_CUSTOM/plugins or ~/.zsh/completions/
|
|
4784
|
+
const zdir = process.env.ZSH_CUSTOM
|
|
4785
|
+
? path.join(process.env.ZSH_CUSTOM, 'plugins', 'cf-memory-mcp')
|
|
4786
|
+
: path.join(home, '.zsh', 'completions');
|
|
4787
|
+
return path.join(zdir, '_cf-memory-mcp');
|
|
4788
|
+
}
|
|
4789
|
+
if (shell === 'fish') {
|
|
4790
|
+
return path.join(home, '.config', 'fish', 'completions', 'cf-memory-mcp.fish');
|
|
4791
|
+
}
|
|
4792
|
+
if (shell === 'powershell' || shell === 'pwsh') {
|
|
4793
|
+
return path.join(home, '.config', 'powershell', 'cf-memory-mcp.ps1');
|
|
4794
|
+
}
|
|
4795
|
+
return null;
|
|
4796
|
+
})();
|
|
4797
|
+
// Buffer the output so we can either print or write-to-disk.
|
|
4798
|
+
let output = '';
|
|
4799
|
+
const emit = (chunk) => { output += chunk; };
|
|
4800
|
+
|
|
4645
4801
|
if (shell === 'bash') {
|
|
4646
|
-
|
|
4802
|
+
emit(`# cf-memory-mcp bash completion
|
|
4647
4803
|
# Install: cf-memory-mcp completion bash > /usr/local/etc/bash_completion.d/cf-memory-mcp
|
|
4648
4804
|
# Or for the current shell: source <(cf-memory-mcp completion bash)
|
|
4649
4805
|
_cf_memory_mcp_complete() {
|
|
@@ -4665,7 +4821,7 @@ complete -F _cf_memory_mcp_complete cf-memory-mcp
|
|
|
4665
4821
|
complete -F _cf_memory_mcp_complete cfm
|
|
4666
4822
|
`);
|
|
4667
4823
|
} else if (shell === 'zsh') {
|
|
4668
|
-
|
|
4824
|
+
emit(`# cf-memory-mcp zsh completion
|
|
4669
4825
|
# Install: cf-memory-mcp completion zsh > "\${fpath[1]}/_cf-memory-mcp" && compinit
|
|
4670
4826
|
# Or for the current shell: source <(cf-memory-mcp completion zsh)
|
|
4671
4827
|
#compdef cf-memory-mcp cfm
|
|
@@ -4686,7 +4842,7 @@ _cf_memory_mcp() {
|
|
|
4686
4842
|
_cf_memory_mcp "\$@"
|
|
4687
4843
|
`);
|
|
4688
4844
|
} else if (shell === 'powershell' || shell === 'pwsh') {
|
|
4689
|
-
|
|
4845
|
+
emit(`# cf-memory-mcp PowerShell completion
|
|
4690
4846
|
# Install: cf-memory-mcp completion powershell | Out-String | Invoke-Expression
|
|
4691
4847
|
# To persist: add the above to your $PROFILE
|
|
4692
4848
|
Register-ArgumentCompleter -Native -CommandName cf-memory-mcp,cfm -ScriptBlock {
|
|
@@ -4706,7 +4862,7 @@ Register-ArgumentCompleter -Native -CommandName cf-memory-mcp,cfm -ScriptBlock {
|
|
|
4706
4862
|
}
|
|
4707
4863
|
`);
|
|
4708
4864
|
} else if (shell === 'fish') {
|
|
4709
|
-
|
|
4865
|
+
emit(`# cf-memory-mcp fish completion
|
|
4710
4866
|
# Install: cf-memory-mcp completion fish > ~/.config/fish/completions/cf-memory-mcp.fish
|
|
4711
4867
|
${commands.map(c => `complete -c cf-memory-mcp -n '__fish_use_subcommand' -a '${c}' -d '${c} command'`).join('\n')}
|
|
4712
4868
|
${commands.map(c => `complete -c cfm -n '__fish_use_subcommand' -a '${c}' -d '${c} command'`).join('\n')}
|
|
@@ -4721,6 +4877,31 @@ complete -c cf-memory-mcp -l version -s v -d 'Show version'
|
|
|
4721
4877
|
process.stderr.write(`Unknown shell "${shell}". Supported: bash, zsh, fish, powershell.\n`);
|
|
4722
4878
|
process.exit(1);
|
|
4723
4879
|
}
|
|
4880
|
+
|
|
4881
|
+
// Either install to a user-local path or print to stdout.
|
|
4882
|
+
if (install) {
|
|
4883
|
+
if (!installTarget) {
|
|
4884
|
+
process.stderr.write(`No install target for shell ${shell}.\n`);
|
|
4885
|
+
process.exit(1);
|
|
4886
|
+
}
|
|
4887
|
+
try {
|
|
4888
|
+
const dir = path.dirname(installTarget);
|
|
4889
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
4890
|
+
fs.writeFileSync(installTarget, output);
|
|
4891
|
+
process.stderr.write(`Installed ${shell} completion to ${installTarget}\n`);
|
|
4892
|
+
if (shell === 'bash') {
|
|
4893
|
+
process.stderr.write(`Add to ~/.bashrc to autoload: source ${installTarget}\n`);
|
|
4894
|
+
} else if (shell === 'zsh') {
|
|
4895
|
+
const dirToFpath = path.dirname(installTarget);
|
|
4896
|
+
process.stderr.write(`Add to ~/.zshrc:\n fpath=(${dirToFpath} $fpath)\n autoload -Uz compinit && compinit\n`);
|
|
4897
|
+
}
|
|
4898
|
+
} catch (err) {
|
|
4899
|
+
process.stderr.write(`Failed to install: ${err.message}\n`);
|
|
4900
|
+
process.exit(1);
|
|
4901
|
+
}
|
|
4902
|
+
} else {
|
|
4903
|
+
process.stdout.write(output);
|
|
4904
|
+
}
|
|
4724
4905
|
process.exit(0);
|
|
4725
4906
|
}
|
|
4726
4907
|
|
|
@@ -4731,6 +4912,7 @@ const PER_COMMAND_HELP = {
|
|
|
4731
4912
|
<session-id-prefix> Optional: pick a specific session (>=8 char prefix or full UUID).
|
|
4732
4913
|
--md <path> Write the markdown to a file instead of stdout.
|
|
4733
4914
|
--copy Pipe the markdown to the platform clipboard (pbcopy/xclip/wl-copy/clip).
|
|
4915
|
+
--card Compact 2-3 line status card (for terminal status widgets).
|
|
4734
4916
|
Extract flags (pick one; each exits 3 if the section is empty):
|
|
4735
4917
|
--next-only First next_step only (for shell prompts).
|
|
4736
4918
|
--next-steps All next_steps, numbered.
|
|
@@ -4806,6 +4988,11 @@ const PER_COMMAND_HELP = {
|
|
|
4806
4988
|
--repo PATH Override the cwd's repo.
|
|
4807
4989
|
--since ISO Lower bound on handoff timestamp.
|
|
4808
4990
|
--json, -j Emit JSON.`,
|
|
4991
|
+
link: `cf-memory-mcp link <child-id-or-prefix> --parent <parent-id-or-prefix> [--json]
|
|
4992
|
+
Retroactively set parent_session_id on a child session, linking it to
|
|
4993
|
+
a parent in the chain. Useful when you forgot --force on checkpoint
|
|
4994
|
+
or want to manually chain sessions across repos.
|
|
4995
|
+
--json, -j Emit a JSON status object.`,
|
|
4809
4996
|
};
|
|
4810
4997
|
|
|
4811
4998
|
function printPerCommandHelp(cmd) {
|
|
@@ -5414,6 +5601,11 @@ if (process.argv[2] === 'history') {
|
|
|
5414
5601
|
return;
|
|
5415
5602
|
}
|
|
5416
5603
|
|
|
5604
|
+
if (process.argv[2] === 'link') {
|
|
5605
|
+
runLinkCli();
|
|
5606
|
+
return;
|
|
5607
|
+
}
|
|
5608
|
+
|
|
5417
5609
|
if (process.argv.includes('--diagnose')) {
|
|
5418
5610
|
(async () => {
|
|
5419
5611
|
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.44.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": {
|