claude-flow 3.5.18 → 3.5.20

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",
3
- "version": "3.5.18",
3
+ "version": "3.5.20",
4
4
  "description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -420,26 +420,86 @@ const metricsCommand = {
420
420
  action: async (ctx) => {
421
421
  const agentId = ctx.args[0];
422
422
  const period = ctx.flags.period;
423
- // Default metrics (updated by MCP agent/metrics when available)
423
+ // Collect real metrics from .swarm/ state
424
+ const { existsSync, readFileSync, readdirSync, statSync } = await import('fs');
425
+ const { join } = await import('path');
426
+ let totalAgents = 0;
427
+ let activeAgents = 0;
428
+ let tasksCompleted = 0;
429
+ const typeCounts = {};
430
+ // Read swarm agent state
431
+ const swarmDir = join(process.cwd(), '.swarm');
432
+ const agentsDir = join(swarmDir, 'agents');
433
+ if (existsSync(agentsDir)) {
434
+ try {
435
+ const files = readdirSync(agentsDir).filter(f => f.endsWith('.json'));
436
+ for (const file of files) {
437
+ try {
438
+ const data = JSON.parse(readFileSync(join(agentsDir, file), 'utf-8'));
439
+ totalAgents++;
440
+ const agType = data.type || 'unknown';
441
+ if (!typeCounts[agType])
442
+ typeCounts[agType] = { count: 0, tasks: 0, success: 0 };
443
+ typeCounts[agType].count++;
444
+ if (data.status === 'active' || data.status === 'running')
445
+ activeAgents++;
446
+ if (data.tasksCompleted) {
447
+ typeCounts[agType].tasks += data.tasksCompleted;
448
+ tasksCompleted += data.tasksCompleted;
449
+ }
450
+ if (data.successCount)
451
+ typeCounts[agType].success += data.successCount;
452
+ }
453
+ catch { /* skip malformed */ }
454
+ }
455
+ }
456
+ catch { /* no agents dir */ }
457
+ }
458
+ // Read swarm activity for additional state
459
+ const activityFile = join(swarmDir, 'swarm-activity.json');
460
+ if (existsSync(activityFile)) {
461
+ try {
462
+ const activity = JSON.parse(readFileSync(activityFile, 'utf-8'));
463
+ if (activity.totalAgents && totalAgents === 0)
464
+ totalAgents = activity.totalAgents;
465
+ if (activity.activeAgents && activeAgents === 0)
466
+ activeAgents = activity.activeAgents;
467
+ }
468
+ catch { /* ignore */ }
469
+ }
470
+ // Read memory.db stats
471
+ let vectorCount = 0;
472
+ const dbPath = join(swarmDir, 'memory.db');
473
+ if (existsSync(dbPath)) {
474
+ try {
475
+ const dbSize = statSync(dbPath).size;
476
+ vectorCount = Math.floor(dbSize / 2048);
477
+ }
478
+ catch { /* ignore */ }
479
+ }
480
+ const byType = Object.entries(typeCounts).map(([type, data]) => ({
481
+ type,
482
+ count: data.count,
483
+ tasks: data.tasks,
484
+ successRate: data.tasks > 0 ? `${Math.round((data.success / data.tasks) * 100)}%` : 'N/A'
485
+ }));
486
+ const avgSuccessRate = tasksCompleted > 0
487
+ ? `${Math.round(Object.values(typeCounts).reduce((a, d) => a + d.success, 0) / tasksCompleted * 100)}%`
488
+ : 'N/A';
424
489
  const metrics = {
425
490
  period,
426
491
  summary: {
427
- totalAgents: 4,
428
- activeAgents: 3,
429
- tasksCompleted: 127,
430
- avgSuccessRate: '96.2%',
431
- totalTokens: 1234567,
432
- avgResponseTime: '1.45s'
492
+ totalAgents,
493
+ activeAgents,
494
+ tasksCompleted,
495
+ avgSuccessRate,
496
+ vectorCount,
497
+ note: totalAgents === 0 ? 'No agents spawned yet. Use: agent spawn -t coder' : undefined
433
498
  },
434
- byType: [
435
- { type: 'coder', count: 2, tasks: 45, successRate: '97%' },
436
- { type: 'researcher', count: 1, tasks: 32, successRate: '95%' },
437
- { type: 'tester', count: 1, tasks: 50, successRate: '98%' }
438
- ],
499
+ byType,
439
500
  performance: {
440
- flashAttention: '2.8x speedup',
441
- memoryReduction: '52%',
442
- searchImprovement: '150x faster'
501
+ memoryVectors: `${vectorCount} vectors`,
502
+ searchBackend: vectorCount > 0 ? 'HNSW-indexed' : 'none'
443
503
  }
444
504
  };
445
505
  if (ctx.flags.format === 'json') {
@@ -459,8 +519,7 @@ const metricsCommand = {
459
519
  { metric: 'Active Agents', value: metrics.summary.activeAgents },
460
520
  { metric: 'Tasks Completed', value: metrics.summary.tasksCompleted },
461
521
  { metric: 'Success Rate', value: metrics.summary.avgSuccessRate },
462
- { metric: 'Total Tokens', value: metrics.summary.totalTokens.toLocaleString() },
463
- { metric: 'Avg Response Time', value: metrics.summary.avgResponseTime }
522
+ { metric: 'Memory Vectors', value: metrics.summary.vectorCount }
464
523
  ]
465
524
  });
