cf-memory-mcp 3.64.0 → 3.65.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 +82 -5
- package/package.json +1 -1
package/bin/cf-memory-mcp.js
CHANGED
|
@@ -4710,6 +4710,62 @@ async function runResumeCli() {
|
|
|
4710
4710
|
} else {
|
|
4711
4711
|
process.stdout.write(JSON.stringify(payload.resume_handoff, null, 2) + '\n');
|
|
4712
4712
|
}
|
|
4713
|
+
// Branch state: if the handoff's repo matches cwd and there
|
|
4714
|
+
// are uncommitted changes (especially in files_touched),
|
|
4715
|
+
// surface them so the agent knows work was interrupted mid-
|
|
4716
|
+
// edit. Quiet when the tree is clean to avoid noise. Skip
|
|
4717
|
+
// entirely when env var disables it.
|
|
4718
|
+
if (process.env.CF_MEMORY_BRANCH_STATE !== 'off') {
|
|
4719
|
+
try {
|
|
4720
|
+
const meta = server.getRepoMetadata();
|
|
4721
|
+
const handoffRepo = payload.resume_handoff?.handoff?.repo_path
|
|
4722
|
+
|| payload.resume_handoff?.repo_path;
|
|
4723
|
+
if (meta.repo_path && handoffRepo && meta.repo_path === handoffRepo) {
|
|
4724
|
+
const { execSync } = require('child_process');
|
|
4725
|
+
const dirty = execSync('git status --porcelain', { cwd: meta.repo_path, encoding: 'utf8', timeout: 2000 })
|
|
4726
|
+
.split('\n').filter(Boolean);
|
|
4727
|
+
if (dirty.length > 0) {
|
|
4728
|
+
const filesTouched = Array.isArray(payload.resume_handoff?.handoff?.files_touched)
|
|
4729
|
+
? payload.resume_handoff.handoff.files_touched
|
|
4730
|
+
.map(ft => typeof ft === 'string' ? ft : ft?.path)
|
|
4731
|
+
.filter(Boolean)
|
|
4732
|
+
: [];
|
|
4733
|
+
const inHandoff = new Set(filesTouched);
|
|
4734
|
+
const matched = dirty.filter(line => {
|
|
4735
|
+
const p = line.slice(3);
|
|
4736
|
+
return inHandoff.has(p);
|
|
4737
|
+
});
|
|
4738
|
+
const otherCount = dirty.length - matched.length;
|
|
4739
|
+
process.stdout.write('\n### Branch state (since handoff was written)\n');
|
|
4740
|
+
if (matched.length > 0) {
|
|
4741
|
+
process.stdout.write(`Mid-edit on ${matched.length} of your files_touched:\n`);
|
|
4742
|
+
for (const line of matched.slice(0, 8)) {
|
|
4743
|
+
process.stdout.write(` ${line}\n`);
|
|
4744
|
+
}
|
|
4745
|
+
if (matched.length > 8) {
|
|
4746
|
+
process.stdout.write(` ... and ${matched.length - 8} more\n`);
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
if (otherCount > 0) {
|
|
4750
|
+
process.stdout.write(`Plus ${otherCount} other uncommitted file${otherCount === 1 ? '' : 's'} in the tree (run \`git status\` for full list).\n`);
|
|
4751
|
+
}
|
|
4752
|
+
// Also check if HEAD has advanced past the handoff time.
|
|
4753
|
+
try {
|
|
4754
|
+
const handoffTime = payload.resume_handoff?.ended_at
|
|
4755
|
+
|| payload.resume_handoff?.started_at;
|
|
4756
|
+
if (handoffTime) {
|
|
4757
|
+
const since = `--since="${handoffTime}"`;
|
|
4758
|
+
const newCommits = execSync(`git log ${since} --oneline 2>/dev/null | wc -l`, { cwd: meta.repo_path, encoding: 'utf8', timeout: 2000, shell: '/bin/sh' }).trim();
|
|
4759
|
+
const n = parseInt(newCommits, 10);
|
|
4760
|
+
if (Number.isFinite(n) && n > 0) {
|
|
4761
|
+
process.stdout.write(`${n} commit${n === 1 ? '' : 's'} on this branch since handoff (\`git log --since="${handoffTime}"\` to see them).\n`);
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
} catch (_) { /* commit-count is best-effort */ }
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
} catch (_) { /* git unavailable or non-repo — silent */ }
|
|
4768
|
+
}
|
|
4713
4769
|
// --include-chain N: walk parent_session_id back N times and
|
|
4714
4770
|
// append each parent's resume_prompt inline so the agent sees
|
|
4715
4771
|
// the full thread arc in one output.
|
|
@@ -4737,12 +4793,32 @@ async function runResumeCli() {
|
|
|
4737
4793
|
}
|
|
4738
4794
|
}
|
|
4739
4795
|
if (Array.isArray(payload.recent_handoffs) && payload.recent_handoffs.length > 1) {
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4796
|
+
// Dedupe: skip the primary handoff (already shown) and
|
|
4797
|
+
// collapse near-duplicate auto-checkpoints — entries that
|
|
4798
|
+
// share normalized (goal, branch, status). Keep the most
|
|
4799
|
+
// recent occurrence of each unique key. This removes
|
|
4800
|
+
// visible noise from 30+ in_progress sessions all named
|
|
4801
|
+
// "Re-verify enrichment+freshness" on the same branch.
|
|
4802
|
+
const primaryId = payload.resume_handoff?.session_id;
|
|
4803
|
+
const norm = (s) => (s || '').toLowerCase().replace(/\s+/g, ' ').trim();
|
|
4804
|
+
const seen = new Set();
|
|
4805
|
+
const unique = [];
|
|
4806
|
+
for (const h of payload.recent_handoffs) {
|
|
4807
|
+
if (h.session_id === primaryId) continue;
|
|
4808
|
+
const key = `${norm(h.goal)}|${norm(h.branch)}|${h.status || ''}`;
|
|
4809
|
+
if (seen.has(key)) continue;
|
|
4810
|
+
seen.add(key);
|
|
4811
|
+
unique.push(h);
|
|
4812
|
+
if (unique.length >= 4) break;
|
|
4813
|
+
}
|
|
4814
|
+
if (unique.length > 0) {
|
|
4815
|
+
process.stdout.write('\n---\nOther recent handoffs:\n');
|
|
4816
|
+
for (const h of unique) {
|
|
4817
|
+
const shortId = (h.session_id || '').slice(0, 8);
|
|
4818
|
+
process.stdout.write(` ${shortId} [${h.status || '?'}] ${h.goal || ''}\n`);
|
|
4819
|
+
}
|
|
4820
|
+
process.stdout.write(`(Pass any short id as: npx cf-memory-mcp resume <id>)\n`);
|
|
4744
4821
|
}
|
|
4745
|
-
process.stdout.write(`(Pass any short id as: npx cf-memory-mcp resume <id>)\n`);
|
|
4746
4822
|
}
|
|
4747
4823
|
process.exit(0);
|
|
4748
4824
|
} else {
|
|
@@ -5480,6 +5556,7 @@ function runEnvCli() {
|
|
|
5480
5556
|
['CF_MEMORY_SHUTDOWN_HANDOFF', 'default: on; "off" disables the SIGINT/SIGTERM handoff flush'],
|
|
5481
5557
|
['CF_MEMORY_PREWARM_RESUME', 'default: on; "off" disables the background resume prewarm at bridge startup'],
|
|
5482
5558
|
['CF_MEMORY_RESUME_DIFF', 'default: on; "off" disables git-diff injection into resume responses'],
|
|
5559
|
+
['CF_MEMORY_BRANCH_STATE', 'default: on; "off" disables the "Branch state (since handoff was written)" block in `cfm resume`'],
|
|
5483
5560
|
['CF_MEMORY_DISK_CACHE', 'default: on; "off" disables ~/.cf-memory/handoff-*.json disk caching'],
|
|
5484
5561
|
['CF_MEMORY_NO_RETRY', 'default: off; "1" disables the single retry-on-transient-failure'],
|
|
5485
5562
|
['CF_MEMORY_LOG', 'default: off; "1" writes DEBUG/ERROR lines to ~/.cf-memory/bridge.log'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-memory-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.65.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": {
|