@claude-flow/cli 3.47.0 → 3.48.0

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 (70) hide show
  1. package/.claude/helpers/auto-memory-hook.mjs +6 -2
  2. package/.claude/helpers/helpers.manifest.json +3 -3
  3. package/.claude/helpers/learning-service.mjs +4 -2
  4. package/.claude/helpers/metrics-db.mjs +4 -2
  5. package/bin/cli.js +4 -1
  6. package/catalog-manifest.json +2 -2
  7. package/dist/src/commands/analyze.js +2 -2
  8. package/dist/src/commands/config.js +5 -7
  9. package/dist/src/commands/hive-mind-worker.d.ts +88 -0
  10. package/dist/src/commands/hive-mind-worker.js +242 -0
  11. package/dist/src/commands/hive-mind.js +24 -41
  12. package/dist/src/commands/hooks.js +15 -5
  13. package/dist/src/commands/memory.js +89 -27
  14. package/dist/src/commands/metaharness.js +1 -0
  15. package/dist/src/commands/security.js +113 -55
  16. package/dist/src/commands/session.js +6 -6
  17. package/dist/src/commands/task.js +5 -4
  18. package/dist/src/init/helpers-generator.js +4 -2
  19. package/dist/src/mcp-server.js +10 -3
  20. package/dist/src/mcp-tools/agentdb-tools.js +29 -62
  21. package/dist/src/mcp-tools/hooks-tools.d.ts +0 -4
  22. package/dist/src/mcp-tools/hooks-tools.js +139 -37
  23. package/dist/src/mcp-tools/memory-tools.js +89 -35
  24. package/dist/src/mcp-tools/policy-enforcer.d.ts +8 -1
  25. package/dist/src/mcp-tools/policy-enforcer.js +80 -8
  26. package/dist/src/mcp-tools/session-tools.js +34 -8
  27. package/dist/src/mcp-tools/task-tools.js +73 -53
  28. package/dist/src/memory/feedback-patterns.d.ts +13 -0
  29. package/dist/src/memory/feedback-patterns.js +14 -0
  30. package/dist/src/memory/live-memory-row.d.ts +3 -0
  31. package/dist/src/memory/live-memory-row.js +5 -0
  32. package/dist/src/memory/memory-bridge.d.ts +11 -20
  33. package/dist/src/memory/memory-bridge.js +348 -134
  34. package/dist/src/memory/memory-initializer.d.ts +9 -1
  35. package/dist/src/memory/memory-initializer.js +41 -31
  36. package/dist/src/ruvector/graph-analyzer.js +4 -1
  37. package/dist/src/services/config-file-manager.js +30 -8
  38. package/dist/src/services/memory-backup.d.ts +1 -1
  39. package/dist/src/services/memory-backup.js +67 -27
  40. package/dist/src/services/worker-daemon.d.ts +2 -2
  41. package/dist/src/services/worker-daemon.js +23 -14
  42. package/node_modules/@claude-flow/codex/package.json +1 -1
  43. package/node_modules/@claude-flow/mcp/dist/tool-registry.d.ts.map +1 -1
  44. package/node_modules/@claude-flow/mcp/dist/tool-registry.js +11 -3
  45. package/node_modules/@claude-flow/mcp/dist/tool-registry.js.map +1 -1
  46. package/node_modules/@claude-flow/mcp/package.json +6 -3
  47. package/node_modules/@claude-flow/plugin-agent-federation/package.json +3 -3
  48. package/node_modules/@claude-flow/security/package.json +2 -3
  49. package/package.json +9 -9
  50. package/plugins/ruflo-metaharness/scripts/_cli-args.mjs +37 -0
  51. package/plugins/ruflo-metaharness/scripts/audit-list.mjs +8 -0
  52. package/plugins/ruflo-metaharness/scripts/audit-trend.mjs +12 -0
  53. package/plugins/ruflo-metaharness/scripts/bench-parse-mcp-scan.mjs +8 -0
  54. package/plugins/ruflo-metaharness/scripts/bench-recordpair-overhead.mjs +8 -0
  55. package/plugins/ruflo-metaharness/scripts/bench-similarity.mjs +8 -0
  56. package/plugins/ruflo-metaharness/scripts/bench.mjs +10 -0
  57. package/plugins/ruflo-metaharness/scripts/drift-from-history.mjs +13 -0
  58. package/plugins/ruflo-metaharness/scripts/evolve.mjs +27 -0
  59. package/plugins/ruflo-metaharness/scripts/genome.mjs +8 -0
  60. package/plugins/ruflo-metaharness/scripts/gepa.mjs +12 -0
  61. package/plugins/ruflo-metaharness/scripts/learn.mjs +13 -0
  62. package/plugins/ruflo-metaharness/scripts/mcp-scan.mjs +8 -0
  63. package/plugins/ruflo-metaharness/scripts/mint.mjs +11 -0
  64. package/plugins/ruflo-metaharness/scripts/oia-audit.mjs +9 -0
  65. package/plugins/ruflo-metaharness/scripts/router-parallel-analyze.mjs +8 -0
  66. package/plugins/ruflo-metaharness/scripts/score.mjs +8 -0
  67. package/plugins/ruflo-metaharness/scripts/security-bench.mjs +11 -0
  68. package/plugins/ruflo-metaharness/scripts/similarity.mjs +12 -0
  69. package/plugins/ruflo-metaharness/scripts/test-cli-help.mjs +72 -0
  70. package/plugins/ruflo-metaharness/scripts/threat-model.mjs +8 -0