466
525
  output.writeln();
@@ -474,12 +533,15 @@ const metricsCommand = {
474
533
  ],
475
534
  data: metrics.byType
476
535
  });
536
+ if (metrics.summary.note) {
537
+ output.writeln();
538
+ output.writeln(output.dim(metrics.summary.note));
539
+ }
477
540
  output.writeln();
478
- output.writeln(output.bold('V3 Performance Gains'));
541
+ output.writeln(output.bold('Memory'));
479
542
  output.printList([
480
- `Flash Attention: ${output.success(metrics.performance.flashAttention)}`,
481
- `Memory Reduction: ${output.success(metrics.performance.memoryReduction)}`,
482
- `Search: ${output.success(metrics.performance.searchImprovement)}`
543
+ `Vectors: ${output.success(metrics.performance.memoryVectors)}`,
544
+ `Backend: ${output.success(metrics.performance.searchBackend)}`
483
545
  ]);
484
546
  return { success: true, data: metrics };
485
547
  }
@@ -59,12 +59,13 @@ async function checkNpmVersion() {
59
59
  }
60
60
  // Check config file
61
61
  async function checkConfigFile() {
62
- const configPaths = [
62
+ // JSON configs (parse-validated)
63
+ const jsonPaths = [
63
64
  '.claude-flow/config.json',
64
65
  'claude-flow.config.json',
65
66
  '.claude-flow.json'
66
67
  ];
67
- for (const configPath of configPaths) {
68
+ for (const configPath of jsonPaths) {
68
69
  if (existsSync(configPath)) {
69
70
  try {
70
71
  const content = readFileSync(configPath, 'utf8');
@@ -76,6 +77,17 @@ async function checkConfigFile() {
76
77
  }
77
78
  }
78
79
  }
80
+ // YAML configs (existence-checked only — no heavy yaml parser dependency)
81
+ const yamlPaths = [
82
+ '.claude-flow/config.yaml',
83
+ '.claude-flow/config.yml',
84
+ 'claude-flow.config.yaml'
85
+ ];
86
+ for (const configPath of yamlPaths) {
87
+ if (existsSync(configPath)) {
88
+ return { name: 'Config File', status: 'pass', message: `Found: ${configPath}` };
89
+ }
90
+ }
79
91
  return { name: 'Config File', status: 'warn', message: 'No config file (using defaults)', fix: 'claude-flow config init' };
80
92
  }
81
93
  // Check daemon status
@@ -128,9 +140,14 @@ async function checkApiKeys() {
128
140
  found.push(key);
129
141
  }
130
142
  }
143
+ // Detect Claude Code environment — API keys are managed internally
144
+ const inClaudeCode = !!(process.env.CLAUDE_CODE || process.env.CLAUDE_PROJECT_DIR || process.env.MCP_SESSION_ID);
131
145
  if (found.includes('ANTHROPIC_API_KEY') || found.includes('CLAUDE_API_KEY')) {
132
146
  return { name: 'API Keys', status: 'pass', message: `Found: ${found.join(', ')}` };
133
147
  }
148
+ else if (inClaudeCode) {
149
+ return { name: 'API Keys', status: 'pass', message: 'Claude Code (managed internally)' };
150
+ }
134
151
  else if (found.length > 0) {
135
152
  return { name: 'API Keys', status: 'warn', message: `Found: ${found.join(', ')} (no Claude key)`, fix: 'export ANTHROPIC_API_KEY=your_key' };
136
153
  }
@@ -171,12 +188,12 @@ async function checkMcpServers() {
171
188
  const content = JSON.parse(readFileSync(configPath, 'utf8'));
172
189
  const servers = content.mcpServers || content.servers || {};
173
190
  const count = Object.keys(servers).length;
174
- const hasClaudeFlow = 'claude-flow' in servers || 'claude-flow_alpha' in servers;
191
+ const hasClaudeFlow = 'claude-flow' in servers || 'claude-flow_alpha' in servers || 'ruflo' in servers || 'ruflo_alpha' in servers;
175
192
  if (hasClaudeFlow) {
176
- return { name: 'MCP Servers', status: 'pass', message: `${count} servers (claude-flow configured)` };
193
+ return { name: 'MCP Servers', status: 'pass', message: `${count} servers (ruflo configured)` };
177
194
  }
178
195
  else {
179
- return { name: 'MCP Servers', status: 'warn', message: `${count} servers (claude-flow not found)`, fix: 'claude mcp add claude-flow npx @claude-flow/cli@v3alpha mcp start' };
196
+ return { name: 'MCP Servers', status: 'warn', message: `${count} servers (ruflo not found)`, fix: 'claude mcp add ruflo -- npx -y ruflo@latest mcp start' };
180
197
  }
181
198
  }
182
199
  catch {
@@ -1146,9 +1146,8 @@ const preTaskCommand = {
1146
1146
  {
1147
1147
  name: 'task-id',
1148
1148
  short: 'i',
1149
- description: 'Unique task identifier',
1150
- type: 'string',
1151
- required: true
1149
+ description: 'Unique task identifier (auto-generated if omitted)',
1150
+ type: 'string'
1152
1151
  },
1153
1152
  {
1154
1153
  name: 'description',
@@ -1170,10 +1169,10 @@ const preTaskCommand = {
1170
1169
  { command: 'claude-flow hooks pre-task -i task-456 -d "Implement feature" --auto-spawn', description: 'With auto-spawn' }
1171
1170
  ],
1172
1171
  action: async (ctx) => {
1173
- const taskId = ctx.flags.taskId;
1172
+ const taskId = ctx.flags.taskId || `task-${Date.now().toString(36)}`;
1174
1173
  const description = ctx.args[0] || ctx.flags.description;
1175
- if (!taskId || !description) {
1176
- output.printError('Task ID and description are required.');
1174
+ if (!description) {
1175
+ output.printError('Description is required: --description "your task"');
1177
1176
  return { success: false, exitCode: 1 };
1178
1177
  }
1179
1178
  output.printInfo(`Starting task: ${output.highlight(taskId)}`);
@@ -3649,6 +3648,45 @@ const taskCompletedCommand = {
3649
3648
  }
3650
3649
  }
3651
3650
  };
3651
+ // Notify subcommand
3652
+ const notifyCommand = {
3653
+ name: 'notify',
3654
+ description: 'Send a notification message (logged to session)',
3655
+ options: [
3656
+ { name: 'message', short: 'm', type: 'string', description: 'Notification message', required: true },
3657
+ { name: 'level', short: 'l', type: 'string', description: 'Level: info, warn, error', default: 'info' },
3658
+ { name: 'channel', short: 'c', type: 'string', description: 'Notification channel', default: 'console' },
3659
+ ],
3660
+ examples: [
3661
+ { command: 'claude-flow hooks notify -m "Build complete"', description: 'Send info notification' },
3662
+ { command: 'claude-flow hooks notify -m "Test failed" -l error', description: 'Send error notification' },
3663
+ ],
3664
+ action: async (ctx) => {
3665
+ const message = ctx.args[0] || ctx.flags.message;
3666
+ const level = ctx.flags.level || 'info';
3667
+ if (!message) {
3668
+ output.printError('Message is required: --message "your message"');
3669
+ return { success: false, exitCode: 1 };
3670
+ }
3671
+ const timestamp = new Date().toISOString();
3672
+ if (level === 'error') {
3673
+ output.printError(`[${timestamp}] ${message}`);
3674
+ }
3675
+ else if (level === 'warn') {
3676
+ output.writeln(output.warning(`[${timestamp}] ${message}`));
3677
+ }
3678
+ else {
3679
+ output.printInfo(`[${timestamp}] ${message}`);
3680
+ }
3681
+ // Store notification in memory if available
3682
+ try {
3683
+ const { storeEntry } = await import('../memory/memory-initializer.js');
3684
+ await storeEntry({ key: `notify-${Date.now()}`, value: `[${level}] ${message}`, namespace: 'notifications' });
3685
+ }
3686
+ catch { /* memory not available */ }
3687
+ return { success: true, data: { timestamp, level, message } };
3688
+ }
3689
+ };
3652
3690
  // Main hooks command
3653
3691
  export const hooksCommand = {
3654
3692
  name: 'hooks',
@@ -3670,6 +3708,7 @@ export const hooksCommand = {
3670
3708
  transferCommand,
3671
3709
  listCommand,
3672
3710
  intelligenceCommand,
3711
+ notifyCommand,
3673
3712
  workerCommand,
3674
3713
  progressHookCommand,
3675
3714
  statuslineCommand,
@@ -30,7 +30,7 @@ const trainCommand = {
30
30
  { command: 'claude-flow neural train -p security --wasm --contrastive', description: 'Security patterns with contrastive learning' },
31
31
  ],
32
32
  action: async (ctx) => {
33
- const patternType = ctx.flags.pattern || 'coordination';
33
+ const patternType = (ctx.flags.pattern || ctx.flags.patternType || ctx.flags['pattern-type']) || 'coordination';
34
34
  const epochs = parseInt(ctx.flags.epochs || '50', 10);
35
35
  const learningRate = parseFloat(ctx.flags['learning-rate'] || '0.01');
36
36
  const batchSize = parseInt(ctx.flags['batch-size'] || '32', 10);
@@ -340,21 +340,52 @@ const auditCommand = {
340
340
  output.writeln();
341
341
  output.writeln(output.bold('Security Audit Log'));
342
342
  output.writeln(output.dim('─'.repeat(60)));
343
- output.printTable({
344
- columns: [
345
- { key: 'timestamp', header: 'Timestamp', width: 22 },
346
- { key: 'event', header: 'Event', width: 20 },
347
- { key: 'user', header: 'User', width: 15 },
348
- { key: 'status', header: 'Status', width: 12 },
349
- ],
350
- data: [
351
- { timestamp: '2024-01-15 14:32:01', event: 'AUTH_LOGIN', user: 'admin', status: output.success('Success') },
352
- { timestamp: '2024-01-15 14:30:45', event: 'CONFIG_CHANGE', user: 'system', status: output.success('Success') },
353
- { timestamp: '2024-01-15 14:28:12', event: 'AUTH_FAILED', user: 'unknown', status: output.error('Failed') },
354
- { timestamp: '2024-01-15 14:25:33', event: 'SCAN_COMPLETE', user: 'ci-bot', status: output.success('Success') },
355
- { timestamp: '2024-01-15 14:20:00', event: 'KEY_ROTATE', user: 'admin', status: output.success('Success') },
356
- ],
357
- });
343
+ // Generate real audit entries from .swarm/ state and session history
344
+ const { existsSync, readFileSync, readdirSync, statSync } = await import('fs');
345
+ const { join } = await import('path');
346
+ const auditEntries = [];
347
+ const swarmDir = join(process.cwd(), '.swarm');
348
+ // Check session files for real audit events
349
+ if (existsSync(swarmDir)) {
350
+ try {
351
+ const files = readdirSync(swarmDir).filter(f => f.endsWith('.json'));
352
+ for (const file of files.slice(-10)) {
353
+ try {
354
+ const stat = statSync(join(swarmDir, file));
355
+ const ts = stat.mtime.toISOString().replace('T', ' ').substring(0, 19);
356
+ auditEntries.push({
357
+ timestamp: ts,
358
+ event: file.includes('session') ? 'SESSION_UPDATE' :
359
+ file.includes('swarm') ? 'SWARM_ACTIVITY' :
360
+ file.includes('memory') ? 'MEMORY_WRITE' : 'CONFIG_CHANGE',
361
+ user: 'system',
362
+ status: output.success('Success')
363
+ });
364
+ }
365
+ catch { /* skip */ }
366
+ }
367
+ }
368
+ catch { /* ignore */ }
369
+ }
370
+ // Add current session entry
371
+ const now = new Date().toISOString().replace('T', ' ').substring(0, 19);
372
+ auditEntries.push({ timestamp: now, event: 'AUDIT_RUN', user: 'cli', status: output.success('Success') });
373
+ // Sort by timestamp desc
374
+ auditEntries.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
375
+ if (auditEntries.length === 0) {
376
+ output.writeln(output.dim('No audit events found. Initialize a project first: claude-flow init'));
377
+ }
378
+ else {
379
+ output.printTable({
380
+ columns: [
381
+ { key: 'timestamp', header: 'Timestamp', width: 22 },
382
+ { key: 'event', header: 'Event', width: 20 },
383
+ { key: 'user', header: 'User', width: 15 },
384
+ { key: 'status', header: 'Status', width: 12 },
385
+ ],
386
+ data: auditEntries.slice(0, parseInt(ctx.flags.limit || '20', 10)),
387
+ });
388
+ }
358
389
  return { success: true };
359
390
  },
360
391
  };
@@ -81,7 +81,7 @@ export const agentdbControllers = {
81
81
  const bridge = await getBridge();
82
82
  const controllers = await bridge.bridgeListControllers();
83
83
  if (!controllers)
84
- return { available: false, controllers: [], error: 'Bridge not available' };
84
+ return { available: false, controllers: [], error: 'AgentDB bridge not available — @claude-flow/memory not installed or missing controller-registry. Use memory_store/memory_search tools instead.' };
85
85
  return {
86
86
  available: true,
87
87
  controllers,
@@ -118,7 +118,7 @@ export const agentdbPatternStore = {
118
118
  type: validateString(params.type, 'type', 200) ?? 'general',
119
119
  confidence: validateScore(params.confidence, 0.8),
120
120
  });
121
- return result ?? { success: false, error: 'Bridge not available' };
121
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
122
122
  }
123
123
  catch (error) {
124
124
  return { success: false, error: sanitizeError(error) };
@@ -182,7 +182,7 @@ export const agentdbFeedback = {
182
182
  quality: validateScore(params.quality, 0.85),
183
183
  agent: validateString(params.agent, 'agent', 200) ?? undefined,
184
184
  });
185
- return result ?? { success: false, error: 'Bridge not available' };
185
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
186
186
  }
187
187
  catch (error) {
188
188
  return { success: false, error: sanitizeError(error) };
@@ -221,7 +221,7 @@ export const agentdbCausalEdge = {
221
221
  relation,
222
222
  weight: typeof params.weight === 'number' ? validateScore(params.weight, 0.5) : undefined,
223
223
  });
224
- return result ?? { success: false, error: 'Bridge not available' };
224
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
225
225
  }
226
226
  catch (error) {
227
227
  return { success: false, error: sanitizeError(error) };
@@ -279,7 +279,7 @@ export const agentdbSessionStart = {
279
279
  sessionId,
280
280
  context: validateString(params.context, 'context', 10_000) ?? undefined,
281
281
  });
282
- return result ?? { success: false, error: 'Bridge not available' };
282
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
283
283
  }
284
284
  catch (error) {
285
285
  return { success: false, error: sanitizeError(error) };
@@ -310,7 +310,7 @@ export const agentdbSessionEnd = {
310
310
  summary: validateString(params.summary, 'summary', 50_000) ?? undefined,
311
311
  tasksCompleted: validatePositiveInt(params.tasksCompleted, 0, 10_000),
312
312
  });
313
- return result ?? { success: false, error: 'Bridge not available' };
313
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
314
314
  }
315
315
  catch (error) {
316
316
  return { success: false, error: sanitizeError(error) };
@@ -349,7 +349,7 @@ export const agentdbHierarchicalStore = {
349
349
  }
350
350
  const bridge = await getBridge();
351
351
  const result = await bridge.bridgeHierarchicalStore({ key, value, tier });
352
- return result ?? { success: false, error: 'Bridge not available' };
352
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
353
353
  }
354
354
  catch (error) {
355
355
  return { success: false, error: sanitizeError(error) };
@@ -384,7 +384,7 @@ export const agentdbHierarchicalRecall = {
384
384
  tier: tier ?? undefined,
385
385
  topK: validatePositiveInt(params.topK, 5, MAX_TOP_K),
386
386
  });
387
- return result ?? { results: [], error: 'Bridge not available' };
387
+ return result ?? { results: [], error: 'AgentDB bridge not available. Use memory_search instead.' };
388
388
  }
389
389
  catch (error) {
390
390
  return { results: [], error: sanitizeError(error) };
@@ -409,7 +409,7 @@ export const agentdbConsolidate = {
409
409
  minAge: typeof params.minAge === 'number' ? Math.max(0, params.minAge) : undefined,
410
410
  maxEntries: validatePositiveInt(params.maxEntries, 1000, 10_000),
411
411
  });
412
- return result ?? { success: false, error: 'Bridge not available' };
412
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
413
413
  }
414
414
  catch (error) {
415
415
  return { success: false, error: sanitizeError(error) };
@@ -475,7 +475,7 @@ export const agentdbBatch = {
475
475
  operation,
476
476
  entries: validatedEntries,
477
477
  });
478
- return result ?? { success: false, error: 'Bridge not available' };
478
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
479
479
  }
