claude-flow 3.21.0 → 3.21.1

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.21.0",
3
+ "version": "3.21.1",
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",
@@ -13,6 +13,7 @@ import { execSync, exec } from 'child_process';
13
13
  import { promisify } from 'util';
14
14
  import { decodeKey, isEncryptionEnabled } from '../encryption/vault.js';
15
15
  import { isEncryptedBlob } from '../encryption/vault.js';
16
+ import { resolveMemoryPackageFromProject, readMemoryPackageVersion, recordMemoryPackagePath, } from '../init/memory-package-resolver.js';
16
17
  // Promisified exec with proper shell and env inheritance for cross-platform support
17
18
  const execAsync = promisify(exec);
18
19
  /**
@@ -244,6 +245,37 @@ async function checkMemoryDatabase() {
244
245
  }
245
246
  return { name: 'Memory Database', status: 'warn', message: 'Not initialized', fix: 'claude-flow memory configure --backend hybrid' };
246
247
  }
248
+ // #2545: Check that the self-learning bridge can actually load @claude-flow/memory
249
+ // the SAME way the SessionStart auto-memory hook does. On the documented `npx ruflo`
250
+ // path the package lands in the npx cache — unreachable from the project — so the
251
+ // hook silently no-op'd with no signal anywhere. This surfaces it.
252
+ async function checkLearningBridge() {
253
+ const cwd = process.cwd();
254
+ const hookPath = join(cwd, '.claude', 'helpers', 'auto-memory-hook.mjs');
255
+ // Only relevant once init has deployed the hook; otherwise stay quiet.
256
+ if (!existsSync(hookPath)) {
257
+ return {
258
+ name: 'Learning Bridge',
259
+ status: 'pass',
260
+ message: 'auto-memory hook not installed (run: npx ruflo@latest init)',
261
+ };
262
+ }
263
+ const distPath = resolveMemoryPackageFromProject(cwd);
264
+ if (distPath) {
265
+ const version = readMemoryPackageVersion(distPath);
266
+ return {
267
+ name: 'Learning Bridge',
268
+ status: 'pass',
269
+ message: `@claude-flow/memory resolvable${version ? ` (v${version})` : ''}`,
270
+ };
271
+ }
272
+ return {
273
+ name: 'Learning Bridge',
274
+ status: 'fail',
275
+ message: '@claude-flow/memory NOT resolvable — SessionStart self-learning imports are a silent no-op',
276
+ fix: 'npx ruflo@latest doctor --fix (records resolver sidecar) — or: npm i -D @claude-flow/memory',
277
+ };
278
+ }
247
279
  // Check API keys
248
280
  async function checkApiKeys() {
249
281
  const keys = ['ANTHROPIC_API_KEY', 'CLAUDE_API_KEY', 'OPENAI_API_KEY'];
@@ -1036,6 +1068,7 @@ export const doctorCommand = {
1036
1068
  checkStaleSettingsNpx, // #2448 — runaway `npx @latest` in statusLine/hooks
1037
1069
  checkDaemonStatus,
1038
1070
  checkMemoryDatabase,
1071
+ checkLearningBridge, // #2545 — can the auto-memory hook actually load @claude-flow/memory?
1039
1072
  checkApiKeys,
1040
1073
  checkMcpServers,
1041
1074
  checkAIDefence, // #1807
@@ -1057,6 +1090,8 @@ export const doctorCommand = {
1057
1090
  'stale-settings': checkStaleSettingsNpx, // #2448
1058
1091
  'daemon': checkDaemonStatus,
1059
1092
  'memory': checkMemoryDatabase,
1093
+ 'learning': checkLearningBridge, // #2545
1094
+ 'learning-bridge': checkLearningBridge, // #2545
1060
1095
  'api': checkApiKeys,
1061
1096
  'git': checkGit,
1062
1097
  'mcp': checkMcpServers,
@@ -1107,6 +1142,27 @@ export const doctorCommand = {
1107
1142
  spinner.stop();
1108
1143
  output.writeln(output.error('Failed to run health checks'));
1109
1144
  }
1145
+ // #2545: --fix / --install can actually repair the Learning Bridge by
1146
+ // recording the resolver sidecar. When doctor runs via `npx ruflo`, the CLI
1147
+ // CAN resolve its optional @claude-flow/memory dep (it is in the same npx
1148
+ // cache), so writing the sidecar makes the SessionStart hook find it.
1149
+ if ((showFix || autoInstall)) {
1150
+ const lbResult = results.find(r => r.name === 'Learning Bridge');
1151
+ if (lbResult && lbResult.status === 'fail') {
1152
+ const record = recordMemoryPackagePath(process.cwd(), 'doctor');
1153
+ if (record) {
1154
+ const newCheck = await checkLearningBridge();
1155
+ const idx = results.findIndex(r => r.name === 'Learning Bridge');
1156
+ if (idx !== -1)
1157
+ results[idx] = newCheck;
1158
+ const fixIdx = fixes.findIndex(f => f.startsWith('Learning Bridge:'));
1159
+ if (fixIdx !== -1 && newCheck.status === 'pass')
1160
+ fixes.splice(fixIdx, 1);
1161
+ output.writeln(output.success(`Repaired Learning Bridge — wrote .claude-flow/memory-package.json → ${record.distPath}`));
1162
+ output.writeln(formatCheck(newCheck));
1163
+ }
1164
+ }
1165
+ }
1110
1166
  // Auto-install missing dependencies if requested
1111
1167
  if (autoInstall) {
1112
1168
  const claudeCodeResult = results.find(r => r.name === 'Claude Code CLI');
@@ -16,6 +16,7 @@ import { generateMCPJson } from './mcp-generator.js';
16
16
  import { generateStatuslineScript } from './statusline-generator.js';
17
17
  import { generatePreCommitHook, generatePostCommitHook, generateSessionManager, generateAgentRouter, generateMemoryHelper, generateHookHandler, generateIntelligenceStub, generateAutoMemoryHook, generateRufloHookCjs, } from './helpers-generator.js';
18
18
  import { generateClaudeMd } from './claudemd-generator.js';
19
+ import { recordMemoryPackagePath } from './memory-package-resolver.js';
19
20
  /**
20
21
  * Skills to copy based on configuration
21
22
  */
