claude-flow 3.18.1 → 3.19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.18.1",
3
+ "version": "3.19.0",
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",
@@ -116,7 +116,8 @@
116
116
  "ws": ">=8.21.0",
117
117
  "@grpc/grpc-js": ">=1.14.4",
118
118
  "form-data": ">=4.0.6",
119
- "http-proxy-middleware": ">=3.0.7"
119
+ "http-proxy-middleware": ">=3.0.7",
120
+ "@ruvector/ruvllm": ">=2.5.7"
120
121
  },
121
122
  "devDependencies": {
122
123
  "@openai/codex": "^0.98.0",
@@ -23,6 +23,7 @@ const trainCommand = {
23
23
  { name: 'hyperbolic', type: 'boolean', description: 'Enable hyperbolic attention for hierarchical patterns', default: 'false' },
24
24
  { name: 'contrastive', type: 'boolean', description: 'Use contrastive learning (InfoNCE)', default: 'true' },
25
25
  { name: 'curriculum', type: 'boolean', description: 'Enable curriculum learning', default: 'false' },
26
+ { name: 'backend', type: 'string', description: 'Training backend: auto (native when available), native (@ruvector/ruvllm TrainingPipeline, disk checkpoints), wasm (RuVector MicroLoRA/InfoNCE)', default: 'auto' },
26
27
  ],
27
28
  examples: [
28
29
  { command: 'claude-flow neural train -p coordination -e 100', description: 'Train coordination patterns' },
@@ -35,6 +36,11 @@ const trainCommand = {
35
36
  const learningRate = parseFloat(ctx.flags['learning-rate'] || '0.01');
36
37
  const batchSize = parseInt(ctx.flags['batch-size'] || '32', 10);
37
38
  const dim = Math.min(parseInt(ctx.flags.dim || '256', 10), 256);
39
+ // #2549 follow-up — backend routing: 'native' = @ruvector/ruvllm
40
+ // TrainingPipeline (real epochs/early-stopping/disk checkpoints),
41
+ // 'wasm' = RuVector MicroLoRA/InfoNCE (pre-3.19 behavior),
42
+ // 'auto' = native when the module resolves, else wasm.
43
+ const backendFlag = String(ctx.flags.backend || 'auto');
38
44
  const useWasm = ctx.flags.wasm !== false;
39
45
  const useFlash = ctx.flags.flash !== false;
40
46
  const useMoE = ctx.flags.moe === true;
@@ -181,6 +187,34 @@ const trainCommand = {
181
187
  }
182
188
  }
183
189
  spinner.setText(`Training with ${embeddings.length} embeddings...`);
190
+ // #2549 — native TrainingPipeline leg. In 'auto'/'native' mode the
191
+ // LoRA training runs through @ruvector/ruvllm with the checkpoint
192
+ // taken from the TRAINED pipeline (the old best-effort block saved
193
+ // a fresh adapter's untrained weights). SONA/ReasoningBank
194
+ // persistence in the loop below runs regardless of backend.
195
+ const nativeTraining = await import('../services/native-training.js');
196
+ const useNative = backendFlag === 'native'
197
+ || (backendFlag === 'auto' && nativeTraining.nativeTrainingAvailable());
198
+ let nativeResult = null;
199
+ if (useNative) {
200
+ spinner.setText(`Training ${patternType} on native @ruvector/ruvllm pipeline...`);
201
+ const path = await import('path');
202
+ nativeResult = await nativeTraining.runNativeTraining({
203
+ embeddings,
204
+ epochs,
205
+ batchSize,
206
+ learningRate,
207
+ dim,
208
+ checkpointPath: path.join(process.cwd(), '.claude-flow', 'neural', `lora-checkpoint-${Date.now()}.json`),
209
+ });
210
+ if (!nativeResult && backendFlag === 'native') {
211
+ spinner.fail('Native backend requested (--backend native) but @ruvector/ruvllm training failed');
212
+ return { success: false, exitCode: 1 };
213
+ }
214
+ }
215
+ // Native handles the LoRA leg; WASM contrastive runs when native
216
+ // didn't (absent module, or explicit --backend wasm).
217
+ const runWasmLeg = !nativeResult;
184
218
  // Main training loop with WASM acceleration
185
219
  for (let epoch = 0; epoch < epochs; epoch++) {
186
220
  const epochStart = performance.now();
@@ -192,7 +226,7 @@ const trainCommand = {
192
226
  if (batch.length === 0)
193
227
  continue;
194
228
  // Training step with contrastive learning
195
- if (useContrastive && batch.length >= 3 && useWasm && wasmFeatures.length > 0) {
229
+ if (runWasmLeg && useContrastive && batch.length >= 3 && useWasm && wasmFeatures.length > 0) {
196
230
  const anchor = batch[0];
197
231
  const positives = [batch[1]];
198
232
  const negatives = batch.slice(2);
@@ -260,17 +294,22 @@ const trainCommand = {
260
294
  // Flush patterns to disk
261
295
  flushPatterns();
262
296
  const persistence = getPersistenceStatus();
263
- // Save LoRA checkpoint via ruvllm TrainingPipeline if available
264
- try {
265
- const { LoRAAdapter } = await import('../ruvector/lora-adapter.js');
266
- const path = await import('path');
267
- const cpDir = path.join(process.cwd(), '.claude-flow', 'neural');
268
- const cpPath = path.join(cpDir, `lora-checkpoint-${Date.now()}.json`);
269
- const adapter = new LoRAAdapter({ inputDim: dim, outputDim: dim, rank: 4 });
270
- await adapter.initBackend();
271
- await adapter.saveCheckpoint(cpPath);
297
+ // Checkpoint: when the native pipeline trained, its checkpoint (the
298
+ // TRAINED weights) was already written by runNativeTraining. The
299
+ // pre-3.19 fallback below saved a FRESH adapter's weights — only
300
+ // meaningful as a fallback when the native leg didn't run.
301
+ if (!nativeResult?.checkpointPath) {
302
+ try {
303
+ const { LoRAAdapter } = await import('../ruvector/lora-adapter.js');
304
+ const path = await import('path');
305
+ const cpDir = path.join(process.cwd(), '.claude-flow', 'neural');
306
+ const cpPath = path.join(cpDir, `lora-checkpoint-${Date.now()}.json`);
307
+ const adapter = new LoRAAdapter({ inputDim: dim, outputDim: dim, rank: 4 });
308
+ await adapter.initBackend();
309
+ await adapter.saveCheckpoint(cpPath);
310
+ }
311
+ catch { /* checkpoint save is best-effort */ }
272
312
  }
273
- catch { /* checkpoint save is best-effort */ }
274
313
  output.writeln();
275
314
  // Display results
276
315
  const tableData = [
@@ -284,8 +323,18 @@ const trainCommand = {
284
323
  { metric: 'Total Time', value: `${(totalTime / 1000).toFixed(1)}s` },
285
324
  { metric: 'Avg Epoch Time', value: `${(epochTimes.reduce((a, b) => a + b, 0) / epochTimes.length).toFixed(2)}ms` },
286
325
  ];
326
+ // Native pipeline metrics (#2549 — the LoRA leg trained on ruvllm)
327
+ if (nativeResult) {
328
+ tableData.push({ metric: 'Backend', value: 'native (@ruvector/ruvllm TrainingPipeline)' }, { metric: 'Native Steps', value: String(nativeResult.steps) }, { metric: 'Final Loss', value: nativeResult.finalLoss.toExponential(3) }, { metric: 'Early Stopped', value: nativeResult.earlyStopped ? 'yes' : 'no' });
329
+ if (nativeResult.checkpointPath) {
330
+ tableData.push({
331
+ metric: 'Checkpoint',
332
+ value: `${nativeResult.checkpointPath}${nativeResult.checkpointBytes ? ` (${(nativeResult.checkpointBytes / 1024).toFixed(1)} KB)` : ''}`,
333
+ });
334
+ }
335
+ }
287
336
  // Add WASM-specific metrics
288
- if (useWasm && wasmFeatures.length > 0) {
337
+ if (runWasmLeg && useWasm && wasmFeatures.length > 0) {
289
338
  const backendUsed = ruvectorStats?.backend || 'unknown';
290
339
  tableData.push({ metric: 'Backend', value: backendUsed === 'wasm' ? 'WASM (native)' : 'JS (fallback)' }, { metric: 'WASM Features', value: wasmFeatures.slice(0, 3).join(', ') }, { metric: 'LoRA Adaptations', value: String(adaptations) }, { metric: 'Avg Loss', value: (totalLoss / Math.max(1, epochs)).toFixed(4) });
291
340
  if (ruvectorStats?.microLoraStats) {
@@ -469,8 +518,20 @@ const statusCommand = {
469
518
  {
470
519
  component: 'Training Pipeline',
471
520
  status: stats._trainingBackend === 'ruvllm' ? output.success('Available') : output.dim(stats._trainingBackend || 'Unavailable'),
521
+ // Checkpoint capability is version-gated: saveCheckpoint(path)
522
+ // was a silent no-op before @ruvector/ruvllm 2.5.7 (#2549).
472
523
  details: stats._trainingBackend === 'ruvllm'
473
- ? 'native @ruvector/ruvllm pipeline'
524
+ ? await (async () => {
525
+ try {
526
+ const { nativeCheckpointsSupported } = await import('../ruvector/lora-adapter.js');
527
+ return nativeCheckpointsSupported()
528
+ ? 'native @ruvector/ruvllm pipeline + disk checkpoints'
529
+ : 'native @ruvector/ruvllm pipeline (checkpoints need >=2.5.7)';
530
+ }
531
+ catch {
532
+ return 'native @ruvector/ruvllm pipeline';
533
+ }
534
+ })()
474
535
  : 'JS fallback',
475
536
  },
476
537
  await (async () => {
@@ -106,6 +106,14 @@ export interface LoRAStats {
106
106
  * module resolution.
107
107
  */
108
108
  export declare function resolveTrainingBackend(): 'ruvllm' | 'js-fallback';
109
+ /**
110
+ * Whether the resolved @ruvector/ruvllm persists checkpoints to disk.
111
+ * saveCheckpoint(path) was a silent no-op (private, void, wrote 0 bytes)
112
+ * before 2.5.7 — status surfaces must not advertise checkpoints against
113
+ * older versions. Reads the resolved package's version; the package does
114
+ * not export ./package.json, so walk up from the resolved entry instead.
115
+ */
116
+ export declare function nativeCheckpointsSupported(): boolean;
109
117
  /**
110
118
  * Low-Rank Adaptation module for efficient embedding fine-tuning
111
119
  */
@@ -77,6 +77,34 @@ export function resolveTrainingBackend() {
77
77
  return 'js-fallback';
78
78
  }
79
79
  }
80
+ /**
81
+ * Whether the resolved @ruvector/ruvllm persists checkpoints to disk.
82
+ * saveCheckpoint(path) was a silent no-op (private, void, wrote 0 bytes)
83
+ * before 2.5.7 — status surfaces must not advertise checkpoints against
84
+ * older versions. Reads the resolved package's version; the package does
85
+ * not export ./package.json, so walk up from the resolved entry instead.
86
+ */
87
+ export function nativeCheckpointsSupported() {
88
+ try {
89
+ const req = createRequire(import.meta.url);
90
+ let dir = dirname(req.resolve('@ruvector/ruvllm'));
91
+ for (let i = 0; i < 5; i++) {
92
+ const pkgPath = join(dir, 'package.json');
93
+ if (existsSync(pkgPath)) {
94
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
95
+ if (pkg.name !== '@ruvector/ruvllm') {
96
+ dir = dirname(dir);
97
+ continue;
98
+ }
99
+ const [maj, min, pat] = String(pkg.version).split('.').map(Number);
100
+ return maj > 2 || (maj === 2 && (min > 5 || (min === 5 && pat >= 7)));
101
+ }
102
+ dir = dirname(dir);
103
+ }
104
+ }
105
+ catch { /* unresolved — no native checkpoints */ }
106
+ return false;
107
+ }
80
108
  async function loadTrainingPipeline(adapter) {
81
109
  if (pipelineLoaded)
82
110
  return ruvllmPipeline;
@@ -408,11 +436,18 @@ export class LoRAAdapter {
408
436
  * Falls back to writing our own weight JSON if ruvllm is unavailable.
409
437
  */
410
438
  async saveCheckpoint(path) {
439
+ // Parent dir must exist for BOTH paths: ruvllm <2.5.7 never wrote a
440
+ // file at all, and the JS fallback's writeFileSync throws ENOENT on a
441
+ // missing dir — which the catch silently converted to `false` (#2549).
442
+ try {
443
+ mkdirSync(dirname(path), { recursive: true });
444
+ }
445
+ catch { /* fs errors surface on write below */ }
411
446
  const pipeline = await loadTrainingPipeline(this);
412
447
  if (pipeline) {
413
448
  try {
414
449
  pipeline.saveCheckpoint(path);
415
- // Verify ruvllm actually wrote the file (some versions are no-op)
450
+ // Verify ruvllm actually wrote the file (<2.5.7 is a silent no-op)
416
451
  const fs = await import('fs');
417
452
  if (fs.existsSync(path))
418
453
  return true;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Native training via @ruvector/ruvllm's TrainingPipeline (#2549 follow-up).
3
+ *
4
+ * `neural train` historically trained only on the RuVector WASM path
5
+ * (MicroLoRA + InfoNCE) and its "checkpoint" was a freshly-constructed
6
+ * adapter's weights — the native TrainingPipeline (real epochs, loss
7
+ * history, early stopping, EWC registration, disk checkpoints since
8
+ * ruvllm 2.5.7) was never exercised. This service routes the LoRA
9
+ * training leg through it.
10
+ *
11
+ * Batch formulation: pattern-alignment pairs — input = embedding[i],
12
+ * target = embedding[i+1 mod n], quality 1.0 — the MSE analogue of the
13
+ * WASM path's anchor→positive contrastive objective (adjacent training
14
+ * items belong to the same pattern family by construction).
15
+ *
16
+ * Graceful: returns null when @ruvector/ruvllm is absent or anything
17
+ * throws — callers fall back to the WASM path.
18
+ */
19
+ export interface NativeTrainingResult {
20
+ epochs: number;
21
+ steps: number;
22
+ finalLoss: number;
23
+ bestValLoss: number | null;
24
+ durationMs: number;
25
+ earlyStopped: boolean;
26
+ checkpointPath?: string;
27
+ checkpointBytes?: number;
28
+ }
29
+ export interface NativeTrainingOptions {
30
+ embeddings: Float32Array[];
31
+ epochs: number;
32
+ batchSize: number;
33
+ learningRate: number;
34
+ dim: number;
35
+ /** When set, the TRAINED pipeline checkpoints here (ruvllm >=2.5.7). */
36
+ checkpointPath?: string;
37
+ }
38
+ export declare function nativeTrainingAvailable(): boolean;
39
+ export declare function runNativeTraining(opts: NativeTrainingOptions): Promise<NativeTrainingResult | null>;
40
+ //# sourceMappingURL=native-training.d.ts.map
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Native training via @ruvector/ruvllm's TrainingPipeline (#2549 follow-up).
3
+ *
4
+ * `neural train` historically trained only on the RuVector WASM path
5
+ * (MicroLoRA + InfoNCE) and its "checkpoint" was a freshly-constructed
6
+ * adapter's weights — the native TrainingPipeline (real epochs, loss
7
+ * history, early stopping, EWC registration, disk checkpoints since
8
+ * ruvllm 2.5.7) was never exercised. This service routes the LoRA
9
+ * training leg through it.
10
+ *
11
+ * Batch formulation: pattern-alignment pairs — input = embedding[i],
12
+ * target = embedding[i+1 mod n], quality 1.0 — the MSE analogue of the
13
+ * WASM path's anchor→positive contrastive objective (adjacent training
14
+ * items belong to the same pattern family by construction).
15
+ *
16
+ * Graceful: returns null when @ruvector/ruvllm is absent or anything
17
+ * throws — callers fall back to the WASM path.
18
+ */
19
+ import { createRequire } from 'module';
20
+ import { mkdirSync, existsSync } from 'fs';
21
+ import { dirname } from 'path';
22
+ export function nativeTrainingAvailable() {
23
+ try {
24
+ createRequire(import.meta.url).resolve('@ruvector/ruvllm');
25
+ return true;
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ export async function runNativeTraining(opts) {
32
+ const { embeddings, epochs, batchSize, learningRate, dim, checkpointPath } = opts;
33
+ if (embeddings.length < 2)
34
+ return null;
35
+ try {
36
+ const req = createRequire(import.meta.url);
37
+ const ruvllm = req('@ruvector/ruvllm');
38
+ const pipeline = new ruvllm.TrainingPipeline({
39
+ learningRate,
40
+ batchSize,
41
+ epochs,
42
+ inputDim: dim,
43
+ outputDim: dim,
44
+ });
45
+ // Pattern-alignment pairs, chunked into pipeline batches.
46
+ const inputs = [];
47
+ const targets = [];
48
+ const qualities = [];
49
+ for (let i = 0; i < embeddings.length; i++) {
50
+ inputs.push(Array.from(embeddings[i]));
51
+ targets.push(Array.from(embeddings[(i + 1) % embeddings.length]));
52
+ qualities.push(1.0);
53
+ }
54
+ for (let i = 0; i < inputs.length; i += batchSize) {
55
+ pipeline.addBatch(inputs.slice(i, i + batchSize), targets.slice(i, i + batchSize), qualities.slice(i, i + batchSize));
56
+ }
57
+ const r = pipeline.train();
58
+ const result = {
59
+ epochs: r.epochs,
60
+ steps: r.steps,
61
+ finalLoss: r.finalLoss,
62
+ bestValLoss: r.bestValLoss ?? null,
63
+ durationMs: r.durationMs,
64
+ earlyStopped: !!r.earlyStopped,
65
+ };
66
+ if (checkpointPath) {
67
+ try {
68
+ mkdirSync(dirname(checkpointPath), { recursive: true });
69
+ const saved = pipeline.saveCheckpoint(checkpointPath);
70
+ // <2.5.7 returns undefined and writes nothing — verify on disk.
71
+ if (existsSync(checkpointPath)) {
72
+ result.checkpointPath = checkpointPath;
73
+ result.checkpointBytes = saved?.bytes;
74
+ }
75
+ }
76
+ catch { /* checkpoint is best-effort; training result stands */ }
77
+ }
78
+ return result;
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ //# sourceMappingURL=native-training.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.18.1",
3
+ "version": "3.19.0",
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",