@claude-flow/cli 3.32.21 → 3.32.23
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/.claude/helpers/.helpers-version +1 -1
- package/.claude/helpers/helpers.manifest.json +2 -2
- package/.claude/proven-config.json +1 -1
- package/catalog-manifest.json +2 -2
- package/dist/src/commands/memory.js +9 -4
- package/dist/src/commands/swarm.js +23 -0
- package/dist/src/mcp-tools/hooks-tools.js +13 -2
- package/dist/src/services/memory-backup.js +45 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
3.32.
|
|
1
|
+
3.32.9
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.23",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "e3e1033b24704992ddef6b31c7fa9dd7fcd9e1af7935dd77ef73402b916b31e6",
|
|
6
6
|
"hook-handler.cjs": "f87ec28684bfc5fd0a54c46bd2a53a3fb037defe71d0ea4b8a5cb88a2cd87a3f",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"statusline.cjs": "10f74a1aa9af217d0623c0a9839d82825b0eed31a4707a7531a85c6116869a6c"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"signature": "/
|
|
11
|
+
"signature": "8EdHRlBpW8Om3t9dixEctCh/RW66gA+IIlo3YxKvRnJYbyeHrV48tSCJqaNAlGgaksGIFqQtzfMjM5LyeZY/BA==",
|
|
12
12
|
"algorithm": "ed25519"
|
|
13
13
|
}
|
package/catalog-manifest.json
CHANGED
|
@@ -78,10 +78,13 @@ const storeCommand = {
|
|
|
78
78
|
// on the value BEFORE persistence and refuse the write if a
|
|
79
79
|
// finding is present. Opt-in per-call; RUFLO_MEMORY_SCAN_ON_WRITE=1
|
|
80
80
|
// enables it globally.
|
|
81
|
+
// NOTE: no `default:` here — needed so the ADR-125 CLI-flag-wins
|
|
82
|
+
// precedence (`ctx.flags.scanContent ?? envVar`) can distinguish
|
|
83
|
+
// "user didn't pass the flag" (undefined) from "user explicitly
|
|
84
|
+
// said --no-scan-content" (false). Fixes #2794.
|
|
81
85
|
name: 'scan-content',
|
|
82
86
|
description: 'Scan the value for injection payloads before persisting (dream-cycle #2752 MemPoison gate)',
|
|
83
87
|
type: 'boolean',
|
|
84
|
-
default: false
|
|
85
88
|
},
|
|
86
89
|
DB_PATH_OPTION
|
|
87
90
|
],
|
|
@@ -126,9 +129,11 @@ const storeCommand = {
|
|
|
126
129
|
return { success: false, exitCode: 1 };
|
|
127
130
|
}
|
|
128
131
|
// #2752 MemPoison gate — scan before persist when opted in.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
// CLI flag ctx.flags.scanContent takes precedence over RUFLO_MEMORY_SCAN_ON_WRITE env var
|
|
133
|
+
// (ADR-125 §"CLI flag wins" / ADR-130 §env-var-config-precedence — fix for #2794).
|
|
134
|
+
const scanContent = ctx.flags.scanContent
|
|
135
|
+
?? /^(1|true|yes|on)$/i.test(String(process.env.RUFLO_MEMORY_SCAN_ON_WRITE ?? ''));
|
|
136
|
+
if (scanContent) {
|
|
132
137
|
try {
|
|
133
138
|
const { scanChannelMessage } = await import('../security/channel-guard.js');
|
|
134
139
|
const scan = scanChannelMessage(value);
|
|
@@ -50,6 +50,29 @@ function getSwarmStatus(swarmId) {
|
|
|
50
50
|
// Ignore
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
// #2799 — `agent spawn` never writes `.swarm/agents/*.json`; it records
|
|
54
|
+
// the count in `.claude-flow/metrics/swarm-activity.json` (via
|
|
55
|
+
// updateSwarmActivityMetrics in commands/agent.ts). So when the agents
|
|
56
|
+
// dir is empty, reconcile against that authoritative activity file
|
|
57
|
+
// instead of reporting Total 0 while `agent list` shows N agents.
|
|
58
|
+
if (totalAgents === 0) {
|
|
59
|
+
try {
|
|
60
|
+
const activityPath = path.join(process.cwd(), '.claude-flow', 'metrics', 'swarm-activity.json');
|
|
61
|
+
if (fs.existsSync(activityPath)) {
|
|
62
|
+
const activity = JSON.parse(fs.readFileSync(activityPath, 'utf-8'));
|
|
63
|
+
const count = Math.max(0, Number((activity?.swarm?.agent_count)) || 0);
|
|
64
|
+
if (count > 0) {
|
|
65
|
+
totalAgents = count;
|
|
66
|
+
// swarm-activity.json tracks a count, not per-agent status; treat
|
|
67
|
+
// a coordination-active swarm's agents as active, else idle.
|
|
68
|
+
activeAgents = activity?.swarm?.coordination_active ? count : 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Ignore — fall back to 0
|
|
74
|
+
}
|
|
75
|
+
}
|
|
53
76
|
// Get session count
|
|
54
77
|
let sessionCount = 0;
|
|
55
78
|
if (fs.existsSync(sessionDir)) {
|
|
@@ -418,10 +418,21 @@ function getIntelligenceStatsFromMemory() {
|
|
|
418
418
|
(e.metadata?.type === 'trajectory'));
|
|
419
419
|
const successfulTrajectories = trajectoryEntries.filter(e => e.metadata?.success === true ||
|
|
420
420
|
(typeof e.value === 'object' && e.value !== null && e.value.success === true));
|
|
421
|
-
// Count patterns
|
|
421
|
+
// Count patterns (#2797). The original filter matched only
|
|
422
|
+
// `key.includes('pattern')` / `metadata.type==='pattern'` /
|
|
423
|
+
// `learned-*`, but NO writer in the codebase ever produces that
|
|
424
|
+
// shape — so Pattern Learning was permanently 0. The post-task
|
|
425
|
+
// dual-write (#2786 fix-2) persists learned patterns as
|
|
426
|
+
// `routing-decision:*` entries in the `patterns` namespace with
|
|
427
|
+
// `metadata.type: 'routing-decision'`. Those ARE the learned
|
|
428
|
+
// patterns the metric is meant to count, so include them: any entry
|
|
429
|
+
// whose namespace is `patterns`, plus the original shapes for
|
|
430
|
+
// forward-compatibility with a future explicit `pattern` writer.
|
|
422
431
|
const patternEntries = entries.filter(e => e.key.includes('pattern') ||
|
|
423
432
|
e.metadata?.type === 'pattern' ||
|
|
424
|
-
e.key.startsWith('learned-')
|
|
433
|
+
e.key.startsWith('learned-') ||
|
|
434
|
+
e.namespace === 'patterns' ||
|
|
435
|
+
e.metadata?.type === 'routing-decision');
|
|
425
436
|
// Categorize patterns
|
|
426
437
|
const categories = {};
|
|
427
438
|
patternEntries.forEach(e => {
|
|
@@ -51,6 +51,51 @@ export async function backupMemoryDb(opts = {}) {
|
|
|
51
51
|
db?.close();
|
|
52
52
|
}
|
|
53
53
|
catch { /* */ }
|
|
54
|
+
// #2798 — under CLAUDE_FLOW_ENCRYPT_AT_REST the source is an RFE1
|
|
55
|
+
// blob, not native SQLite, so better-sqlite3's online-backup API
|
|
56
|
+
// throws "file is not a database" and the run was silently recorded
|
|
57
|
+
// as skipped (users with encryption had ZERO backups behind a green
|
|
58
|
+
// status). The online-backup API only exists to avoid tearing a live
|
|
59
|
+
// WAL-mode DB; that concern doesn't apply to the encrypted file (sql.js
|
|
60
|
+
// rewrites it wholesale per flush), so a plain byte copy is a valid
|
|
61
|
+
// snapshot. Fall back to it before giving up.
|
|
62
|
+
try {
|
|
63
|
+
fs.copyFileSync(dbPath, destPath);
|
|
64
|
+
const copiedBytes = fs.statSync(destPath).size;
|
|
65
|
+
if (copiedBytes > 0) {
|
|
66
|
+
// Fall through to rotation/offsite/return below via a flag path.
|
|
67
|
+
// (Mirror the success path's tail by re-using the same code.)
|
|
68
|
+
const keep = typeof opts.keep === 'number' && opts.keep > 0 ? opts.keep : 7;
|
|
69
|
+
const rotatedAway = [];
|
|
70
|
+
try {
|
|
71
|
+
const snaps = fs.readdirSync(destDir).filter(f => /^memory-.*\.db$/.test(f)).sort();
|
|
72
|
+
while (snaps.length > keep) {
|
|
73
|
+
const old = snaps.shift();
|
|
74
|
+
try {
|
|
75
|
+
fs.rmSync(path.join(destDir, old), { force: true });
|
|
76
|
+
rotatedAway.push(old);
|
|
77
|
+
}
|
|
78
|
+
catch { /* */ }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch { /* */ }
|
|
82
|
+
let gcsUri;
|
|
83
|
+
if (opts.gcs) {
|
|
84
|
+
try {
|
|
85
|
+
const { execFileSync } = await import('child_process');
|
|
86
|
+
const dest = opts.gcs.replace(/\/+$/, '') + '/' + path.basename(destPath);
|
|
87
|
+
execFileSync('gcloud', ['storage', 'cp', destPath, dest], { stdio: ['ignore', 'ignore', 'inherit'] });
|
|
88
|
+
gcsUri = dest;
|
|
89
|
+
}
|
|
90
|
+
catch { /* offsite failed — local snapshot stands */ }
|
|
91
|
+
}
|
|
92
|
+
if (opts.verbose) {
|
|
93
|
+
console.log(`memory DB backed up (byte-copy, encrypted-at-rest) → ${destPath} (${Math.round(copiedBytes / 1024)} KB)`);
|
|
94
|
+
}
|
|
95
|
+
return { backedUp: true, path: destPath, sizeBytes: copiedBytes, rotatedAway, gcsUri };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch { /* byte-copy also failed — report the original error */ }
|
|
54
99
|
return { backedUp: false, skipped: `backup failed: ${e?.message ?? e}` };
|
|
55
100
|
}
|
|
56
101
|
let sizeBytes = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|