claude-flow 3.32.17 → 3.32.18

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.32.17",
3
+ "version": "3.32.18",
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",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "generation": 1,
4
- "generatedAt": "2026-07-27T02:44:16.339Z",
5
- "gitSha": "a0a4f165",
4
+ "generatedAt": "2026-07-27T02:55:18.250Z",
5
+ "gitSha": "684ca3bf",
6
6
  "catalog": {
7
7
  "agents": 164,
8
8
  "tools": 387,
@@ -345,25 +345,62 @@ const searchCommand = {
345
345
  type: 'boolean',
346
346
  default: false
347
347
  },
348
+ {
349
+ // #2760 dream-cycle — SCM routed memory. Classify the query intent
350
+ // and route search to the mapped namespaces (episodic → session
351
+ // writes, semantic → patterns, procedural → skills). Default
352
+ // "mixed" preserves the pre-#2760 behavior (search everything).
353
+ name: 'intent',
354
+ description: 'Route query to intent-mapped namespaces (auto | mixed | episodic | semantic | procedural) — dream-cycle #2760',
355
+ type: 'string',
356
+ choices: ['auto', 'mixed', 'episodic', 'semantic', 'procedural'],
357
+ default: 'mixed',
358
+ },
348
359
  DB_PATH_OPTION
349
360
  ],
350
361
  examples: [
351
362
  { command: 'claude-flow memory search -q "authentication patterns"', description: 'Semantic search' },
352
363
  { command: 'claude-flow memory search -q "JWT" -t keyword', description: 'Keyword search' },
353
364
  { command: 'claude-flow memory search -q "test" --build-hnsw', description: 'Build HNSW index and search' },
354
- { command: 'claude-flow memory search -q "auth patterns" --smart', description: 'SmartRetrieval with RRF + MMR' }
365
+ { command: 'claude-flow memory search -q "auth patterns" --smart', description: 'SmartRetrieval with RRF + MMR' },
366
+ { command: 'claude-flow memory search -q "when did we last touch auth" --intent auto', description: 'SCM-routed retrieval (dream-cycle #2760)' },
355
367
  ],
356
368
  action: async (ctx) => {
357
369
  const query = ctx.flags.query || ctx.args[0];
358
- const namespace = ctx.flags.namespace || 'all';
370
+ let namespace = ctx.flags.namespace || 'all';
359
371
  const limit = ctx.flags.limit || 10;
360
372
  const threshold = ctx.flags.threshold || 0.3;
361
373
  const searchType = ctx.flags.type || 'semantic';
362
374
  const buildHnsw = (ctx.flags['build-hnsw'] || ctx.flags.buildHnsw);
375
+ const requestedIntent = ctx.flags.intent || 'mixed';
363
376
  if (!query) {
364
377
  output.printError('Query is required. Use --query or -q');
365
378
  return { success: false, exitCode: 1 };
366
379
  }
380
+ // #2760 SCM routed memory (v1 MVP) — classify query intent and
381
+ // print a routing hint. Only fires when --intent is NOT the default
382
+ // "mixed" AND --namespace was NOT explicitly passed. Intentionally
383
+ // does NOT mutate the search path — the routing is advisory in v1
384
+ // so the search backend's exact behavior is preserved. v2 will
385
+ // apply the routing when the search-backend interface adds a
386
+ // multi-namespace OR filter.
387
+ if (requestedIntent !== 'mixed' && (namespace === 'all' || !ctx.flags.namespace)) {
388
+ try {
389
+ const { resolveIntent } = await import('../memory/scm-classifier.js');
390
+ const resolved = resolveIntent(query, requestedIntent);
391
+ if (resolved.intent !== 'mixed' && resolved.namespaces.length > 0) {
392
+ output.printInfo(`SCM router → ${resolved.intent} (confidence ${(resolved.confidence * 100).toFixed(1)}%)`);
393
+ output.writeln(output.dim(` ${resolved.reason}`));
394
+ output.writeln(output.dim(` Suggested: rerun with --namespace ${resolved.namespaces[0]} to filter (or one of: ${resolved.namespaces.slice(1, 4).join(', ')}...)`));
395
+ }
396
+ else {
397
+ output.writeln(output.dim(`SCM router → mixed (${resolved.reason})`));
398
+ }
399
+ }
400
+ catch (err) {
401
+ output.writeln(output.dim(`SCM routing skipped: ${err instanceof Error ? err.message : String(err)}`));
402
+ }
403
+ }
367
404
  // Build/rebuild HNSW index if requested
368
405
  if (buildHnsw) {
369
406
  output.printInfo('Building HNSW index...');
@@ -1595,11 +1632,48 @@ const initMemoryCommand = {
1595
1632
  }
1596
1633
  }
1597
1634
  };
