claude-flow 3.5.21 → 3.5.23

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 (25) hide show
  1. package/.claude/helpers/hook-handler.cjs +4 -2
  2. package/README.md +9 -7
  3. package/package.json +1 -1
  4. package/v3/@claude-flow/cli/README.md +9 -7
  5. package/v3/@claude-flow/cli/dist/src/commands/hooks.js +698 -55
  6. package/v3/@claude-flow/cli/dist/src/commands/init.js +3 -1
  7. package/v3/@claude-flow/cli/dist/src/commands/neural.js +11 -5
  8. package/v3/@claude-flow/cli/dist/src/index.d.ts +1 -1
  9. package/v3/@claude-flow/cli/dist/src/index.js +2 -0
  10. package/v3/@claude-flow/cli/dist/src/mcp-tools/coordination-tools.js +191 -12
  11. package/v3/@claude-flow/cli/dist/src/mcp-tools/hive-mind-tools.js +224 -23
  12. package/v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +1 -0
  13. package/v3/@claude-flow/cli/dist/src/memory/ewc-consolidation.d.ts +24 -0
  14. package/v3/@claude-flow/cli/dist/src/memory/ewc-consolidation.js +59 -0
  15. package/v3/@claude-flow/cli/dist/src/memory/intelligence.d.ts +53 -0
  16. package/v3/@claude-flow/cli/dist/src/memory/intelligence.js +225 -0
  17. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +7 -0
  18. package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +27 -1
  19. package/v3/@claude-flow/cli/dist/src/ruvector/index.d.ts +4 -0
  20. package/v3/@claude-flow/cli/dist/src/ruvector/index.js +12 -0
  21. package/v3/@claude-flow/cli/dist/src/services/ruvector-training.d.ts +9 -1
  22. package/v3/@claude-flow/cli/dist/src/services/ruvector-training.js +223 -39
  23. package/v3/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +4 -0
  24. package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +33 -5
  25. package/v3/@claude-flow/cli/package.json +1 -1