480
480
  catch (error) {
481
481
  return { success: false, error: sanitizeError(error) };
@@ -504,7 +504,7 @@ export const agentdbContextSynthesize = {
504
504
  query,
505
505
  maxEntries: validatePositiveInt(params.maxEntries, 10, MAX_TOP_K),
506
506
  });
507
- return result ?? { success: false, error: 'Bridge not available' };
507
+ return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
508
508
  }
509
509
  catch (error) {
510
510
  return { success: false, error: sanitizeError(error) };
@@ -529,7 +529,7 @@ export const agentdbSemanticRoute = {
529
529
  return { route: null, error: 'input is required (non-empty string, max 10KB)' };
530
530
  const bridge = await getBridge();
531
531
  const result = await bridge.bridgeSemanticRoute({ input });
532
- return result ?? { route: null, error: 'Bridge not available' };
532
+ return result ?? { route: null, error: 'AgentDB bridge not available. Use hooks route instead.' };
533
533
  }
534
534
  catch (error) {
535
535
  return { route: null, error: sanitizeError(error) };
@@ -545,9 +545,13 @@ export async function findSimilarPatterns(query, options) {
545
545
  const queryResult = await generateEmbedding(query);
546
546
  queryEmbedding = queryResult.embedding;
547
547
  }
548
+ // Hash-fallback embeddings (128-dim) produce lower cosine similarities
549
+ // than ONNX/transformer embeddings, so use a lower default threshold
550
+ const isHashFallback = queryEmbedding.length === 128;
551
+ const defaultThreshold = isHashFallback ? 0.1 : 0.5;
548
552
  const results = reasoningBank.findSimilar(queryEmbedding, {
549
553
  k: options?.k ?? 5,
550
- threshold: options?.threshold ?? 0.5,
554
+ threshold: options?.threshold ?? defaultThreshold,
551
555
  type: options?.type
552
556
  });
553
557
  return results.map((r) => ({
@@ -32,6 +32,16 @@ export declare class CommandParser {
32
32
  private parseValue;
33
33
  private normalizeKey;
34
34
  private buildAliases;
35
+ /**
36
+ * Build aliases scoped to a specific command/subcommand.
37
+ * The resolved command's short flags take priority over global ones,
38
+ * fixing collisions where multiple subcommands use the same short flag (e.g. -t).
39
+ */
40
+ private buildScopedAliases;
41
+ /**
42
+ * Get boolean flags scoped to a specific command/subcommand.
43
+ */
44
+ private getScopedBooleanFlags;
35
45
  private getBooleanFlags;
36
46
  private applyDefaults;
37
47
  validateFlags(flags: ParsedFlags, command?: Command): string[];
@@ -101,9 +101,23 @@ export class CommandParser {
101
101
  positional: [],
102
102
  raw: [...args]
103
103
  };
104
- // Build flag configuration from global options
105
- const aliases = this.buildAliases();
106
- const booleanFlags = this.getBooleanFlags();
104
+ // Pass 1: Identify command and subcommand (skip flags)
105
+ let resolvedCmd;
106
+ let resolvedSub;
107
+ for (const arg of args) {
108
+ if (arg.startsWith('-'))
109
+ continue;
110
+ if (!resolvedCmd && this.commands.has(arg)) {
111
+ resolvedCmd = this.commands.get(arg);
112
+ }
113
+ else if (resolvedCmd && !resolvedSub && resolvedCmd.subcommands) {
114
+ resolvedSub = resolvedCmd.subcommands.find(sc => sc.name === arg || sc.aliases?.includes(arg));
115
+ }
116
+ }
117
+ // Pass 2: Build aliases scoped to the resolved subcommand
118
+ // Subcommand-specific aliases take priority over global ones
119
+ const aliases = this.buildScopedAliases(resolvedSub || resolvedCmd);
120
+ const booleanFlags = this.getScopedBooleanFlags(resolvedSub || resolvedCmd);
107
121
  let i = 0;
108
122
  let parsingFlags = true;
109
123
  while (i < args.length) {
@@ -275,6 +289,38 @@ export class CommandParser {
275
289
  }
276
290
  return { ...aliases, ...this.options.aliases };
277
291
  }
292
+ /**
293
+ * Build aliases scoped to a specific command/subcommand.
294
+ * The resolved command's short flags take priority over global ones,
295
+ * fixing collisions where multiple subcommands use the same short flag (e.g. -t).
296
+ */
297
+ buildScopedAliases(resolvedCmd) {
298
+ // Start with global aliases as base
299
+ const aliases = this.buildAliases();
300
+ // Override with the resolved command's own options (these take priority)
301
+ if (resolvedCmd?.options) {
302
+ for (const opt of resolvedCmd.options) {
303
+ if (opt.short) {
304
+ aliases[opt.short] = opt.name;
305
+ }
306
+ }
307
+ }
308
+ return aliases;
309
+ }
310
+ /**
311
+ * Get boolean flags scoped to a specific command/subcommand.
312
+ */
313
+ getScopedBooleanFlags(resolvedCmd) {
314
+ const flags = this.getBooleanFlags();
315
+ if (resolvedCmd?.options) {
316
+ for (const opt of resolvedCmd.options) {
317
+ if (opt.type === 'boolean') {
318
+ flags.add(this.normalizeKey(opt.name));
319
+ }
320
+ }
321
+ }
322
+ return flags;
323
+ }
278
324
  getBooleanFlags() {
279
325
  const flags = new Set();
280
326
  for (const opt of this.globalOptions) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.5.18",
3
+ "version": "3.5.20",
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",