1635
+ // #2760 dream-cycle — SCM query classifier. Standalone subcommand so
1636
+ // users can inspect what intent a query maps to and pipe the mapped
1637
+ // namespaces into other tools (e.g. `memory search --namespace ...`).
1638
+ const classifyCommand = {
1639
+ name: 'classify',
1640
+ description: 'Classify a query into episodic/semantic/procedural intent (SCM router, dream-cycle #2760)',
1641
+ options: [
1642
+ { name: 'query', short: 'q', type: 'string', description: 'Query text to classify', required: true },
1643
+ { name: 'intent', type: 'string', choices: ['auto', 'mixed', 'episodic', 'semantic', 'procedural'], default: 'auto', description: 'Force a specific intent (default: auto)' },
1644
+ ],
1645
+ examples: [
1646
+ { command: 'claude-flow memory classify -q "when did we last touch auth"', description: 'Auto-classify (should return episodic)' },
1647
+ { command: 'claude-flow memory classify -q "how does JWT work" --format json', description: 'JSON output for pipelines' },
1648
+ ],
1649
+ action: async (ctx) => {
1650
+ const query = ctx.flags.query;
1651
+ const requested = ctx.flags.intent || 'auto';
1652
+ if (!query) {
1653
+ output.printError('Query is required. Use --query or -q');
1654
+ return { success: false, exitCode: 1 };
1655
+ }
1656
+ const { resolveIntent } = await import('../memory/scm-classifier.js');
1657
+ const resolved = resolveIntent(query, requested);
1658
+ if (ctx.flags.format === 'json') {
1659
+ output.printJson(resolved);
1660
+ return { success: true, data: resolved };
1661
+ }
1662
+ output.writeln();
1663
+ output.printBox(`Query: "${query}"\n` +
1664
+ `Intent: ${resolved.intent}\n` +
1665
+ `Confidence: ${(resolved.confidence * 100).toFixed(1)}%\n` +
1666
+ `Namespaces: ${resolved.namespaces.length > 0 ? resolved.namespaces.slice(0, 4).join(', ') + (resolved.namespaces.length > 4 ? '…' : '') : '(all — mixed retrieval)'}`, 'SCM Classifier (#2760)');
1667
+ output.writeln();
1668
+ output.writeln(output.dim(resolved.reason));
1669
+ return { success: true, data: resolved };
1670
+ },
1671
+ };
1598
1672
  // Main memory command
1599
1673
  export const memoryCommand = {
1600
1674
  name: 'memory',
1601
1675
  description: 'Memory management commands',
1602
- subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, purgeCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand, distillCommand, backupCommand],
1676
+ subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, purgeCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand, distillCommand, backupCommand, classifyCommand],
1603
1677
  options: [],
