@claude-flow/cli 3.10.23 → 3.10.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.10.23",
3
+ "version": "3.10.24",
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",
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env node
2
+ // benchmark-cross-repo.mjs — cross-repo generalisation proof (ADR-084).
3
+ //
4
+ // Pretrains on a DIFFERENT repo's history (default: ruvnet/agentdb) and runs
5
+ // labelled queries about THAT repo's work. If the retrieval system genuinely
6
+ // generalises (vs overfits to the ruflo corpus it was tuned on), nDCG@3
7
+ // should stay near 0.96.
8
+ //
9
+ // Usage:
10
+ // 1. cd /tmp/agentdb-bench
11
+ // 2. REPO_ROOT=/tmp/agentdb-bench GH_REPO=ruvnet/agentdb \
12
+ // node /path/to/pretrain-from-github.mjs # writes /tmp/agentdb-bench/.claude-flow/neural/
13
+ // 3. cd /tmp/agentdb-bench && node /path/to/benchmark-cross-repo.mjs
14
+ //
15
+ // Or use the wrapper at the bottom that does both steps with --repo=<name>.
16
+
17
+ import { writeFileSync, mkdirSync } from 'node:fs';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { dirname, join, resolve } from 'node:path';
20
+ import { performance } from 'node:perf_hooks';
21
+
22
+ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
23
+ const CLI_ROOT = resolve(SCRIPT_DIR, '..');
24
+ const RUFLO_ROOT = resolve(SCRIPT_DIR, '../../../..');
25
+ const RUNS_DIR = join(RUFLO_ROOT, 'docs', 'benchmarks', 'runs');
26
+
27
+ // Labelled queries about agentdb's actual history (commits + issues
28
+ // observed via `git log` + `gh issue list` on ruvnet/agentdb).
29
+ // Each query targets a specific piece of work; labels are case-insensitive
30
+ // substring matches against the pattern name.
31
+ const QUERIES_AGENTDB = [
32
+ { q: 'SQL injection fix REINDEX',
33
+ labels: ['sql injection', 'reindex'] },
34
+ { q: 'insecure PRNG random IDs',
35
+ labels: ['insecure prng', 'random ids', 'random id', 'crypto', 'uuid'] },
36
+ { q: 'JSON parse crash hardening',
37
+ labels: ['json.parse', 'json parse', 'crash hardening'] },
38
+ { q: 'protobuf critical CVE patch',
39
+ labels: ['protobufjs', 'protobuf', 'cve'] },
40
+ { q: 'spawnSync vs execSync security',
41
+ labels: ['spawnsync', 'execsync'] },
42
+ { q: 'better-sqlite3 inline schemas',
43
+ labels: ['better-sqlite3', 'inline schema', 'schemas'] },
44
+ { q: 'Claude Code marketplace plugins',
45
+ labels: ['marketplace', 'plugin', 'claude code'] },
46
+ { q: 'README rewrite ruflo style',
47
+ labels: ['readme', 'rewrite'] },
48
+ { q: 'WASM browser fs.readFileSync blocking',
49
+ labels: ['wasm', 'browser', 'fs.readfilesync', 'readfilesync', 'agentdb/wasm'] },
50
+ { q: 'AgentDB missing schema files',
51
+ labels: ['missing schema', 'mising schema', 'schema files', 'not working'] },
52
+ ];
53
+
54
+ // Labelled queries about agentic-flow's actual history.
55
+ const QUERIES_AGENTIC_FLOW = [
56
+ { q: 'CWE-78 shell injection fix',
57
+ labels: ['cwe-78', 'shell injection', 'execsync', 'safe-exec'] },
58
+ { q: 'SSRF hardcoded key NaN panic security',
59
+ labels: ['ssrf', 'hardcoded key', 'nan-panic', 'nan panic'] },
60
+ { q: 'WebSocket QUIC transport fallback',
61
+ labels: ['websocket', 'quic', 'transport'] },
62
+ { q: 'agentdb submodule bump',
63
+ labels: ['agentdb submodule', 'bump agentdb', 'submodule'] },
64
+ { q: 'sql.js prepared statement leak',
65
+ labels: ['sql.js', 'prepared statement', 'leak'] },
66
+ { q: 'WASM ADR-071 integration',
67
+ labels: ['wasm', 'adr-071', 'wasm-integration'] },
68
+ { q: 'patch CVEs transitive overrides',
69
+ labels: ['cve', 'patch', 'transitive', 'overrides'] },
70
+ { q: 'GraphDatabaseAdapter delete API',
71
+ labels: ['graphdatabaseadapter', 'delete api', 'reflexionmemory', 'deleteepisode'] },
72
+ { q: 'release alpha publish version',
73
+ labels: ['release', 'publish', 'alpha', 'version'] },
74
+ { q: 'extract packages to dedicated repo',
75
+ labels: ['extract', 'refactor', 'dedicated repo', 'submodule', 'agentdb'] },
76
+ ];
77
+
78
+ // Auto-pick query set based on GH_REPO env var.
79
+ const QUERY_SETS = {
80
+ 'ruvnet/agentdb': QUERIES_AGENTDB,
81
+ 'ruvnet/agentic-flow': QUERIES_AGENTIC_FLOW,
82
+ };
83
+ const QUERIES = QUERY_SETS[process.env.GH_REPO] || QUERIES_AGENTDB;
84
+ const TOP_K = 5;
85
+
86
+ function isRelevant(name, labels) {
87
+ if (!name || !labels?.length) return false;
88
+ const lower = String(name).toLowerCase();
89
+ return labels.some((s) => lower.includes(s.toLowerCase()));
90
+ }
91
+
92
+ function ndcgAtK(rankedRel, k) {
93
+ const arr = rankedRel.slice(0, k);
94
+ const dcg = arr.reduce((acc, rel, i) => acc + (rel ? 1 / Math.log2(i + 2) : 0), 0);
95
+ const numRelevant = arr.filter(Boolean).length;
96
+ if (numRelevant === 0) return 0;
97
+ let idcg = 0;
98
+ for (let i = 0; i < numRelevant; i++) idcg += 1 / Math.log2(i + 2);
99
+ return idcg > 0 ? dcg / idcg : 0;
100
+ }
101
+
102
+ async function evalConfig(tool, params) {
103
+ let top1 = 0, top3 = 0, ranks = [], ndcg3sum = 0, ndcg5sum = 0, p3sum = 0;
104
+ const t0 = performance.now();
105
+ const perQuery = [];
106
+ for (const { q, labels } of QUERIES) {
107
+ const r = await tool.handler({ action: 'search', query: q, mode: 'hybrid', limit: TOP_K, ...params });
108
+ const matches = (r.results || []).slice(0, TOP_K);
109
+ const rel = matches.map((m) => isRelevant(m?.name, labels));
110
+ if (rel[0]) top1++;
111
+ if (rel.slice(0, 3).some(Boolean)) top3++;
112
+ const firstRank = rel.findIndex(Boolean);
113
+ if (firstRank >= 0) ranks.push(firstRank + 1);
114
+ ndcg3sum += ndcgAtK(rel, 3);
115
+ ndcg5sum += ndcgAtK(rel, 5);
116
+ p3sum += rel.slice(0, 3).filter(Boolean).length / 3;
117
+ perQuery.push({ q, top1: rel[0] || false, topK: matches.map((m, i) => ({ name: m.name?.slice(0, 90), relevant: rel[i], score: (m.score ?? m.similarity)?.toFixed?.(3) })) });
118
+ }
119
+ const elapsed = performance.now() - t0;
120
+ return {
121
+ top1HitRate: top1 / QUERIES.length,
122
+ top3HitRate: top3 / QUERIES.length,
123
+ mrr3: ranks.reduce((s, r) => s + 1 / r, 0) / QUERIES.length,
124
+ precision3: p3sum / QUERIES.length,
125
+ ndcg3: ndcg3sum / QUERIES.length,
126
+ ndcg5: ndcg5sum / QUERIES.length,
127
+ avgLatencyMs: elapsed / QUERIES.length,
128
+ perQuery,
129
+ };
130
+ }
131
+
132
+ async function main() {
133
+ const neural = await import(join(CLI_ROOT, 'dist/src/mcp-tools/neural-tools.js'));
134
+ const intel = await import(join(CLI_ROOT, 'dist/src/memory/intelligence.js'));
135
+ const stats = await intel.getUnifiedLearningStats();
136
+ const storeSize = stats.neuralPatterns.patternCount;
137
+
138
+ if (storeSize === 0) {
139
+ console.error('No patterns in neural store. Run pretrain-from-github.mjs first (with REPO_ROOT + GH_REPO env).');
140
+ process.exit(2);
141
+ }
142
+
143
+ const tool = neural.neuralTools.find((t) => t.name === 'neural_patterns');
144
+ if (!tool) throw new Error('neural_patterns tool not found');
145
+
146
+ console.log(`# Cross-repo generalisation benchmark (ADR-084)`);
147
+ console.log(`Cwd: ${process.cwd()}`);
148
+ console.log(`Store size: ${storeSize} patterns`);
149
+ console.log(`Queries: ${QUERIES.length} (labelled set for ${process.env.GH_REPO || 'default agentdb'})`);
150
+ console.log('');
151
+
152
+ console.log('--- Hybrid path (defaults) ---');
153
+ const hybrid = await evalConfig(tool, { rerank: false });
154
+ console.log(` top-1: ${(hybrid.top1HitRate * 100).toFixed(0)}% top-3: ${(hybrid.top3HitRate * 100).toFixed(0)}% MRR@3: ${hybrid.mrr3.toFixed(3)} P3: ${hybrid.precision3.toFixed(3)} nDCG@3: ${hybrid.ndcg3.toFixed(3)} nDCG@5: ${hybrid.ndcg5.toFixed(3)} ${hybrid.avgLatencyMs.toFixed(0)}ms`);
155
+
156
+ console.log('--- Rerank path (defaults) ---');
157
+ const rerank = await evalConfig(tool, { rerank: true });
158
+ console.log(` top-1: ${(rerank.top1HitRate * 100).toFixed(0)}% top-3: ${(rerank.top3HitRate * 100).toFixed(0)}% MRR@3: ${rerank.mrr3.toFixed(3)} P3: ${rerank.precision3.toFixed(3)} nDCG@3: ${rerank.ndcg3.toFixed(3)} nDCG@5: ${rerank.ndcg5.toFixed(3)} ${rerank.avgLatencyMs.toFixed(0)}ms`);
159
+
160
+ console.log('\n--- Per-query rerank top-3 ---');
161
+ for (const q of rerank.perQuery) {
162
+ console.log(`Q: "${q.q}" (top-1: ${q.top1 ? '✓' : '✗'})`);
163
+ for (const m of q.topK.slice(0, 3)) {
164
+ console.log(` ${m.relevant ? '★' : ' '} [${m.score ?? '—'}] ${m.name}`);
165
+ }
166
+ }
167
+
168
+ const summary = {
169
+ runAt: new Date().toISOString(),
170
+ benchmark: 'cross-repo-generalisation',
171
+ repo: process.env.GH_REPO || 'unknown',
172
+ cwd: process.cwd(),
173
+ storeSize,
174
+ queries: QUERIES.length,
175
+ hybrid: {
176
+ top1HitRate: hybrid.top1HitRate,
177
+ top3HitRate: hybrid.top3HitRate,
178
+ mrr3: hybrid.mrr3,
179
+ precision3: hybrid.precision3,
180
+ ndcg3: hybrid.ndcg3,
181
+ ndcg5: hybrid.ndcg5,
182
+ avgLatencyMs: hybrid.avgLatencyMs,
183
+ },
184
+ rerank: {
185
+ top1HitRate: rerank.top1HitRate,
186
+ top3HitRate: rerank.top3HitRate,
187
+ mrr3: rerank.mrr3,
188
+ precision3: rerank.precision3,
189
+ ndcg3: rerank.ndcg3,
190
+ ndcg5: rerank.ndcg5,
191
+ avgLatencyMs: rerank.avgLatencyMs,
192
+ },
193
+ perQueryRerank: rerank.perQuery,
194
+ };
195
+
196
+ mkdirSync(RUNS_DIR, { recursive: true });
197
+ const stamp = summary.runAt.replace(/[:.]/g, '-');
198
+ const repoSlug = (process.env.GH_REPO || 'unknown').replace('/', '-');
199
+ writeFileSync(join(RUNS_DIR, `cross-repo-${repoSlug}-${stamp}.json`), JSON.stringify(summary, null, 2));
200
+ writeFileSync(join(RUNS_DIR, `cross-repo-${repoSlug}-latest.json`), JSON.stringify(summary, null, 2));
201
+ console.log(`\nWrote ${join(RUNS_DIR, `cross-repo-${repoSlug}-${stamp}.json`)}`);
202
+
203
+ process.exit(0);
204
+ }
205
+
206
+ main().catch((err) => { console.error(err); process.exit(1); });
@@ -32,8 +32,14 @@ import { performance } from 'node:perf_hooks';
32
32
 
