cf-memory-mcp 3.37.0 → 3.39.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 +95 -1
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -66,6 +66,32 @@ const STREAMABLE_HTTP_URL = `${BASE_URL}/mcp`;
|
|
|
66
66
|
const LEGACY_SERVER_URL = `${BASE_URL}/mcp/message`;
|
|
67
67
|
const PROGRESS_SSE_URL = `${BASE_URL}/api/indexing/progress`;
|
|
68
68
|
const PACKAGE_VERSION = require('../package.json').version;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Fetch the latest version of cf-memory-mcp from the npm registry.
|
|
72
|
+
* Returns the latest version string, or null on timeout/error.
|
|
73
|
+
* Used by `doctor` to flag outdated installs. Bounded by timeoutMs
|
|
74
|
+
* so an unreachable registry doesn't hang the doctor command.
|
|
75
|
+
*/
|
|
76
|
+
function checkLatestNpmVersion(currentVersion, timeoutMs = 1500) {
|
|
77
|
+
return new Promise((resolve) => {
|
|
78
|
+
const req = https.get('https://registry.npmjs.org/cf-memory-mcp/latest', {
|
|
79
|
+
timeout: timeoutMs,
|
|
80
|
+
headers: { 'Accept': 'application/json', 'User-Agent': `cf-memory-mcp/${currentVersion}` },
|
|
81
|
+
}, (res) => {
|
|
82
|
+
let body = '';
|
|
83
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
84
|
+
res.on('end', () => {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(body);
|
|
87
|
+
resolve(parsed.version || null);
|
|
88
|
+
} catch (_) { resolve(null); }
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
req.on('error', () => resolve(null));
|
|
92
|
+
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
93
|
+
});
|
|
94
|
+
}
|
|
69
95
|
// Default per-request timeout. Batch uploads use BATCH_TIMEOUT_MS below.
|
|
70
96
|
const TIMEOUT_MS = 60000;
|
|
71
97
|
// Batch uploads can take longer because the worker processes each file
|
|
@@ -3886,6 +3912,8 @@ function parseCliArgs(rest) {
|
|
|
3886
3912
|
flags.blockers_only = true;
|
|
3887
3913
|
} else if (a === '--chain') {
|
|
3888
3914
|
flags.chain = true;
|
|
3915
|
+
} else if (a === '--validate') {
|
|
3916
|
+
flags.validate = true;
|
|
3889
3917
|
} else if (a === '--older-than') {
|
|
3890
3918
|
// Accept "7d" / "30d" / "12h" / raw number (days).
|
|
3891
3919
|
const raw = rest[++i] || '';
|
|
@@ -4092,6 +4120,56 @@ async function runResumeCli() {
|
|
|
4092
4120
|
process.exit(0);
|
|
4093
4121
|
}
|
|
4094
4122
|
|
|
4123
|
+
// --validate: verify the handoff's file references still exist
|
|
4124
|
+
// on disk. Resolves each path relative to the handoff's repo_path
|
|
4125
|
+
// (or cwd). Reports per-path status. Useful before resuming to
|
|
4126
|
+
// catch "the file was moved or deleted since the handoff".
|
|
4127
|
+
if (flags.validate) {
|
|
4128
|
+
if (!found) {
|
|
4129
|
+
process.stderr.write('No resume handoff available to validate.\n');
|
|
4130
|
+
process.exit(3);
|
|
4131
|
+
}
|
|
4132
|
+
const handoff = payload.resume_handoff.handoff;
|
|
4133
|
+
const repoRoot = handoff.repo_path || process.env.CF_MEMORY_WATCH_PATH || process.cwd();
|
|
4134
|
+
const results = [];
|
|
4135
|
+
const checkPath = (relPath, kind) => {
|
|
4136
|
+
try {
|
|
4137
|
+
const full = path.isAbsolute(relPath) ? relPath : path.join(repoRoot, relPath);
|
|
4138
|
+
const exists = fs.existsSync(full);
|
|
4139
|
+
results.push({ kind, path: relPath, exists });
|
|
4140
|
+
} catch (_) {
|
|
4141
|
+
results.push({ kind, path: relPath, exists: false });
|
|
4142
|
+
}
|
|
4143
|
+
};
|
|
4144
|
+
for (const f of (handoff.files_touched || [])) checkPath(f.path, 'touched');
|
|
4145
|
+
for (const a of (handoff.code_anchors || [])) checkPath(a.file_path, 'anchor');
|
|
4146
|
+
const missing = results.filter(r => !r.exists);
|
|
4147
|
+
|
|
4148
|
+
if (flags.json) {
|
|
4149
|
+
process.stdout.write(JSON.stringify({
|
|
4150
|
+
repo_root: repoRoot,
|
|
4151
|
+
total: results.length,
|
|
4152
|
+
missing_count: missing.length,
|
|
4153
|
+
results,
|
|
4154
|
+
}, null, 2) + '\n');
|
|
4155
|
+
process.exit(missing.length === 0 ? 0 : 4);
|
|
4156
|
+
}
|
|
4157
|
+
process.stdout.write(`Validating ${results.length} file reference${results.length === 1 ? '' : 's'} against ${repoRoot}:\n\n`);
|
|
4158
|
+
for (const r of results) {
|
|
4159
|
+
const mark = r.exists ? '✓' : '✗';
|
|
4160
|
+
process.stdout.write(` ${mark} [${r.kind}] ${r.path}\n`);
|
|
4161
|
+
}
|
|
4162
|
+
process.stdout.write(`\n`);
|
|
4163
|
+
if (missing.length === 0) {
|
|
4164
|
+
process.stdout.write(`All ${results.length} references exist.\n`);
|
|
4165
|
+
process.exit(0);
|
|
4166
|
+
} else {
|
|
4167
|
+
process.stdout.write(`${missing.length} of ${results.length} references are missing.\n`);
|
|
4168
|
+
process.stdout.write(`The repo has moved or these files were deleted since the handoff was written.\n`);
|
|
4169
|
+
process.exit(4);
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4095
4173
|
// --md <path>: write the rendered markdown to a file instead of
|
|
4096
4174
|
// (or in addition to) stdout. Useful for piping to a markdown
|
|
4097
4175
|
// viewer or saving to the project.
|
|
@@ -4566,8 +4644,10 @@ const PER_COMMAND_HELP = {
|
|
|
4566
4644
|
--anchors-only code_anchors as "file:lines symbol".
|
|
4567
4645
|
--decisions-only decisions, one per line.
|
|
4568
4646
|
--blockers-only open blockers, one per line.
|
|
4647
|
+
--chain Walk parent_session_id back; show the thread history.
|
|
4648
|
+
--validate Check that files_touched + code_anchors still exist locally.
|
|
4569
4649
|
--json, -j Full bootstrap payload as JSON.
|
|
4570
|
-
Exit codes: 0 = found, 3 = no handoff / no data.`,
|
|
4650
|
+
Exit codes: 0 = found, 3 = no handoff / no data, 4 = --validate found missing files.`,
|
|
4571
4651
|
list: `cf-memory-mcp list [--status S] [--since ISO] [--repo PATH] [--limit N] [--json]
|
|
4572
4652
|
List recent handoffs for the current cwd, status-ranked. Header shows
|
|
4573
4653
|
a status-count summary.
|
|
@@ -4648,6 +4728,20 @@ async function runDoctorCli() {
|
|
|
4648
4728
|
const checks = [];
|
|
4649
4729
|
const add = (label, ok, detail, fix) => checks.push({ label, ok, detail, ...(fix && !ok ? { fix } : {}) });
|
|
4650
4730
|
|
|
4731
|
+
// 0. Installed vs latest npm version. Best-effort: skipped on
|
|
4732
|
+
// network failure or when registry is unreachable. Doesn't add to
|
|
4733
|
+
// exit-code failures so doctor still passes if you're just behind.
|
|
4734
|
+
try {
|
|
4735
|
+
const latest = await checkLatestNpmVersion(PACKAGE_VERSION, 1500);
|
|
4736
|
+
if (latest && latest !== PACKAGE_VERSION) {
|
|
4737
|
+
add(`npm version current`, false,
|
|
4738
|
+
`installed v${PACKAGE_VERSION}, latest v${latest}`,
|
|
4739
|
+
`npm install -g cf-memory-mcp@latest # or: npx cf-memory-mcp@${latest}`);
|
|
4740
|
+
} else if (latest) {
|
|
4741
|
+
add(`npm version current`, true, `v${PACKAGE_VERSION} (latest)`);
|
|
4742
|
+
}
|
|
4743
|
+
} catch (_) { /* network failure or registry timeout — skip */ }
|
|
4744
|
+
|
|
4651
4745
|
// 1. API key set?
|
|
4652
4746
|
add('CF_MEMORY_API_KEY set', !!API_KEY,
|
|
4653
4747
|
API_KEY ? '(redacted)' : 'unset — most commands will fail',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.39.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": {
|