@@ -196,6 +197,16 @@ export async function executeInit(options) {
196
197
  // Generate helpers
197
198
  if (options.components.helpers) {
198
199
  await writeHelpers(targetDir, options, result);
200
+ // #2545: The auto-memory hook needs @claude-flow/memory, which is an
201
+ // optionalDependency of the CLI and lands in the npx cache — unreachable
202
+ // by a node_modules walk-up from the user's project. Resolve it from the
203
+ // CLI's own context now (where it IS present) and record the absolute
204
+ // path in a machine-local sidecar the hook reads first. Best-effort:
205
+ // when the optional dep is absent the hook fails loud and doctor flags it.
206
+ const memRecord = recordMemoryPackagePath(targetDir, 'init');
207
+ if (memRecord) {
208
+ result.created.files.push('.claude-flow/memory-package.json');
209
+ }
199
210
  }
200
211
  // Generate statusline
201
212
  if (options.components.statusline) {
@@ -472,6 +483,12 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
472
483
  catch { }
473
484
  }
474
485
  }
486
+ // #2545: (re)record the resolved @claude-flow/memory path so the auto-memory
487
+ // hook can find it on the npx install path. Best-effort — see executeInit.
488
+ const memRecord = recordMemoryPackagePath(targetDir, 'upgrade');
489
+ if (memRecord) {
490
+ result.updated.push('.claude-flow/memory-package.json');
491
+ }
475
492
  // 1. ALWAYS update statusline helper (force overwrite)
476
493
  const statuslinePath = path.join(targetDir, '.claude', 'helpers', 'statusline.cjs');
477
494
  // Use default options with statusline config
@@ -863,13 +863,37 @@ const DATA_DIR = join(PROJECT_ROOT, '.claude-flow', 'data');
863
863
  const STORE_PATH = join(DATA_DIR, 'auto-memory-store.json');
864
864
 
865
865
  const DIM = '\\x1b[2m';