@@ -40,6 +40,53 @@ function saveTaskStore(store) {
40
40
  ensureTaskDir();
41
41
  writeFileSync(getTaskPath(), JSON.stringify(store, null, 2), 'utf-8');
42
42
  }
43
+ /**
44
+ * Apply an agent-state change to every store that holds the agent.
45
+ *
46
+ * `hive-mind_spawn` keeps its workers in `.claude-flow/agents.json`, not the
47
+ * canonical `.claude-flow/agents/store.json` (#1916). Syncing only the
48
+ * canonical store meant assigning a task to a hive worker never marked it
49
+ * busy, and completing one never counted it: `hive-mind status` showed the
50
+ * worker idle with 0 completed while its task sat in the queue.
51
+ */
52
+ function updateAgents(agentIds, mutate) {
53
+ if (agentIds.length === 0)
54
+ return;
55
+ const paths = [
56
+ join(getProjectCwd(), STORAGE_DIR, 'agents', 'store.json'),
57
+ join(getProjectCwd(), STORAGE_DIR, 'agents.json'),
58
+ ];
59
+ for (const path of paths) {
60
+ try {
61
+ if (!existsSync(path))
62
+ continue;
63
+ const store = JSON.parse(readFileSync(path, 'utf-8'));
64
+ if (!store.agents)
65
+ continue;
66
+ let touched = false;
67
+ for (const id of agentIds) {
68
+ if (store.agents[id]) {
69
+ mutate(store.agents[id]);
70
+ touched = true;
71
+ }
72
+ }
73
+ if (touched)
74
+ writeFileSync(path, JSON.stringify(store, null, 2), 'utf-8');
75
+ }
76
+ catch {
77
+ // Best-effort agent sync: a corrupt agent store must not fail the task op.
78
+ }
79
+ }
80
+ }
81
+ /** Return agents still holding `taskId` to idle. */
82
+ function releaseAgents(agentIds, taskId) {
83
+ updateAgents(agentIds, (agent) => {
84
+ if (agent.currentTask === taskId) {
85
+ agent.status = 'idle';
86
+ agent.currentTask = null;
87
+ }
88
+ });
89
+ }
43
90
  export const taskTools = [
44
91
  {
45
92
  name: 'task_create',
@@ -214,33 +261,22 @@ export const taskTools = [
214
261
  const taskId = input.taskId;
215
262
  const task = store.tasks[taskId];
216
263
  if (task) {
264
+ if (task.status === 'completed') {
265
+ return { taskId: task.taskId, status: task.status, completedAt: task.completedAt, result: task.result };
266
+ }
217
267
  task.status = 'completed';
218
268
  task.progress = 100;
219
269
  task.completedAt = new Date().toISOString();
220
270
  task.result = input.result || {};
221
271
  saveTaskStore(store);
222
272
  // Sync assigned agents back to idle and increment taskCount
223
- if (task.assignedTo.length > 0) {
224
- const agentStorePath = join(getProjectCwd(), STORAGE_DIR, 'agents', 'store.json');
225
- try {
226
- let agentStore = { agents: {} };
227
- if (existsSync(agentStorePath)) {
228
- agentStore = JSON.parse(readFileSync(agentStorePath, 'utf-8'));
229
- }
230
- for (const agentId of task.assignedTo) {
231
- if (agentStore.agents[agentId]) {
232
- agentStore.agents[agentId].status = 'idle';
233
- agentStore.agents[agentId].currentTask = null;
234
- agentStore.agents[agentId].taskCount =
235
- (agentStore.agents[agentId].taskCount || 0) + 1;
236
- }
237
- }
238
- writeFileSync(agentStorePath, JSON.stringify(agentStore, null, 2), 'utf-8');
239
- }
240
- catch {
241
- // Best-effort agent sync
273
+ updateAgents(task.assignedTo, (agent) => {
274
+ if (agent.currentTask === taskId) {
275
+ agent.status = 'idle';
276
+ agent.currentTask = null;
242
277
  }
243
- }
278
+ agent.taskCount = (agent.taskCount || 0) + 1;
279
+ });
244
280
  return {
245
281
  taskId: task.taskId,
246
282
  status: task.status,
@@ -266,6 +302,7 @@ export const taskTools = [
266
302
  status: { type: 'string', description: 'New status' },
267
303
  progress: { type: 'number', description: 'Progress percentage (0-100)' },
268
304
  assignTo: { type: 'array', items: { type: 'string' }, description: 'Agent IDs to assign' },
305
+ result: { type: 'object', description: 'Result data (e.g. the failure of a failed task)' },
269
306
  },
270
307
  required: ['taskId'],
271
308
  },
@@ -284,6 +321,12 @@ export const taskTools = [
284
321
  if (newStatus === 'in_progress' && !task.startedAt) {
285
322
  task.startedAt = new Date().toISOString();
286
323
  }
324
+ // A failed task frees its workers, as task_complete and task_cancel do;
325
+ // otherwise a worker whose run failed stays `busy` forever.
326
+ if (newStatus === 'failed') {
327
+ task.completedAt = new Date().toISOString();
328
+ releaseAgents(task.assignedTo, taskId);
329
+ }
287
330
  }
288
331
  if (typeof input.progress === 'number') {
289
332
  task.progress = Math.min(100, Math.max(0, input.progress));
@@ -291,6 +334,9 @@ export const taskTools = [
291
334
  if (input.assignTo) {
292
335
  task.assignedTo = input.assignTo;
293
336
  }
337
+ if (input.result && typeof input.result === 'object') {
338
+ task.result = input.result;
339
+ }
294
340
  saveTaskStore(store);
295
341
  return {
296
342
  success: true,
@@ -332,41 +378,20 @@ export const taskTools = [
332
378
  return { taskId, error: 'Task not found' };
333
379
  }
334
380
  const previouslyAssigned = [...task.assignedTo];
335
- // Load agent store to sync worker state
336
- const agentStorePath = join(getProjectCwd(), STORAGE_DIR, 'agents', 'store.json');
337
- let agentStore = { agents: {} };
338
- try {
339
- if (existsSync(agentStorePath)) {
340
- agentStore = JSON.parse(readFileSync(agentStorePath, 'utf-8'));
341
- }
342
- }
343
- catch { /* ignore */ }
344
381
  if (input.unassign) {
345
382
  // Revert previously assigned agents to idle
346
- for (const agentId of previouslyAssigned) {
347
- if (agentStore.agents[agentId]) {
348
- agentStore.agents[agentId].status = 'idle';
349
- agentStore.agents[agentId].currentTask = null;
350
- }
351
- }
383
+ releaseAgents(previouslyAssigned, taskId);
352
384
  task.assignedTo = [];
353
385
  }
354
386
  else {
355
387
  const agentIds = input.agentIds || [];
356
388
  // Revert old agents to idle
357
- for (const agentId of previouslyAssigned) {
358
- if (!agentIds.includes(agentId) && agentStore.agents[agentId]) {
359
- agentStore.agents[agentId].status = 'idle';
360
- agentStore.agents[agentId].currentTask = null;
361
- }
362
- }
389
+ releaseAgents(previouslyAssigned.filter((id) => !agentIds.includes(id)), taskId);
363
390
  // Set new agents to active
364
- for (const agentId of agentIds) {
365
- if (agentStore.agents[agentId]) {
366
- agentStore.agents[agentId].status = 'active';
367
- agentStore.agents[agentId].currentTask = taskId;
368
- }
369
- }
391
+ updateAgents(agentIds, (agent) => {
392
+ agent.status = 'busy';
393
+ agent.currentTask = taskId;
394
+ });
370
395
  task.assignedTo = agentIds;
371
396
  // Auto-transition task to in_progress if pending
372
397
  if (task.status === 'pending' && agentIds.length > 0) {
@@ -377,12 +402,6 @@ export const taskTools = [
377
402
  }
378
403
  }
379
404
  saveTaskStore(store);
380
- // Save agent store
381
- const agentDir = join(getProjectCwd(), STORAGE_DIR, 'agents');
382
- if (!existsSync(agentDir)) {
383
- mkdirSync(agentDir, { recursive: true });
384
- }
385
- writeFileSync(agentStorePath, JSON.stringify(agentStore, null, 2), 'utf-8');
386
405
  return {
387
406
  taskId: task.taskId,
388
407
  assignedTo: task.assignedTo,
@@ -421,6 +440,7 @@ export const taskTools = [
421
440
  task.completedAt = new Date().toISOString();
422
441
  task.result = { cancelReason: input.reason || 'Cancelled by user' };
423
442
  saveTaskStore(store);
443
+ releaseAgents(task.assignedTo, taskId);
424
444
  return {
425
445
  success: true,
426
446
  taskId: task.taskId,
@@ -0,0 +1,13 @@
1
+ /** Shared input contract for learned patterns supplied by feedback callers. */
2
+ export declare const feedbackPatternsSchema: {
3
+ type: string;
4
+ items: {
5
+ type: string;
6
+ minLength: number;
7
+ maxLength: number;
8
+ };
9
+ maxItems: number;
10
+ description: string;
11
+ };
12
+ export declare function validateFeedbackPatterns(value: unknown): string[] | undefined;
13
+ //# sourceMappingURL=feedback-patterns.d.ts.map
@@ -0,0 +1,14 @@
1
+ /** Shared input contract for learned patterns supplied by feedback callers. */
2
+ export const feedbackPatternsSchema = {
3
+ type: 'array', items: { type: 'string', minLength: 1, maxLength: 10_000 }, maxItems: 100,
4
+ description: 'Learned patterns to retain; successful tasks with quality >= 0.9 may create reusable skills',
5
+ };
6
+ export function validateFeedbackPatterns(value) {
7
+ if (value === undefined)
8
+ return undefined;
9
+ if (!Array.isArray(value) || value.length > 100 || value.some(item => typeof item !== 'string' || !item.trim() || item.length > 10_000)) {
10
+ throw new Error('patterns must be an array of at most 100 non-empty strings (maximum 10000 characters each)');
11
+ }
12
+ return value;
13
+ }
14
+ //# sourceMappingURL=feedback-patterns.js.map
@@ -0,0 +1,3 @@
1
+ /** TTL is a read-time visibility rule, independent of background cleanup. */
2
+ export declare function liveMemoryRowSql(): string;
3
+ //# sourceMappingURL=live-memory-row.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** TTL is a read-time visibility rule, independent of background cleanup. */
2
+ export function liveMemoryRowSql() {
3
+ return `(status = 'active' OR status IS NULL) AND (expires_at IS NULL OR expires_at > ${Date.now()})`;
4
+ }
5
+ //# sourceMappingURL=live-memory-row.js.map
@@ -36,6 +36,8 @@ export declare function shouldDisableNativeBridge(platform?: NodeJS.Platform, en
36
36
  export declare function shouldSuppressInitLog(msg: string): boolean;
37
37
  /** Test seam: forget cached registries so a test can exercise a fresh open. */
38
38
  export declare function _resetRegistryCacheForTest(): void;
39
+ /** Inject registry construction without requiring the optional native package in tests. */
40
+ export declare function __setMemoryBridgeRegistryFactoryForTests(factory: (() => any) | null): void;
39
41
  /** #3196: the sibling store AgentDB owns next to a given sql.js database. */
40
42
  export declare function siblingAgentDbPath(dbPath: string): string | null;
41
43
  /**
@@ -271,6 +273,7 @@ export declare function bridgeAddEmbedding(id: string, embedding: number[], entr
271
273
  }, dbPath?: string): Promise<boolean | null>;
272
274
  /**
273
275
  * Get a named controller from AgentDB v3 via ControllerRegistry.
276
+ * This borrowed handle must not be retained across shutdownBridge().
274
277
  * Returns null if unavailable.
275
278
  */
276
279
  export declare function bridgeGetController(name: string, dbPath?: string): Promise<any | null>;
@@ -292,13 +295,15 @@ export declare function bridgeListControllers(dbPath?: string): Promise<Array<{
292
295
  export declare function isBridgeAvailable(dbPath?: string): Promise<boolean>;
293
296
  /**
294
297
  * Get the ControllerRegistry instance (for advanced consumers).
298
+ * This is a borrowed handle, valid only until shutdownBridge(). Callers must
299
+ * finish using it before requesting shutdown; bridge operations own their own
300
+ * leases. Prefer bridgeListControllers() for status inspection.
295
301
  */
296
302
  export declare function getControllerRegistry(dbPath?: string): Promise<any | null>;
297
303
  /**
298
304
  * Why the bridge last declined a write, or null when it has not.
299
305
  *
300
- * Deliberately NOT gated on `bridgeAvailable === false`. A bridge that
301
- * initialised fine can still fail every write — a schema mismatch throws
306
+ * A bridge that initialised fine can still fail every write — a schema mismatch throws
302
307
  * per-operation while the registry stays healthy — and that case is exactly
303
308
  * the one worth reporting, since the caller then demotes to a fallback whose
304
309
  * error message describes something else entirely.
@@ -306,7 +311,7 @@ export declare function getControllerRegistry(dbPath?: string): Promise<any | nu
306
311
  * Callers that surface a degraded-path error should include this so the
307
312
  * operator learns the cause instead of only the symptom.
308
313
  */
309
- export declare function getBridgeFailureReason(): string | null;
314
+ export declare function getBridgeFailureReason(dbPath?: string): string | null;
310
315
  /**
311
316
  * Install a pre-initialized registry for deterministic bridge tests.
312
317
  *
@@ -321,10 +326,8 @@ export declare function __setMemoryBridgeRegistryForTests(registry: any | null):
321
326
  * Shutdown the bridge and release resources.
322
327
  *
323
328
  * The cached state is cleared unconditionally. Previously the reset lived
324
- * inside `if (registryInstance)`, so it could not clear a FAILED init — the
325
- * one state that actually needs clearing, since `registryInstance` is null
326
- * precisely when init failed. A process that latched `bridgeAvailable = false`
327
- * therefore had no recovery path short of a restart.
329
+ * inside `if (registryInstance)`, so it could not clear a FAILED init. This
330
+ * also clears per-path failed promises, allowing a later retry.
328
331
  */
329
332
  export declare function shutdownBridge(): Promise<void>;
330
333
  /**
@@ -589,15 +592,7 @@ export declare function bridgeHierarchicalRecall(params: {
589
592
  topK?: number;
590
593
  includeExpired?: boolean;
591
594
  }): Promise<any>;
592
- /**
593
- * Run memory consolidation.
594
- *
595
- * Real MemoryConsolidation API (agentdb alpha.10+):
596
- * consolidate() → Promise<ConsolidationReport>
597
- * ConsolidationReport = { episodicProcessed, semanticCreated, memoriesForgotten, ... }
598
- * Stub API (fallback):
599
- * consolidate() → { promoted, pruned, timestamp }
600
- */
595
+ /** Run consolidation when a real controller is available. */
601
596
  export declare function bridgeConsolidate(params: {
602
597
  minAge?: number;
603
598
  maxEntries?: number;
@@ -612,10 +607,6 @@ export declare function bridgeBatchOperation(params: {
612
607
  operation: string;
613
608
  entries: any[];
614
609
  }): Promise<any>;
615
- /**
616
- * Synthesize context from memories.
617
- * ContextSynthesizer.synthesize is a static method that takes MemoryPattern[] (not a string).
618
- */
619
610
  export declare function bridgeContextSynthesize(params: {
620
611
  query: string;
621
612
  maxEntries?: number;