claude-flow 3.57.0 → 3.57.2

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 (33) hide show
  1. package/.claude/helpers/intelligence.cjs +3 -5
  2. package/.claude/proven-config.json +1 -1
  3. package/README.md +12 -3
  4. package/node_modules/@claude-flow/codex/README.md +9 -9
  5. package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
  6. package/node_modules/@claude-flow/codex/dist/dual-mode/cli.js +3 -3
  7. package/node_modules/@claude-flow/codex/dist/dual-mode/cli.js.map +1 -1
  8. package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
  9. package/package.json +3 -2
  10. package/v3/@claude-flow/cli/README.md +12 -3
  11. package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
  12. package/v3/@claude-flow/cli/dist/src/commands/hooks.js +20 -1
  13. package/v3/@claude-flow/cli/dist/src/commands/memory.js +25 -1
  14. package/v3/@claude-flow/cli/dist/src/commands/workflow.js +55 -15
  15. package/v3/@claude-flow/cli/dist/src/init/executor.js +9 -5
  16. package/v3/@claude-flow/cli/dist/src/init/helper-companions.d.ts +1 -1
  17. package/v3/@claude-flow/cli/dist/src/init/helper-companions.js +4 -3
  18. package/v3/@claude-flow/cli/dist/src/mcp-tools/hooks-tools.js +9 -3
  19. package/v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +58 -9
  20. package/v3/@claude-flow/cli/dist/src/mcp-tools/workflow-tools.js +2 -1
  21. package/v3/@claude-flow/cli/dist/src/memory/graph-edge-writer.d.ts +16 -4
  22. package/v3/@claude-flow/cli/dist/src/memory/graph-edge-writer.js +19 -7
  23. package/v3/@claude-flow/cli/dist/src/memory/intelligence.js +4 -0
  24. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +12 -5
  25. package/v3/@claude-flow/cli/dist/src/missions/schemas.d.ts +113 -113
  26. package/v3/@claude-flow/cli/dist/src/mods/command-registry/schema.d.ts +193 -193
  27. package/v3/@claude-flow/cli/dist/src/services/memory-backup.d.ts +6 -0
  28. package/v3/@claude-flow/cli/dist/src/services/memory-backup.js +109 -81
  29. package/v3/@claude-flow/cli/dist/src/services/policy-ledger-anchor.d.ts +2 -0
  30. package/v3/@claude-flow/cli/dist/src/services/policy-ledger-anchor.js +4 -4
  31. package/v3/@claude-flow/cli/dist/src/services/policy-runtime.js +54 -3
  32. package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +4 -0
  33. package/v3/@claude-flow/cli/package.json +5 -4
@@ -227,15 +227,31 @@ function loadLegacyStore() {
227
227
  /**
228
228
  * Mark migration as complete
229
229
  */
230
- function markMigrationComplete() {
230
+ function markMigrationComplete(counts) {
231
231
  const legacyDir = resolve(LEGACY_MEMORY_DIR);
232
232
  if (!existsSync(legacyDir))
233
233
  mkdirSync(legacyDir, { recursive: true });
234
234
  writeFileSync(resolve(join(LEGACY_MEMORY_DIR, MIGRATION_MARKER)), JSON.stringify({
235
235
  migratedAt: new Date().toISOString(),
236
236
  version: '3.0.0',
237
+ ...(counts ?? {}),
237
238
  }), 'utf-8');
238
239
  }
240
+ /**
241
+ * Counts recorded by the migration that wrote the marker, or null when no
242
+ * marker (or an older marker without counts) is present.
243
+ */
244
+ function readMigrationCounts() {
245
+ try {
246
+ const marker = JSON.parse(readFileSync(resolve(join(LEGACY_MEMORY_DIR, MIGRATION_MARKER)), 'utf-8'));
247
+ return typeof marker?.migrated === 'number' && typeof marker?.total === 'number'
248
+ ? { migrated: marker.migrated, total: marker.total }
249
+ : null;
250
+ }
251
+ catch {
252
+ return null;
253
+ }
254
+ }
239
255
  /**
240
256
  * Lazy-load memory initializer functions to avoid circular deps
241
257
  */
@@ -391,7 +407,7 @@ async function ensureInitialized(dbPath) {
391
407
  }
392
408
  }
393
409
  console.error(`[MCP Memory] Migrated ${migrated}/${Object.keys(legacyStore.entries).length} entries`);
394
- markMigrationComplete();
410
+ markMigrationComplete({ migrated, total: Object.keys(legacyStore.entries).length });
395
411
  }