33
33
  const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
34
34
  const CLI_ROOT = resolve(SCRIPT_DIR, '..');
35
- const REPO_ROOT = resolve(SCRIPT_DIR, '../../../..');
36
- const RUNS_DIR = join(REPO_ROOT, 'docs', 'benchmarks', 'runs');
35
+ const RUFLO_ROOT = resolve(SCRIPT_DIR, '../../../..');
36
+ const RUNS_DIR = join(RUFLO_ROOT, 'docs', 'benchmarks', 'runs');
37
+
38
+ // ADR-084 cross-repo support — REPO_ROOT and GH_REPO env-overridable so the
39
+ // same script can pretrain on agentdb / agentic-flow / any other repo for
40
+ // generalisation testing. Defaults preserve ruflo behaviour.
41
+ const REPO_ROOT = process.env.REPO_ROOT ? resolve(process.env.REPO_ROOT) : RUFLO_ROOT;
42
+ const GH_REPO = process.env.GH_REPO || 'ruvnet/ruflo';
37
43
 
38
44
  const COMMITS = Number(process.env.COMMITS) || 50;
39
45
  const ISSUES = Number(process.env.ISSUES) || 30;
@@ -156,7 +162,7 @@ function harvestIssues(n) {
156
162
  if (SOURCE === 'git') return [];
157
163
  try {
158
164
  const raw = execSync(
159
- `gh issue list --repo ruvnet/ruflo --state all --limit ${n} --json number,title,body,state,closedAt 2>/dev/null`,
165
+ `gh issue list --repo ${GH_REPO} --state all --limit ${n} --json number,title,body,state,closedAt 2>/dev/null`,
160
166
  { cwd: REPO_ROOT, encoding: 'utf-8', maxBuffer: 64 * 1024 * 1024 },
161
167
  );
162
168
  const items = JSON.parse(raw);