@@ -82,6 +82,7 @@ class LocalSonaCoordinator {
82
82
  signalCount = 0;
83
83
  trajectories = [];
84
84
  adaptationTimes = [];
85
+ currentTrajectorySteps = [];
85
86
  constructor(config) {
86
87
  this.config = config;
87
88
  // Pre-allocate circular buffer
@@ -136,6 +137,164 @@ class LocalSonaCoordinator {
136
137
  return 0;
137
138
  return this.adaptationTimes.reduce((a, b) => a + b, 0) / this.adaptationTimes.length;
138
139
  }
140
+ /**
141
+ * Add a step to the current in-progress trajectory
142
+ */
143
+ addTrajectoryStep(step) {
144
+ this.currentTrajectorySteps.push(step);
145
+ // Prevent unbounded growth
146
+ if (this.currentTrajectorySteps.length > this.config.maxTrajectorySize) {
147
+ this.currentTrajectorySteps.shift();
148
+ }
149
+ }
150
+ /**
151
+ * End the current trajectory with a verdict and apply RL updates.
152
+ * Reward mapping: success=1.0, partial=0.5, failure=-0.5
153
+ *
154
+ * For successful/partial trajectories, boosts confidence of similar patterns
155
+ * in the ReasoningBank. For failures, reduces confidence scores.
156
+ */
157
+ async endTrajectory(verdict, bank) {
158
+ const rewardMap = {
159
+ success: 1.0,
160
+ partial: 0.5,
161
+ failure: -0.5
162
+ };
163
+ const reward = rewardMap[verdict] ?? 0;
164
+ // Record the completed trajectory
165
+ const completedTrajectory = {
166
+ steps: [...this.currentTrajectorySteps],
167
+ verdict,
168
+ timestamp: Date.now()
169
+ };
170
+ this.recordTrajectory(completedTrajectory);
171
+ // Update pattern confidences based on reward
172
+ let patternsUpdated = 0;
173
+ const allPatterns = bank.getAll();
174
+ for (const step of this.currentTrajectorySteps) {
175
+ if (!step.embedding || step.embedding.length === 0)
176
+ continue;
177
+ // Find patterns similar to this trajectory step
178
+ const similar = bank.findSimilar(step.embedding, {
179
+ k: 3,
180
+ threshold: 0.3
181
+ });
182
+ for (const match of similar) {
183
+ const pattern = bank.get(match.id);
184
+ if (!pattern)
185
+ continue;
186
+ // Adjust confidence: positive reward boosts, negative reduces
187
+ const delta = reward * 0.1; // small step per update
188
+ const newConfidence = Math.max(0.0, Math.min(1.0, pattern.confidence + delta));
189
+ pattern.confidence = newConfidence;
190
+ pattern.usageCount++;
191
+ pattern.lastUsedAt = Date.now();
192
+ patternsUpdated++;
193
+ }
194
+ }
195
+ // Clear current trajectory
196
+ this.currentTrajectorySteps = [];
197
+ return { reward, patternsUpdated };
198
+ }
199
+ /**
200
+ * Distill learning from recent successful trajectories.
201
+ * Applies LoRA-style confidence updates and integrates EWC++ consolidation.
202
+ *
203
+ * For each successful trajectory step with high confidence,
204
+ * increases the pattern's stored confidence by loraLearningRate * reward.
205
+ * Before applying updates, checks EWC penalty to prevent catastrophic forgetting.
206
+ */
207
+ async distillLearning(bank) {
208
+ let patternsDistilled = 0;
209
+ let totalEwcPenalty = 0;
210
+ // Get recent successful trajectories
211
+ const recentSuccessful = this.trajectories.filter(t => t.verdict === 'success' || t.verdict === 'partial').slice(-10); // last 10 successful
212
+ if (recentSuccessful.length === 0) {
213
+ return { patternsDistilled: 0, ewcPenalty: 0 };
214
+ }
215
+ // Try to get EWC consolidator
216
+ let ewcConsolidator = null;
217
+ try {
218
+ const ewcModule = await import('./ewc-consolidation.js');
219
+ ewcConsolidator = await ewcModule.getEWCConsolidator({
220
+ lambda: this.config.ewcLambda
221
+ });
222
+ }
223
+ catch {
224
+ // EWC not available, proceed without consolidation protection
225
+ }
226
+ const rewardMap = {
227
+ success: 1.0,
228
+ partial: 0.5
229
+ };
230
+ // Collect confidence changes for EWC Fisher update
231
+ const confidenceChanges = [];
232
+ for (const trajectory of recentSuccessful) {
233
+ const reward = rewardMap[trajectory.verdict] ?? 0;
234
+ for (const step of trajectory.steps) {
235
+ if (!step.embedding || step.embedding.length === 0)
236
+ continue;
237
+ const similar = bank.findSimilar(step.embedding, {
238
+ k: 3,
239
+ threshold: 0.4
240
+ });
241
+ for (const match of similar) {
242
+ const pattern = bank.get(match.id);
243
+ if (!pattern)
244
+ continue;
245
+ // Only distill from high-confidence matches
246
+ if (match.confidence < 0.5)
247
+ continue;
248
+ const oldConfidence = pattern.confidence;
249
+ // Check EWC penalty before applying update
250
+ if (ewcConsolidator) {
251
+ const oldWeights = [oldConfidence];
252
+ const proposedConfidence = Math.min(1.0, oldConfidence + this.config.loraLearningRate * reward);
253
+ const newWeights = [proposedConfidence];
254
+ const penalty = ewcConsolidator.getPenalty(oldWeights, newWeights);
255
+ totalEwcPenalty += penalty;
256
+ // If penalty is too high, reduce the update magnitude
257
+ if (penalty > this.config.ewcLambda) {
258
+ const dampedDelta = (this.config.loraLearningRate * reward) / (1 + penalty);
259
+ pattern.confidence = Math.max(0.0, Math.min(1.0, oldConfidence + dampedDelta));
260
+ }
261
+ else {
262
+ pattern.confidence = proposedConfidence;
263
+ }
264
+ }
265
+ else {
266
+ // No EWC: apply full LoRA update
267
+ pattern.confidence = Math.max(0.0, Math.min(1.0, oldConfidence + this.config.loraLearningRate * reward));
268
+ }
269
+ pattern.lastUsedAt = Date.now();
270
+ patternsDistilled++;
271
+ confidenceChanges.push({
272
+ id: pattern.id,
273
+ oldConf: oldConfidence,
274
+ newConf: pattern.confidence,
275
+ embedding: pattern.embedding
276
+ });
277
+ }
278
+ }
279
+ }
280
+ // Update EWC Fisher matrix with confidence changes
281
+ if (ewcConsolidator && confidenceChanges.length > 0) {
282
+ for (const change of confidenceChanges) {
283
+ // Use confidence delta as gradient proxy
284
+ const gradient = change.embedding.map(e => e * Math.abs(change.newConf - change.oldConf));
285
+ ewcConsolidator.recordGradient(change.id, gradient, true);
286
+ }
287
+ }
288
+ // Persist updated patterns
289
+ bank.flushToDisk();
290
+ return { patternsDistilled, ewcPenalty: totalEwcPenalty };
291
+ }
292
+ /**
293
+ * Get current trajectory steps (for inspection)
294
+ */
295
+ getCurrentTrajectorySteps() {
296
+ return [...this.currentTrajectorySteps];
297
+ }
139
298
  /**
140
299
  * Get statistics
141
300
  */
@@ -478,6 +637,9 @@ export async function recordStep(step) {
478
637
  metadata: step.metadata,
479
638
  timestamp: step.timestamp || Date.now()
480
639
  });
640
+ // Add to current trajectory for RL tracking
641
+ const stepWithEmbedding = { ...step, embedding };
642
+ sonaCoordinator.addTrajectoryStep(stepWithEmbedding);
481
643
  // Store in ReasoningBank for retrieval
482
644
  if (reasoningBank) {
483
645
  reasoningBank.store({
@@ -489,6 +651,15 @@ export async function recordStep(step) {
489
651
  metadata: step.metadata
490
652
  });
491
653
  }
654
+ // When a 'result' step arrives, end the trajectory and run RL loop
655
+ if (step.type === 'result' && reasoningBank) {
656
+ // Determine verdict from metadata or default to 'partial'
657
+ const verdict = step.metadata?.verdict || 'partial';
658
+ await sonaCoordinator.endTrajectory(verdict, reasoningBank);
659
+ // Distill learning from recent successful trajectories
660
+ await sonaCoordinator.distillLearning(reasoningBank);
661
+ globalStats.lastAdaptation = Date.now();
662
+ }
492
663
  globalStats.trajectoriesRecorded++;
493
664
  savePersistedStats();
494
665
  return true;
@@ -512,6 +683,15 @@ export async function recordTrajectory(steps, verdict) {
512
683
  verdict,
513
684
  timestamp: Date.now()
514
685
  });
686
+ // Apply RL: update pattern confidences based on verdict
687
+ if (reasoningBank) {
688
+ // Load steps into the coordinator for endTrajectory processing
689
+ for (const step of steps) {
690
+ sonaCoordinator.addTrajectoryStep(step);
691
+ }
692
+ await sonaCoordinator.endTrajectory(verdict, reasoningBank);
693
+ await sonaCoordinator.distillLearning(reasoningBank);
694
+ }
515
695
  globalStats.trajectoriesRecorded++;
516
696
  globalStats.lastAdaptation = Date.now();
517
697
  savePersistedStats();
@@ -597,6 +777,51 @@ export function getSonaCoordinator() {
597
777
  export function getReasoningBank() {
598
778
  return reasoningBank;
599
779
  }
780
+ /**
781
+ * End the current trajectory with a verdict and apply RL updates.
782
+ * This is the public API for the SONA RL loop.
783
+ *
784
+ * @param verdict - 'success' (reward=1.0), 'partial' (0.5), or 'failure' (-0.5)
785
+ * @returns Update statistics or null if not initialized
786
+ */
787
+ export async function endTrajectoryWithVerdict(verdict) {
788
+ if (!sonaCoordinator || !reasoningBank) {
789
+ const init = await initializeIntelligence();
790
+ if (!init.success)
791
+ return null;
792
+ }
793
+ try {
794
+ const result = await sonaCoordinator.endTrajectory(verdict, reasoningBank);
795
+ globalStats.lastAdaptation = Date.now();
796
+ savePersistedStats();
797
+ return result;
798
+ }
799
+ catch {
800
+ return null;
801
+ }
802
+ }
803
+ /**
804
+ * Distill learning from recent successful trajectories.
805
+ * Applies LoRA-style confidence updates with EWC++ consolidation protection.
806
+ *
807
+ * @returns Distillation statistics or null if not initialized
808
+ */
809
+ export async function distillLearning() {
810
+ if (!sonaCoordinator || !reasoningBank) {
811
+ const init = await initializeIntelligence();
812
+ if (!init.success)
813
+ return null;
814
+ }
815
+ try {
816
+ const result = await sonaCoordinator.distillLearning(reasoningBank);
817
+ globalStats.lastAdaptation = Date.now();
818
+ savePersistedStats();
819
+ return result;
820
+ }
821
+ catch {
822
+ return null;
823
+ }
824
+ }
600
825
  /**
601
826
  * Clear intelligence state
602
827
  */
@@ -65,6 +65,12 @@ export declare function getHNSWStatus(): {
65
65
  * Clear the HNSW index (for rebuilding)
66
66
  */
67
67
  export declare function clearHNSWIndex(): void;
68
+ /**
69
+ * Invalidate the in-memory HNSW cache so the next search rebuilds from DB.
70
+ * Call this after deleting entries that had embeddings to prevent ghost
71
+ * vectors from appearing in search results.
72
+ */
73
+ export declare function rebuildSearchIndex(): void;
68
74
  /**
69
75
  * Quantize a Float32 embedding to Int8 (4x memory reduction)
70
76
  * Uses symmetric quantization with scale factor stored per-vector
@@ -398,6 +404,7 @@ declare const _default: {
398
404
  listEntries: typeof listEntries;
399
405
  getEntry: typeof getEntry;
400
406
  deleteEntry: typeof deleteEntry;
407
+ rebuildSearchIndex: typeof rebuildSearchIndex;
401
408
  MEMORY_SCHEMA_V3: string;
402
409
  getInitialMetadata: typeof getInitialMetadata;
403
410
  };
@@ -573,6 +573,15 @@ export function getHNSWStatus() {
573
573
  export function clearHNSWIndex() {
574
574
  hnswIndex = null;
575
575
  }
576
+ /**
577
+ * Invalidate the in-memory HNSW cache so the next search rebuilds from DB.
578
+ * Call this after deleting entries that had embeddings to prevent ghost
579
+ * vectors from appearing in search results.
580
+ */
581
+ export function rebuildSearchIndex() {
582
+ hnswIndex = null;
583
+ hnswInitializing = false;
584
+ }
576
585
  // ============================================================================
577
586
  // INT8 VECTOR QUANTIZATION (4x memory reduction)
578
587
  // ============================================================================
@@ -2051,10 +2060,15 @@ export async function deleteEntry(options) {
2051
2060
  error: `Key '${key}' not found in namespace '${namespace}'`
2052
2061
  };
2053
2062
  }
2063
+ // Capture the entry ID for HNSW cleanup
2064
+ const entryId = String(checkResult[0].values[0][0]);
2054
2065
  // Delete the entry (soft delete by setting status to 'deleted')
2066
+ // Also null out the embedding to clean up vector data from SQLite
2055
2067
  db.run(`
2056
2068
  UPDATE memory_entries
2057
- SET status = 'deleted', updated_at = strftime('%s', 'now') * 1000
2069
+ SET status = 'deleted',
2070
+ embedding = NULL,
2071
+ updated_at = strftime('%s', 'now') * 1000
2058
2072
  WHERE key = '${key.replace(/'/g, "''")}'
2059
2073
  AND namespace = '${namespace.replace(/'/g, "''")}'
2060
2074
  AND status = 'active'
@@ -2066,6 +2080,17 @@ export async function deleteEntry(options) {
2066
2080
  const data = db.export();
2067
2081
  fs.writeFileSync(dbPath, Buffer.from(data));
2068
2082
  db.close();
2083
+ // Clean up in-memory HNSW index so ghost vectors don't appear in searches.
2084
+ // Remove the entry from the HNSW entries map and invalidate the index.
2085
+ // The next search will rebuild the HNSW index from the remaining DB rows.
2086
+ if (hnswIndex?.entries) {
2087
+ hnswIndex.entries.delete(entryId);
2088
+ saveHNSWMetadata();
2089
+ // Invalidate the HNSW index so it rebuilds from DB on next search.
2090
+ // We can't surgically remove a vector from the HNSW graph, so we
2091
+ // clear the entire index; it will be lazily rebuilt from SQLite.
2092
+ rebuildSearchIndex();
2093
+ }
2069
2094
  return {
2070
2095
  success: true,
2071
2096
  deleted: true,
@@ -2099,6 +2124,7 @@ export default {
2099
2124
  listEntries,
2100
2125
  getEntry,
2101
2126
  deleteEntry,
2127
+ rebuildSearchIndex,
2102
2128
  MEMORY_SCHEMA_V3,
2103
2129
  getInitialMetadata
2104
2130
  };
@@ -27,6 +27,10 @@ export { SemanticRouter, createSemanticRouter, type Intent, type RouteResult, ty
27
27
  * Check if ruvector packages are available
28
28
  */
29
29
  export declare function isRuvectorAvailable(): Promise<boolean>;
30
+ /**
31
+ * Check if @ruvector/learning-wasm is available and loadable
32
+ */
33
+ export declare function isWasmBackendAvailable(): Promise<boolean>;
30
34
  /**
31
35
  * Get ruvector version if available
32
36
  */
@@ -45,6 +45,18 @@ export async function isRuvectorAvailable() {
45
45
  return false;
46
46
  }
47
47
  }
48
+ /**
49
+ * Check if @ruvector/learning-wasm is available and loadable
50
+ */
51
+ export async function isWasmBackendAvailable() {
52
+ try {
53
+ const wasm = await import('@ruvector/learning-wasm');
54
+ return typeof wasm.WasmMicroLoRA === 'function' && typeof wasm.initSync === 'function';
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
48
60
  /**
49
61
  * Get ruvector version if available
50
62
  */
@@ -14,6 +14,10 @@
14
14
  * Created with ❤️ by ruv.io
15
15
  */
16
16
  type BenchmarkResult = any;
17
+ /**
18
+ * Get which backend is active for training
19
+ */
20
+ export declare function getActiveBackend(): 'wasm' | 'js-fallback';
17
21
  export interface TrainingConfig {
18
22
  dim?: number;
19
23
  learningRate?: number;
@@ -41,11 +45,14 @@ export interface TrainingResult {
41
45
  benchmark?: BenchmarkResult[];
42
46
  }
43
47
  /**
44
- * Initialize the RuVector training system
48
+ * Initialize the RuVector training system.
49
+ * Attempts to load @ruvector/learning-wasm for WASM-accelerated training.
50
+ * Falls back to a pure-JS implementation if WASM is unavailable.
45
51
  */
46
52
  export declare function initializeTraining(config?: TrainingConfig): Promise<{
47
53
  success: boolean;
48
54
  features: string[];
55
+ backend: 'wasm' | 'js-fallback';
49
56
  error?: string;
50
57
  }>;
51
58
  /**
@@ -177,6 +184,7 @@ export declare function sonaFlush(): void;
177
184
  */
178
185
  export declare function getTrainingStats(): {
179
186
  initialized: boolean;
187
+ backend: 'wasm' | 'js-fallback';
180
188
  totalAdaptations: number;
181
189
  totalForwards: number;
182
190
  microLoraStats?: {