396
412
  }
397
413
  }
@@ -636,7 +652,11 @@ export const memoryTools = [
636
652
  });
637
653
  return {
638
654
  results: r.results.map(e => ({
639
- id: e.id,
655
+ // #2271: searchEntries() truncates ids to 12 chars ("entry_" +
656
+ // the leading digits of Date.now()), so entries written within
657
+ // ~2.8h share one id and RRF fused them into a single result.
658
+ // SmartRetrieval dedupes on id: give it the (namespace, key) tuple.
659
+ id: JSON.stringify([e.namespace, e.key]),
640
660
  key: e.key,
641
661
  content: e.content,
642
662
  score: e.score,
@@ -966,11 +986,17 @@ export const memoryTools = [
966
986
  },
967
987
  handler: async (input) => {
968
988
  const force = input.force;
969
- // Remove migration marker if forcing
989
+ // Remove the migration marker if forcing. hasLegacyStore() checks the marker
990
+ // beside the legacy store, so that is the one force must clear (#4194);
991
+ // the old .swarm marker path is cleared too for compatibility.
970
992
  if (force) {
971
- const markerPath = getMigrationMarkerPath();
972
- if (existsSync(markerPath)) {
973
- unlinkSync(markerPath);
993
+ for (const markerPath of [
994
+ resolve(join(LEGACY_MEMORY_DIR, MIGRATION_MARKER)),
995
+ getMigrationMarkerPath(),
996
+ ]) {
997
+ if (existsSync(markerPath)) {
998
+ unlinkSync(markerPath);
999
+ }
974
1000
  }
975
1001
  }
976
1002
  // Check for legacy data
@@ -982,12 +1008,35 @@ export const memoryTools = [
982
1008
  migrated: 0,
983
1009
  };
984
1010
  }
1011
+ // A marker beside the store means a migration already ran; ensureInitialized
1012
+ // would move nothing, so say so instead of reporting the store's size.
1013
+ if (!hasLegacyStore()) {
1014
+ return {
1015
+ success: true,
1016
+ message: 'Legacy store already migrated (marker present); nothing was moved. Pass force: true to re-run.',
1017
+ migrated: 0,
1018
+ total: Object.keys(legacyStore.entries).length,
1019
+ };
1020
+ }
985
1021
  // Run migration via ensureInitialized
986
1022
  await ensureInitialized();
1023
+ // ensureInitialized swallows errors and records what it moved in the marker.
1024
+ const counts = readMigrationCounts();
1025
+ if (!counts) {
1026
+ return {
1027
+ success: false,
1028
+ message: 'Migration did not complete; no entries were recorded as migrated. See the MCP server log.',
1029
+ migrated: 0,
1030
+ total: Object.keys(legacyStore.entries).length,
1031
+ };
1032
+ }
987
1033
  return {
988
1034
  success: true,
989
- message: 'Migration completed',
990
- migrated: Object.keys(legacyStore.entries).length,
1035
+ message: counts.migrated === counts.total
1036
+ ? 'Migration completed'
1037
+ : `Migration completed with failures: ${counts.migrated} of ${counts.total} entries migrated`,
1038
+ migrated: counts.migrated,
1039
+ total: counts.total,
991
1040
  backend: await describeBackend(),
992
1041
  };
993
1042
  },
@@ -577,7 +577,8 @@ export const workflowTools = [
577
577
  const store = loadWorkflowStore();
578
578
  let workflows = Object.values(store.workflows);
579
579
  // Apply filters
580
- if (input.status) {
580
+ // 'all' is the CLI's explicit "no filter" value (`workflow list` sends it by default).
581
+ if (input.status && input.status !== 'all') {
581
582
  workflows = workflows.filter(w => w.status === input.status);
582
583
  }
583
584
  // Sort by creation date (newest first)
@@ -30,10 +30,12 @@
30
30
  * @module v3/cli/memory/graph-edge-writer
31
31
  */
32
32
  /**
33
- * True iff the memory.db bridge at `customDbPath` (or the default location)
34
- * is currently RFE1-encrypted-at-rest. Callers that receive `null` from
35
- * getBridgeDb()/insertGraphEdge() can use this to avoid recommending the
36
- * destructive `memory init` command for this specific, non-corrupt case.
33
+ * True iff the memory.db bridge at `customDbPath` — or, when omitted, the
34
+ * path `resolveDbPath()` resolves from the `CLAUDE_FLOW_DB_PATH` env binding
35
+ * / memory root default (#4291) — is currently RFE1-encrypted-at-rest.
36
+ * Callers that receive `null` from getBridgeDb()/insertGraphEdge() can use
37
+ * this to avoid recommending the destructive `memory init` command for this
38
+ * specific, non-corrupt case.
37
39
  */
38
40
  export declare function isBridgeDbEncryptedAtRest(customDbPath?: string): boolean;
39
41
  /** Test-only: clear the once-per-path warning dedup set. */
@@ -60,6 +62,16 @@ export declare function releaseBridgeDb(dbPath?: string): boolean;
60
62
  * #2431 fix: better-sqlite3 + WAL mode replaces sql.js + whole-file
61
63
  * writeFileSync. Eliminates the dual-write race that corrupted memory.db
62
64
  * when called alongside the memory bridge's better-sqlite3 writer.
65
+ *
66
+ * #4291 fix: the file is resolved via `resolveDbPath()` — the project's one
67
+ * documented path-priority rule (explicit `customDbPath` argument wins, then
68
+ * the `CLAUDE_FLOW_DB_PATH` env binding, then the plain `memory.db` default
69
+ * under the memory root) — instead of a local `customDbPath ?? <default>`
70
+ * expression that silently ignored `CLAUDE_FLOW_DB_PATH`. A caller that
71
+ * explicitly selected a store via that env var no longer gets answers read
72
+ * from a different, unselected database file. When the resolved file is
73
+ * missing (and `createIfMissing` is false) or encrypted at rest, this
74
+ * refuses (returns null) rather than falling back to any other store.
63
75
  */
64
76
  export declare function getBridgeDb(customDbPath?: string, opts?: {
65
77
  createIfMissing?: boolean;
@@ -33,7 +33,7 @@ import * as path from 'path';
33
33
  import * as fs from 'fs';
34
34
  import * as crypto from 'crypto';
35
35
  import { execFileSync } from 'child_process';
36
- import { getMemoryRoot } from './memory-initializer.js';
36
+ import { resolveDbPath } from './memory-initializer.js';
37
37
  import { encodeEmbedding } from './embedding-quantization.js';
38
38
  import { loadBetterSqlite3 } from './shared-sqlite.js';
39
39
  import { isEncryptedBlob } from '../encryption/vault.js';
@@ -125,13 +125,15 @@ function warnRfe1EncryptedOnce(dbPath) {
125
125
  'See #2889 (https://github.com/ruvnet/ruflo/issues/2889) for details and recovery options.');
126
126
  }
127
127
  /**
128
- * True iff the memory.db bridge at `customDbPath` (or the default location)
129
- * is currently RFE1-encrypted-at-rest. Callers that receive `null` from
130
- * getBridgeDb()/insertGraphEdge() can use this to avoid recommending the
131
- * destructive `memory init` command for this specific, non-corrupt case.
128
+ * True iff the memory.db bridge at `customDbPath` — or, when omitted, the
129
+ * path `resolveDbPath()` resolves from the `CLAUDE_FLOW_DB_PATH` env binding
130
+ * / memory root default (#4291) — is currently RFE1-encrypted-at-rest.
131
+ * Callers that receive `null` from getBridgeDb()/insertGraphEdge() can use
132
+ * this to avoid recommending the destructive `memory init` command for this
133
+ * specific, non-corrupt case.
132
134
  */
133
135
  export function isBridgeDbEncryptedAtRest(customDbPath) {
134
- const dbPath = customDbPath ?? path.join(getMemoryRoot(), 'memory.db');
136
+ const dbPath = resolveDbPath(customDbPath);
135
137
  return fs.existsSync(dbPath) && isRfe1EncryptedAtRest(dbPath);
136
138
  }
137
139
  /** Test-only: clear the once-per-path warning dedup set. */
@@ -222,9 +224,19 @@ export function releaseBridgeDb(dbPath) {
222
224
  * #2431 fix: better-sqlite3 + WAL mode replaces sql.js + whole-file
223
225
  * writeFileSync. Eliminates the dual-write race that corrupted memory.db
224
226
  * when called alongside the memory bridge's better-sqlite3 writer.
227
+ *
228
+ * #4291 fix: the file is resolved via `resolveDbPath()` — the project's one
229
+ * documented path-priority rule (explicit `customDbPath` argument wins, then
230
+ * the `CLAUDE_FLOW_DB_PATH` env binding, then the plain `memory.db` default
231
+ * under the memory root) — instead of a local `customDbPath ?? <default>`
232
+ * expression that silently ignored `CLAUDE_FLOW_DB_PATH`. A caller that
233
+ * explicitly selected a store via that env var no longer gets answers read
234
+ * from a different, unselected database file. When the resolved file is
235
+ * missing (and `createIfMissing` is false) or encrypted at rest, this
236
+ * refuses (returns null) rather than falling back to any other store.
225
237
  */
226
238
  export async function getBridgeDb(customDbPath, opts) {
227
- const dbPath = customDbPath ?? path.join(getMemoryRoot(), 'memory.db');
239
+ const dbPath = resolveDbPath(customDbPath);
228
240
  const createIfMissing = opts?.createIfMissing === true;
229
241
  if (_db && _dbPath === dbPath) {
230
242
  armIdleRelease();
@@ -1077,6 +1077,10 @@ export async function recordTrajectory(steps, verdict) {
1077
1077
  }
1078
1078
  bumpStat('trajectoriesRecorded');
1079
1079
  globalStats.lastAdaptation = Date.now();
1080
+ // #4283: the bank's own save is debounced, and the one-shot bins exit as
1081
+ // soon as the command resolves, so write the patterns now. Otherwise
1082
+ // stats.json counts patterns that never reach patterns.json.
1083
+ reasoningBank?.flushToDisk();
1080
1084
  savePersistedStats();
1081
1085
  return true;
1082
1086
  }
@@ -2131,15 +2131,19 @@ async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now())
2131
2131
  if (verbose) {
2132
2132
  console.log('Loading agentic-flow ReasoningBank embedding model...');
2133
2133
  }
2134
+ // #3113: register a callable, like the ruvector branch below —
2135
+ // generateLocalEmbedding() only invokes function models. The bundled
2136
+ // model is all-MiniLM-L6-v2 (384-dim, per agentic-flow's
2137
+ // getEmbeddingDimensions()).
2134
2138
  embeddingModelState = {
2135
2139
  loaded: true,
2136
- model: { embed: reasoningBank.computeEmbedding },
2140
+ model: (text) => reasoningBank.computeEmbedding(text),
2137
2141
  tokenizer: null,
2138
- dimensions: 768
2142
+ dimensions: 384
2139
2143
  };
2140
2144
  return {
2141
2145
  success: true,
2142
- dimensions: 768,
2146
+ dimensions: 384,
2143
2147
  modelName: 'agentic-flow/reasoningbank',
2144
2148
  loadTime: Date.now() - startTime
2145
2149
  };
@@ -2272,10 +2276,13 @@ export async function generateLocalEmbedding(text) {
2272
2276
  if (state.model && typeof state.model === 'function') {
2273
2277
  try {
2274
2278
  const output = await state.model(text, { pooling: 'mean', normalize: true });
2275
- // Handle both @xenova/transformers (output.data) and ruvector (plain array) formats
2279
+ // Handle @xenova/transformers (output.data), ruvector (plain array) and
2280
+ // typed-array (ReasoningBank Float32Array, #3114) formats. DataView is an
2281
+ // ArrayBuffer view without an iterator (Array.from gives []), so exclude it.
2276
2282
  const embedding = output?.data
2277
2283
  ? Array.from(output.data)
2278
- : Array.isArray(output) ? output : null;
2284
+ : Array.isArray(output) ? output
2285
+ : ArrayBuffer.isView(output) && !(output instanceof DataView) ? Array.from(output) : null;
2279
2286
  if (embedding) {
2280
2287
  return {
2281
2288
  embedding,