866
+ const YELLOW = '\\x1b[0;33m';
866
867
  const RESET = '\\x1b[0m';
867
868
  const dim = (msg) => console.log(\` \${DIM}\${msg}\${RESET}\`);
868
869
 
870
+ // #2545: fail LOUD instead of a silent dim skip when @claude-flow/memory is
871
+ // unresolvable — self-learning imports are a no-op and the user must be told.
872
+ function warnMemoryUnavailable() {
873
+ const l1 = \`[AutoMemory] @claude-flow/memory not resolvable from \${PROJECT_ROOT} — self-learning imports are DISABLED.\`;
874
+ const l2 = ' Fix: npm i -D @claude-flow/memory (or re-run: npx ruflo@latest init, then npx ruflo@latest doctor --fix)';
875
+ console.log(\`\${YELLOW}\${l1}\${RESET}\`);
876
+ console.log(\`\${YELLOW}\${l2}\${RESET}\`);
877
+ process.stderr.write(\`\${l1}\\n\${l2}\\n\`);
878
+ }
879
+
869
880
  // Ensure data dir
870
881
  if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
871
882
 
872
883
  async function loadMemoryPackage() {
884
+ // Strategy 0 (#2545): sidecar recorded by \`init\` / \`doctor --fix\`. On the npx
885
+ // path @claude-flow/memory lands in the npx cache (unreachable by walk-up), so
886
+ // init records its absolute path here — the only strategy that works there.
887
+ try {
888
+ const sidecar = join(PROJECT_ROOT, '.claude-flow', 'memory-package.json');
889
+ if (existsSync(sidecar)) {
890
+ const rec = JSON.parse(readFileSync(sidecar, 'utf-8'));
891
+ if (rec && rec.distPath && existsSync(rec.distPath)) {
892
+ return await import(\`file://\${rec.distPath}\`);
893
+ }
894
+ }
895
+ } catch { /* fall through */ }
896
+
873
897
  // Strategy 1: Use createRequire for CJS-style resolution (handles nested node_modules
874
898
  // when installed as a transitive dependency via npx ruflo / npx claude-flow)
875
899
  try {
@@ -899,7 +923,7 @@ async function doImport() {
899
923
  const memPkg = await loadMemoryPackage();
900
924
 
901
925
  if (!memPkg || !memPkg.AutoMemoryBridge) {
902
- dim('Memory package not available — auto memory import skipped (non-critical)');
926
+ warnMemoryUnavailable();
903
927
  return;
904
928
  }
905
929
 
@@ -916,7 +940,7 @@ async function doSync() {
916
940
  const memPkg = await loadMemoryPackage();
917
941
 
918
942
  if (!memPkg || !memPkg.AutoMemoryBridge) {
919
- dim('Memory package not available — sync skipped (non-critical)');
943
+ warnMemoryUnavailable();
920
944
  return;
921
945
  }
922
946
 
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Memory Package Resolver (#2545)
3
+ *
4
+ * `@claude-flow/memory` is an *optionalDependency* of `@claude-flow/cli`. On the
5
+ * documented `npx ruflo` install path it lands in the npx cache
6
+ * (`~/.npm/_npx/<hash>/node_modules`), which is NOT on the node_modules walk-up
7
+ * path from the user's project. The SessionStart auto-memory hook therefore
8
+ * could never resolve it and self-learning silently no-op'd.
9
+ *
10
+ * At init time, however, the CLI *can* resolve the package from its own module
11
+ * context (it is installed alongside the CLI in that same npx cache). We resolve
12
+ * it once and record the absolute path in a machine-local project sidecar
13
+ * (`.claude-flow/memory-package.json`). The hook reads this sidecar first, so it
14
+ * reuses the copy npx already downloaded — no second install, no vendoring.
15
+ *
16
+ * This module is deliberately dependency-free and best-effort: nothing here ever
17
+ * throws into the init/doctor flow.
18
+ */
19
+ export declare const MEMORY_PACKAGE = "@claude-flow/memory";
20
+ /** Project-relative path of the resolver sidecar written by init / doctor --fix. */
21
+ export declare const MEMORY_SIDECAR_REL: string;
22
+ export interface MemoryPackageRecord {
23
+ /** Absolute path to the package's main entry (dist/index.js). */
24
+ distPath: string;
25
+ /** Resolved package version, if readable. */
26
+ version: string | null;
27
+ /** What produced this record ("init" | "doctor" | "upgrade"). */
28
+ resolvedBy: string;
29
+ /** ISO timestamp of resolution. */
30
+ resolvedAt: string;
31
+ }
32
+ /**
33
+ * Resolve `@claude-flow/memory`'s main entry from the CLI's own module context.
34
+ * Returns the absolute dist path, or null when the optional dependency is absent
35
+ * (e.g. installed with `--omit=optional`).
36
+ */
37
+ export declare function resolveMemoryPackageFromCli(): string | null;
38
+ /**
39
+ * Resolve `@claude-flow/memory` the same way the runtime hook does, from a target
40
+ * project directory: sidecar → project package.json → node_modules walk-up.
41
+ * Used by `doctor` so its verdict matches what the hook will actually experience.
42
+ */
43
+ export declare function resolveMemoryPackageFromProject(targetDir: string): string | null;
44
+ /** Read the version of the resolved memory package (dist/index.js → ../package.json). */
45
+ export declare function readMemoryPackageVersion(distPath: string): string | null;
46
+ /**
47
+ * Best-effort: resolve `@claude-flow/memory` from the CLI and record its path in
48
+ * the project sidecar so the runtime hook can find it on the npx install path.
49
+ * Returns the written record, or null when the package is not resolvable from the
50
+ * CLI (in which case the hook fails loud and `doctor` flags it).
51
+ */
52
+ export declare function recordMemoryPackagePath(targetDir: string, resolvedBy?: string): MemoryPackageRecord | null;
53
+ //# sourceMappingURL=memory-package-resolver.d.ts.map
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Memory Package Resolver (#2545)
3
+ *
4
+ * `@claude-flow/memory` is an *optionalDependency* of `@claude-flow/cli`. On the
5
+ * documented `npx ruflo` install path it lands in the npx cache
6
+ * (`~/.npm/_npx/<hash>/node_modules`), which is NOT on the node_modules walk-up
7
+ * path from the user's project. The SessionStart auto-memory hook therefore
8
+ * could never resolve it and self-learning silently no-op'd.
9
+ *
10
+ * At init time, however, the CLI *can* resolve the package from its own module
11
+ * context (it is installed alongside the CLI in that same npx cache). We resolve
12
+ * it once and record the absolute path in a machine-local project sidecar
13
+ * (`.claude-flow/memory-package.json`). The hook reads this sidecar first, so it
14
+ * reuses the copy npx already downloaded — no second install, no vendoring.
15
+ *
16
+ * This module is deliberately dependency-free and best-effort: nothing here ever
17
+ * throws into the init/doctor flow.
18
+ */
19
+ import { createRequire } from 'module';
20
+ import * as fs from 'fs';
21
+ import * as path from 'path';
22
+ export const MEMORY_PACKAGE = '@claude-flow/memory';
23
+ /** Project-relative path of the resolver sidecar written by init / doctor --fix. */
24
+ export const MEMORY_SIDECAR_REL = path.join('.claude-flow', 'memory-package.json');
25
+ /**
26
+ * Resolve `@claude-flow/memory`'s main entry from the CLI's own module context.
27
+ * Returns the absolute dist path, or null when the optional dependency is absent
28
+ * (e.g. installed with `--omit=optional`).
29
+ */
30
+ export function resolveMemoryPackageFromCli() {
31
+ try {
32
+ const require = createRequire(import.meta.url);
33
+ return require.resolve(MEMORY_PACKAGE);
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ /**
40
+ * Resolve `@claude-flow/memory` the same way the runtime hook does, from a target
41
+ * project directory: sidecar → project package.json → node_modules walk-up.
42
+ * Used by `doctor` so its verdict matches what the hook will actually experience.
43
+ */
44
+ export function resolveMemoryPackageFromProject(targetDir) {
45
+ // 1. Sidecar written by a previous init / doctor --fix
46
+ try {
47
+ const sidecar = path.join(targetDir, MEMORY_SIDECAR_REL);
48
+ if (fs.existsSync(sidecar)) {
49
+ const rec = JSON.parse(fs.readFileSync(sidecar, 'utf-8'));
50
+ if (rec?.distPath && fs.existsSync(rec.distPath))
51
+ return rec.distPath;
52
+ }
53
+ }
54
+ catch {
55
+ /* fall through */
56
+ }
57
+ // 2. createRequire from the project's package.json (direct/transitive dep)
58
+ try {
59
+ const require = createRequire(path.join(targetDir, 'package.json'));
60
+ return require.resolve(MEMORY_PACKAGE);
61
+ }
62
+ catch {
63
+ /* fall through */
64
+ }
65
+ // 3. node_modules walk-up from the project root
66
+ let dir = path.resolve(targetDir);
67
+ // eslint-disable-next-line no-constant-condition
68
+ while (true) {
69
+ const candidate = path.join(dir, 'node_modules', '@claude-flow', 'memory', 'dist', 'index.js');
70
+ if (fs.existsSync(candidate))
71
+ return candidate;
72
+ const parent = path.dirname(dir);
73
+ if (parent === dir)
74
+ break;
75
+ dir = parent;
76
+ }
77
+ return null;
78
+ }
79
+ /** Read the version of the resolved memory package (dist/index.js → ../package.json). */
80
+ export function readMemoryPackageVersion(distPath) {
81
+ try {
82
+ const pkgJson = path.resolve(path.dirname(distPath), '..', 'package.json');
83
+ if (fs.existsSync(pkgJson)) {
84
+ const parsed = JSON.parse(fs.readFileSync(pkgJson, 'utf-8'));
85
+ return parsed.version ?? null;
86
+ }
87
+ }
88
+ catch {
89
+ /* ignore */
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Best-effort: resolve `@claude-flow/memory` from the CLI and record its path in
95
+ * the project sidecar so the runtime hook can find it on the npx install path.
96
+ * Returns the written record, or null when the package is not resolvable from the
97
+ * CLI (in which case the hook fails loud and `doctor` flags it).
98
+ */
99
+ export function recordMemoryPackagePath(targetDir, resolvedBy = 'init') {
100
+ const distPath = resolveMemoryPackageFromCli();
101
+ if (!distPath)
102
+ return null;
103
+ const record = {
104
+ distPath,
105
+ version: readMemoryPackageVersion(distPath),
106
+ resolvedBy,
107
+ resolvedAt: new Date().toISOString(),
108
+ };
109
+ try {
110
+ fs.mkdirSync(path.join(targetDir, '.claude-flow'), { recursive: true });
111
+ fs.writeFileSync(path.join(targetDir, MEMORY_SIDECAR_REL), JSON.stringify(record, null, 2), 'utf-8');
112
+ return record;
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ //# sourceMappingURL=memory-package-resolver.js.map
@@ -680,6 +680,31 @@ export async function bridgeStoreEntry(options) {
680
680
  catch { /* vector_indexes may not exist on legacy DBs — fall through */ }
681
681
  const stmt = ctx.db.prepare(insertSql);
682
682
  stmt.run(id, key, namespace, value, embeddingJson, dimensions || null, model, tags.length > 0 ? JSON.stringify(tags) : null, '{}', now, now, ttl ? now + (ttl * 1000) : null);
683
+ // #2558: keep `vector_indexes.total_vectors` accurate so status/tooling
684
+ // stop reporting "HNSW index: 0 vectors" while embedded entries exist.
685
+ try {
686
+ ctx.db
687
+ .prepare(`UPDATE vector_indexes SET
688
+ total_vectors = (SELECT COUNT(*) FROM memory_entries
689
+ WHERE namespace = ? AND embedding IS NOT NULL),
690
+ updated_at = ?
691
+ WHERE name = ?`)
692
+ .run(namespace, now, namespace);
693
+ }
694
+ catch { /* vector_indexes may not exist on legacy DBs — non-fatal */ }
695
+ // #2558: better-sqlite3 opens the DB in WAL mode and, for the small write
696
+ // volumes typical of CLI usage, may never reach the auto-checkpoint
697
+ // threshold — leaving committed rows only in the -wal file. WAL-blind
698
+ // readers (the sql.js fallback search path; the statusline's read-only
699
+ // `sqlite3` vector count) then see a stale/empty main DB file and report
700
+ // "0 vectors" / empty search. A PASSIVE checkpoint flushes committed pages
701
+ // into the main file without blocking writers. Best-effort, never fatal.
702
+ try {
703
+ if (typeof ctx.db.pragma === 'function') {
704
+ ctx.db.pragma('wal_checkpoint(PASSIVE)');
705
+ }
706
+ }
707
+ catch { /* non-WAL, busy, or unsupported — non-fatal */ }
683
708
  // Phase 2: Write-through to TieredCache
684
709
  const safeNs = String(namespace).replace(/:/g, '_');
685
710
  const safeKey = String(key).replace(/:/g, '_');
@@ -770,17 +795,33 @@ export async function bridgeSearchEntries(options) {
770
795
  // Normalize BM25 to 0-1 range (cap at 10 for normalization)
771
796
  bm25ScoreVal = Math.min(bm25ScoreVal / 10, 1.0);
772
797
  }
773
- // Reciprocal rank fusion: combine semantic and BM25
774
- // Weight: 0.7 semantic + 0.3 BM25 when both embeddings present
775
- // Fall back to BM25-only when either query or row lacks an embedding
776
- const score = semanticScore > 0
777
- ? (0.7 * semanticScore + 0.3 * bm25ScoreVal)
778
- : bm25ScoreVal;
798
+ // #2558: keyword-coverage floor for the lexical signal.
799
+ // BM25's IDF collapses toward zero when a term appears in most/all
800
+ // documents (routine on small memory corpora), and the /10 normalization
801
+ // crushed exact-keyword hits well below the default 0.3 threshold — so
802
+ // `memory search` recalled NOTHING even when the content literally
803
+ // contained the query term (issue #2558: "keyword recall random"). The
804
+ // pre-BM25 fallback guaranteed keyword recall via matchCount/words*0.5;
805
+ // this restores that guarantee. `coverage` is the fraction of query
806
+ // terms present in the document — a full-coverage hit must always be
807
+ // recallable regardless of IDF.
808
+ const contentLower = String(row.content || '').toLowerCase();
809
+ const matchedTerms = queryTerms.filter(t => contentLower.includes(t)).length;
810
+ const coverage = queryTerms.length > 0 ? matchedTerms / queryTerms.length : 0;
811
+ const lexicalScore = Math.max(bm25ScoreVal, coverage);
812
+ // Recall-friendly fusion: a strong semantic OR lexical signal alone must
813
+ // clear the threshold. `blended` (0.6 semantic + 0.4 lexical) drives
814
+ // ranking; taking max() with the raw semantic score means (a) a genuinely
815
+ // similar entry is never dropped just because it lacks the query's exact
816
+ // words, and (b) a full-coverage keyword hit (lexical=1 → blended≥0.4) is
817
+ // never dropped just because its embedding cosine is low or negative.
818
+ const blended = 0.6 * Math.max(0, semanticScore) + 0.4 * lexicalScore;
819
+ const score = Math.max(blended, semanticScore);
779
820
  if (score >= threshold) {
780
821
  // Phase 4: ExplainableRecall provenance
781
822
  const provenance = queryEmbedding
782
- ? `semantic:${semanticScore.toFixed(3)}+bm25:${bm25ScoreVal.toFixed(3)}`
783
- : `bm25:${bm25ScoreVal.toFixed(3)}`;
823
+ ? `semantic:${semanticScore.toFixed(3)}+lexical:${lexicalScore.toFixed(3)}`
824
+ : `lexical:${lexicalScore.toFixed(3)}`;
784
825
  results.push({
785
826
  id: String(row.id).substring(0, 12),
786
827
  key: row.key || String(row.id).substring(0, 15),
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.21.0",
3
+ "version": "3.21.1",
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",