1604
1678
  examples: [
1605
1679
  { command: 'claude-flow memory store -k "key" -v "value"', description: 'Store data' },
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Selective Context Memory (SCM) query-intent classifier (#2760).
3
+ *
4
+ * Dream-cycle #2760 (SCM routed memory 86% LongMemEval): agents perform
5
+ * dramatically better on long-memory retrieval when the query is routed
6
+ * to the RIGHT memory tier — episodic (session recall) vs semantic
7
+ * (learned patterns) vs procedural (skills/recipes). Ruflo previously
8
+ * had all these tiers writing to different namespaces but the search
9
+ * command didn't discriminate — every query searched everything.
10
+ *
11
+ * v1 classifier: keyword-scored intent detection. Ships as a bounded
12
+ * MVP so users can opt in via `memory search --intent auto|episodic|
13
+ * semantic|procedural|mixed`. Default remains `mixed` (existing
14
+ * behavior) so no baseline retrieval is disturbed.
15
+ *
16
+ * v2 (future): embedding-based classifier trained on the trajectory
17
+ * store's actual routing outcomes.
18
+ */
19
+ export type MemoryIntent = 'episodic' | 'semantic' | 'procedural' | 'mixed';
20
+ export interface ClassifiedIntent {
21
+ intent: MemoryIntent;
22
+ confidence: number;
23
+ /** Per-intent scores for transparency; sums roughly to 1. */
24
+ scores: Record<Exclude<MemoryIntent, 'mixed'>, number>;
25
+ /** Namespaces the caller should search for this intent (relative to memory backend). */
26
+ namespaces: string[];
27
+ /** Human-readable rationale. */
28
+ reason: string;
29
+ }
30
+ /**
31
+ * Keyword catalog per intent — case-insensitive substring match.
32
+ * Order matters for ties: earlier categories win when scores tie.
33
+ */
34
+ declare const KEYWORDS: Record<Exclude<MemoryIntent, 'mixed'>, readonly string[]>;
35
+ /**
36
+ * Namespaces owned by each intent. These match ruflo's actual
37
+ * memory-write conventions:
38
+ * episodic → session/trajectory writes (hooks_post-task, session-checkpoints)
39
+ * semantic → pattern/learning writes (patterns/, learned-*, adr-patterns)
40
+ * procedural → skill/workflow writes (skills/, agents/, workflow-templates)
41
+ * A namespace listed under more than one intent means it's genuinely dual-nature.
42
+ */
43
+ declare const NAMESPACES: Record<Exclude<MemoryIntent, 'mixed'>, readonly string[]>;
44
+ export declare function classifyQueryIntent(query: string): ClassifiedIntent;
45
+ /**
46
+ * Given a user-requested intent (which may be `auto`), resolve to a
47
+ * concrete ClassifiedIntent for the given query.
48
+ */
49
+ export declare function resolveIntent(query: string, requested?: MemoryIntent | 'auto'): ClassifiedIntent;
50
+ export { KEYWORDS as INTENT_KEYWORDS, NAMESPACES as INTENT_NAMESPACES };
51
+ //# sourceMappingURL=scm-classifier.d.ts.map
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Selective Context Memory (SCM) query-intent classifier (#2760).
3
+ *
4
+ * Dream-cycle #2760 (SCM routed memory 86% LongMemEval): agents perform
5
+ * dramatically better on long-memory retrieval when the query is routed
6
+ * to the RIGHT memory tier — episodic (session recall) vs semantic
7
+ * (learned patterns) vs procedural (skills/recipes). Ruflo previously
8
+ * had all these tiers writing to different namespaces but the search
9
+ * command didn't discriminate — every query searched everything.
10
+ *
11
+ * v1 classifier: keyword-scored intent detection. Ships as a bounded
12
+ * MVP so users can opt in via `memory search --intent auto|episodic|
13
+ * semantic|procedural|mixed`. Default remains `mixed` (existing
14
+ * behavior) so no baseline retrieval is disturbed.
15
+ *
16
+ * v2 (future): embedding-based classifier trained on the trajectory
17
+ * store's actual routing outcomes.
18
+ */
19
+ /**
20
+ * Keyword catalog per intent — case-insensitive substring match.
21
+ * Order matters for ties: earlier categories win when scores tie.
22
+ */
23
+ const KEYWORDS = {
24
+ episodic: [
25
+ 'when', 'last time', 'yesterday', 'today', 'session',
26
+ 'recent', 'recently', 'trajectory', 'did i', 'did we',
27
+ 'what happened', 'the previous', 'the last', 'earlier',
28
+ 'this morning', 'this afternoon', 'this evening',
29
+ ],
30
+ semantic: [
31
+ 'how does', 'what is', 'why', 'why does', 'concept',
32
+ 'pattern', 'design', 'architecture', 'principle',
33
+ 'means', 'meaning', 'definition', 'explanation',
34
+ 'relationship between',
35
+ ],
36
+ procedural: [
37
+ 'how do i', 'how to', 'steps to', 'recipe', 'playbook',
38
+ 'procedure', 'walk me through', 'guide', 'runbook',
39
+ 'checklist', 'template', 'workflow', 'skill',
40
+ ],
41
+ };
42
+ /**
43
+ * Namespaces owned by each intent. These match ruflo's actual
44
+ * memory-write conventions:
45
+ * episodic → session/trajectory writes (hooks_post-task, session-checkpoints)
46
+ * semantic → pattern/learning writes (patterns/, learned-*, adr-patterns)
47
+ * procedural → skill/workflow writes (skills/, agents/, workflow-templates)
48
+ * A namespace listed under more than one intent means it's genuinely dual-nature.
49
+ */
50
+ const NAMESPACES = {
51
+ episodic: [
52
+ 'sessions', 'session-checkpoints', 'trajectory', 'trajectories',
53
+ 'routing-outcomes', 'commands', 'feedback',
54
+ ],
55
+ semantic: [
56
+ 'patterns', 'learned-patterns', 'adr-patterns', 'adr-edges',
57
+ 'reasoning-patterns', 'concepts',
58
+ ],
59
+ procedural: [
60
+ 'skills', 'agents', 'workflow-templates', 'playbooks', 'recipes',
61
+ ],
62
+ };
63
+ const CONFIDENCE_THRESHOLD = 0.35;
64
+ export function classifyQueryIntent(query) {
65
+ const q = query.toLowerCase();
66
+ const scores = {
67
+ episodic: 0,
68
+ semantic: 0,
69
+ procedural: 0,
70
+ };
71
+ // Score by keyword hits (weighted by phrase length — longer phrases
72
+ // are less ambiguous, e.g. "how do i" beats "how").
73
+ for (const intent of Object.keys(KEYWORDS)) {
74
+ for (const kw of KEYWORDS[intent]) {
75
+ if (q.includes(kw)) {
76
+ // Weight: longer keyword → higher confidence
77
+ scores[intent] += Math.max(1, kw.length / 6);
78
+ }
79
+ }
80
+ }
81
+ const total = scores.episodic + scores.semantic + scores.procedural;
82
+ if (total === 0) {
83
+ return {
84
+ intent: 'mixed',
85
+ confidence: 0,
86
+ scores,
87
+ namespaces: [],
88
+ reason: 'No intent keywords matched — falling back to mixed retrieval (search all namespaces).',
89
+ };
90
+ }
91
+ // Normalize
92
+ const normalized = {
93
+ episodic: scores.episodic / total,
94
+ semantic: scores.semantic / total,
95
+ procedural: scores.procedural / total,
96
+ };
97
+ // Pick the winner
98
+ const entries = [
99
+ ['episodic', normalized.episodic],
100
+ ['semantic', normalized.semantic],
101
+ ['procedural', normalized.procedural],
102
+ ];
103
+ entries.sort((a, b) => b[1] - a[1]);
104
+ const [winner, winnerScore] = entries[0];
105
+ // Low-confidence winner → mixed
106
+ if (winnerScore < CONFIDENCE_THRESHOLD) {
107
+ return {
108
+ intent: 'mixed',
109
+ confidence: winnerScore,
110
+ scores: normalized,
111
+ namespaces: [],
112
+ reason: `Top intent (${winner}) below confidence threshold ${CONFIDENCE_THRESHOLD} — falling back to mixed retrieval.`,
113
+ };
114
+ }
115
+ return {
116
+ intent: winner,
117
+ confidence: winnerScore,
118
+ scores: normalized,
119
+ namespaces: [...NAMESPACES[winner]],
120
+ reason: `Classified as ${winner} (confidence ${(winnerScore * 100).toFixed(1)}%) — route to ${NAMESPACES[winner].length} namespaces.`,
121
+ };
122
+ }
123
+ /**
124
+ * Given a user-requested intent (which may be `auto`), resolve to a
125
+ * concrete ClassifiedIntent for the given query.
126
+ */
127
+ export function resolveIntent(query, requested = 'auto') {
128
+ if (requested === 'auto')
129
+ return classifyQueryIntent(query);
130
+ if (requested === 'mixed') {
131
+ return {
132
+ intent: 'mixed',
133
+ confidence: 1,
134
+ scores: { episodic: 0, semantic: 0, procedural: 0 },
135
+ namespaces: [],
136
+ reason: 'Explicitly requested mixed retrieval (search all namespaces).',
137
+ };
138
+ }
139
+ return {
140
+ intent: requested,
141
+ confidence: 1,
142
+ scores: { episodic: 0, semantic: 0, procedural: 0, [requested]: 1 },
143
+ namespaces: [...NAMESPACES[requested]],
144
+ reason: `Explicitly requested ${requested} retrieval — route to ${NAMESPACES[requested].length} namespaces.`,
145
+ };
146
+ }
147
+ export { KEYWORDS as INTENT_KEYWORDS, NAMESPACES as INTENT_NAMESPACES };
148
+ //# sourceMappingURL=scm-classifier.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.32.17",
3
+ "version": "3.32.18",
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",