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
@@ -9,6 +9,78 @@ import { join } from 'node:path';
9
9
  const STORAGE_DIR = '.claude-flow';
10
10
  const HIVE_DIR = 'hive-mind';
11
11
  const HIVE_FILE = 'state.json';
12
+ /**
13
+ * Calculate required votes for a given strategy and total node count.
14
+ */
15
+ function calculateRequiredVotes(strategy, totalNodes, quorumPreset = 'majority') {
16
+ if (totalNodes <= 0)
17
+ return 1;
18
+ switch (strategy) {
19
+ case 'bft':
20
+ // BFT: requires 2/3 + 1 of total nodes
21
+ return Math.floor((totalNodes * 2) / 3) + 1;
22
+ case 'raft':
23
+ // Raft: simple majority
24
+ return Math.floor(totalNodes / 2) + 1;
25
+ case 'quorum':
26
+ switch (quorumPreset) {
27
+ case 'unanimous':
28
+ return totalNodes;
29
+ case 'supermajority':
30
+ return Math.floor((totalNodes * 2) / 3) + 1;
31
+ case 'majority':
32
+ default:
33
+ return Math.floor(totalNodes / 2) + 1;
34
+ }
35
+ default:
36
+ return Math.floor(totalNodes / 2) + 1;
37
+ }
38
+ }
39
+ /**
40
+ * Detect Byzantine behavior: a voter who has cast conflicting votes
41
+ * across proposals in the same round (same type, overlapping time).
42
+ * Here we check if the voter already voted differently on this proposal
43
+ * (which shouldn't happen if we block double-votes, so this checks
44
+ * cross-proposal conflicting votes for same type within the pending set).
45
+ */
46
+ function detectByzantineVoters(pending, currentProposal, voterId, newVote) {
47
+ // Check if voter cast opposite votes on proposals of the same type
48
+ for (const p of pending) {
49
+ if (p.proposalId === currentProposal.proposalId)
50
+ continue;
51
+ if (p.type !== currentProposal.type)
52
+ continue;
53
+ if (voterId in p.votes && p.votes[voterId] !== newVote) {
54
+ return true; // Conflicting vote detected
55
+ }
56
+ }
57
+ return false;
58
+ }
59
+ /**
60
+ * Try to resolve a proposal based on its strategy.
61
+ * Returns 'approved', 'rejected', or null if still pending.
62
+ */
63
+ function tryResolveProposal(proposal, totalNodes) {
64
+ const votesFor = Object.values(proposal.votes).filter(v => v).length;
65
+ const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
66
+ const required = calculateRequiredVotes(proposal.strategy, totalNodes, proposal.quorumPreset);
67
+ if (votesFor >= required)
68
+ return 'approved';
69
+ if (votesAgainst >= required)
70
+ return 'rejected';
71
+ // For quorum with 'unanimous', also reject if any vote is against
72
+ if (proposal.strategy === 'quorum' && proposal.quorumPreset === 'unanimous' && votesAgainst > 0) {
73
+ return 'rejected';
74
+ }
75
+ // Check if it's impossible to reach quorum (remaining potential votes can't tip it)
76
+ const totalVotes = Object.keys(proposal.votes).length;
77
+ const remaining = totalNodes - totalVotes;
78
+ if (votesFor + remaining < required && votesAgainst + remaining < required) {
79
+ // Deadlock: neither side can win -- reject
80
+ return 'rejected';
81
+ }
82
+ return null;
83
+ }
12
84
  function getHiveDir() {
13
85
  return join(process.cwd(), STORAGE_DIR, HIVE_DIR);
14
86
  }
@@ -300,7 +372,7 @@ export const hiveMindTools = [
300
372
  },
301
373
  {
302
374
  name: 'hive-mind_consensus',
303
- description: 'Propose or vote on consensus',
375
+ description: 'Propose or vote on consensus with BFT, Raft, or Quorum strategies',
304
376
  category: 'hive-mind',
305
377
  inputSchema: {
306
378
  type: 'object',
@@ -311,14 +383,36 @@ export const hiveMindTools = [
311
383
  value: { description: 'Proposal value (for propose)' },
312
384
  vote: { type: 'boolean', description: 'Vote (true=for, false=against)' },
313
385
  voterId: { type: 'string', description: 'Voter agent ID' },
386
+ strategy: { type: 'string', enum: ['bft', 'raft', 'quorum'], description: 'Consensus strategy (default: raft)' },
387
+ quorumPreset: { type: 'string', enum: ['unanimous', 'majority', 'supermajority'], description: 'Quorum threshold preset (for quorum strategy, default: majority)' },
388
+ term: { type: 'number', description: 'Term number (for raft strategy)' },
389
+ timeoutMs: { type: 'number', description: 'Timeout in ms for raft re-proposal (default: 30000)' },
314
390
  },
315
391
  required: ['action'],
316
392
  },
317
393
  handler: async (input) => {
318
394
  const state = loadHiveState();
319
395
  const action = input.action;
396
+ const strategy = input.strategy || 'raft';
397
+ const totalNodes = state.workers.length || 1;
320
398
  if (action === 'propose') {
321
399
  const proposalId = `proposal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
400
+ const quorumPreset = input.quorumPreset || 'majority';
401
+ const term = input.term || (state.queen?.term ?? 1);
402
+ const timeoutMs = input.timeoutMs || 30000;
403
+ // Raft: check if there's already a pending proposal for this term
404
+ if (strategy === 'raft') {
405
+ const existingTermProposal = state.consensus.pending.find(p => p.strategy === 'raft' && p.term === term && p.status === 'pending');
406
+ if (existingTermProposal) {
407
+ return {
408
+ action,
409
+ error: `Raft term ${term} already has a pending proposal: ${existingTermProposal.proposalId}. Wait for resolution or use a higher term.`,
410
+ existingProposalId: existingTermProposal.proposalId,
411
+ term,
412
+ };
413
+ }
414
+ }
415
+ const required = calculateRequiredVotes(strategy, totalNodes, quorumPreset);
322
416
  const proposal = {
323
417
  proposalId,
324
418
  type: input.type || 'general',
@@ -327,6 +421,11 @@ export const hiveMindTools = [
327
421
  proposedAt: new Date().toISOString(),
328
422
  votes: {},
329
423
  status: 'pending',
424
+ strategy,
425
+ term: strategy === 'raft' ? term : undefined,
426
+ quorumPreset: strategy === 'quorum' ? quorumPreset : undefined,
427
+ byzantineVoters: strategy === 'bft' ? [] : undefined,
428
+ timeoutAt: strategy === 'raft' ? new Date(Date.now() + timeoutMs).toISOString() : undefined,
330
429
  };
331
430
  state.consensus.pending.push(proposal);
332
431
  saveHiveState(state);
@@ -334,40 +433,115 @@ export const hiveMindTools = [
334
433
  action,
335
434
  proposalId,
336
435
  type: proposal.type,
436
+ strategy,
337
437
  status: 'pending',
338
- requiredVotes: Math.ceil(state.workers.length / 2) + 1,
438
+ required,
439
+ totalNodes,
440
+ term: proposal.term,
441
+ quorumPreset: proposal.quorumPreset,
442
+ timeoutAt: proposal.timeoutAt,
339
443
  };
340
444
  }
341
445
  if (action === 'vote') {
342
446
  const proposal = state.consensus.pending.find(p => p.proposalId === input.proposalId);
343
447
  if (!proposal) {
344
- return { action, error: 'Proposal not found' };
448
+ return { action, error: 'Proposal not found or already resolved' };
345
449
  }
346
450
  const voterId = input.voterId;
347
- proposal.votes[voterId] = input.vote;
348
- // Check if we have majority
349
- const votesFor = Object.values(proposal.votes).filter(v => v).length;
350
- const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
351
- const majority = Math.ceil(state.workers.length / 2) + 1;
352
- if (votesFor >= majority) {
353
- proposal.status = 'approved';
354
- state.consensus.history.push({
451
+ if (!voterId) {
452
+ return { action, error: 'voterId is required for voting' };
453
+ }
454
+ const voteValue = input.vote;
455
+ const proposalStrategy = proposal.strategy || 'raft';
456
+ const required = calculateRequiredVotes(proposalStrategy, totalNodes, proposal.quorumPreset);
457
+ // Prevent double-voting
458
+ if (voterId in proposal.votes) {
459
+ const previousVote = proposal.votes[voterId];
460
+ if (previousVote === voteValue) {
461
+ return {
462
+ action,
463
+ error: `Voter ${voterId} has already cast the same vote on this proposal`,
464
+ proposalId: proposal.proposalId,
465
+ existingVote: previousVote,
466
+ };
467
+ }
468
+ // Conflicting vote from same voter
469
+ if (proposalStrategy === 'bft') {
470
+ // BFT: detect as Byzantine behavior
471
+ if (!proposal.byzantineVoters)
472
+ proposal.byzantineVoters = [];
473
+ if (!proposal.byzantineVoters.includes(voterId)) {
474
+ proposal.byzantineVoters.push(voterId);
475
+ }
476
+ // Remove their vote entirely -- Byzantine voter is excluded
477
+ delete proposal.votes[voterId];
478
+ saveHiveState(state);
479
+ return {
480
+ action,
481
+ proposalId: proposal.proposalId,
482
+ voterId,
483
+ byzantineDetected: true,
484
+ message: `Byzantine behavior detected: voter ${voterId} attempted conflicting vote. Vote invalidated.`,
485
+ byzantineVoters: proposal.byzantineVoters,
486
+ status: proposal.status,
487
+ };
488
+ }
489
+ if (proposalStrategy === 'raft') {
490
+ // Raft: only one vote per node per term, reject the change
491
+ return {
492
+ action,
493
+ error: `Raft: voter ${voterId} already voted in term ${proposal.term}. Cannot change vote.`,
494
+ proposalId: proposal.proposalId,
495
+ term: proposal.term,
496
+ };
497
+ }
498
+ // Quorum: reject double-vote
499
+ return {
500
+ action,
501
+ error: `Voter ${voterId} has already voted on this proposal`,
355
502
  proposalId: proposal.proposalId,
356
- type: proposal.type,
357
- result: 'approved',
358
- votes: { for: votesFor, against: votesAgainst },
359
- decidedAt: new Date().toISOString(),
360
- });
361
- state.consensus.pending = state.consensus.pending.filter(p => p.proposalId !== proposal.proposalId);
503
+ };
504
+ }
505
+ // BFT: check for cross-proposal Byzantine behavior
506
+ if (proposalStrategy === 'bft') {
507
+ const isByzantine = detectByzantineVoters(state.consensus.pending, proposal, voterId, voteValue);
508
+ if (isByzantine) {
509
+ if (!proposal.byzantineVoters)
510
+ proposal.byzantineVoters = [];
511
+ if (!proposal.byzantineVoters.includes(voterId)) {
512
+ proposal.byzantineVoters.push(voterId);
513
+ }
514
+ saveHiveState(state);
515
+ return {
516
+ action,
517
+ proposalId: proposal.proposalId,
518
+ voterId,
519
+ byzantineDetected: true,
520
+ message: `Byzantine behavior detected: voter ${voterId} cast conflicting votes across proposals of same type. Vote rejected.`,
521
+ byzantineVoters: proposal.byzantineVoters,
522
+ status: proposal.status,
523
+ };
524
+ }
362
525
  }
363
- else if (votesAgainst >= majority) {
364
- proposal.status = 'rejected';
526
+ // Record the vote
527
+ proposal.votes[voterId] = voteValue;
528
+ const votesFor = Object.values(proposal.votes).filter(v => v).length;
529
+ const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
530
+ // Try to resolve
531
+ const resolution = tryResolveProposal(proposal, totalNodes);
532
+ let resolved = false;
533
+ if (resolution !== null) {
534
+ resolved = true;
535
+ proposal.status = resolution;
365
536
  state.consensus.history.push({
366
537
  proposalId: proposal.proposalId,
367
538
  type: proposal.type,
368
- result: 'rejected',
539
+ result: resolution,
369
540
  votes: { for: votesFor, against: votesAgainst },
370
541
  decidedAt: new Date().toISOString(),
542
+ strategy: proposalStrategy,
543
+ term: proposal.term,
544
+ byzantineDetected: proposal.byzantineVoters?.length ? proposal.byzantineVoters : undefined,
371
545
  });
372
546
  state.consensus.pending = state.consensus.pending.filter(p => p.proposalId !== proposal.proposalId);
373
547
  }
@@ -376,10 +550,17 @@ export const hiveMindTools = [
376
550
  action,
377
551
  proposalId: proposal.proposalId,
378
552
  voterId,
379
- vote: input.vote,
553
+ vote: voteValue,
554
+ strategy: proposalStrategy,
380
555
  votesFor,
381
556
  votesAgainst,
557
+ required,
558
+ totalNodes,
559
+ resolved,
560
+ result: resolved ? resolution : undefined,
382
561
  status: proposal.status,
562
+ term: proposal.term,
563
+ byzantineVoters: proposal.byzantineVoters?.length ? proposal.byzantineVoters : undefined,
383
564
  };
384
565
  }
385
566
  if (action === 'status') {
@@ -388,21 +569,37 @@ export const hiveMindTools = [
388
569
  // Check history
389
570
  const historical = state.consensus.history.find(h => h.proposalId === input.proposalId);
390
571
  if (historical) {
391
- return { action, ...historical, historical: true };
572
+ return { action, ...historical, historical: true, resolved: true };
392
573
  }
393
574
  return { action, error: 'Proposal not found' };
394
575
  }
395
576
  const votesFor = Object.values(proposal.votes).filter(v => v).length;
396
577
  const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
578
+ const proposalStrategy = proposal.strategy || 'raft';
579
+ const required = calculateRequiredVotes(proposalStrategy, totalNodes, proposal.quorumPreset);
580
+ // Raft: check timeout
581
+ let timedOut = false;
582
+ if (proposalStrategy === 'raft' && proposal.timeoutAt) {
583
+ timedOut = new Date().getTime() > new Date(proposal.timeoutAt).getTime();
584
+ }
397
585
  return {
398
586
  action,
399
587
  proposalId: proposal.proposalId,
400
588
  type: proposal.type,
589
+ strategy: proposalStrategy,
401
590
  status: proposal.status,
402
591
  votesFor,
403
592
  votesAgainst,
404
593
  totalVotes: Object.keys(proposal.votes).length,
405
- requiredMajority: Math.ceil(state.workers.length / 2) + 1,
594
+ required,
595
+ totalNodes,
596
+ resolved: false,
597
+ term: proposal.term,
598
+ quorumPreset: proposal.quorumPreset,
599
+ byzantineVoters: proposal.byzantineVoters?.length ? proposal.byzantineVoters : undefined,
600
+ timedOut,
601
+ timeoutAt: proposal.timeoutAt,
602
+ hint: timedOut ? `Raft timeout reached. Re-propose with term ${(proposal.term || 1) + 1}.` : undefined,
406
603
  };
407
604
  }
408
605
  if (action === 'list') {
@@ -411,8 +608,12 @@ export const hiveMindTools = [
411
608
  pending: state.consensus.pending.map(p => ({
412
609
  proposalId: p.proposalId,
413
610
  type: p.type,
611
+ strategy: p.strategy || 'raft',
414
612
  proposedAt: p.proposedAt,
415
613
  totalVotes: Object.keys(p.votes).length,
614
+ required: calculateRequiredVotes(p.strategy || 'raft', totalNodes, p.quorumPreset),
615
+ term: p.term,
616
+ status: p.status,
416
617
  })),
417
618
  recentHistory: state.consensus.history.slice(-5),
418
619
  };
@@ -344,6 +344,7 @@ export const memoryTools = [
344
344
  key,
345
345
  namespace,
346
346
  deleted: result.deleted,
347
+ hnswIndexInvalidated: result.deleted,
347
348
  backend: 'sql.js + HNSW',
348
349
  };
349
350
  }
@@ -197,6 +197,30 @@ export declare class EWCConsolidator {
197
197
  * Reset Fisher matrix (use with caution - allows forgetting)
198
198
  */
199
199
  resetFisher(): void;
200
+ /**
201
+ * Update Fisher matrix from pattern confidence changes.
202
+ * Called by SONA after distillLearning to track which patterns
203
+ * are important and should be protected from forgetting.
204
+ *
205
+ * Uses online averaging: F_new = alpha * F_old + (1-alpha) * F_current
206
+ *
207
+ * @param confidenceChanges - Array of {id, embedding, oldConf, newConf}
208
+ */
209
+ updateFisherFromConfidences(confidenceChanges: {
210
+ id: string;
211
+ embedding: number[];
212
+ oldConf: number;
213
+ newConf: number;
214
+ }[]): void;
215
+ /**
216
+ * Compute consolidation penalty for a proposed confidence update.
217
+ * Used by SONA to check whether a pattern update would cause forgetting.
218
+ *
219
+ * @param oldConfidence - Current confidence value
220
+ * @param newConfidence - Proposed new confidence value
221
+ * @returns Penalty value (higher = more forgetting risk)
222
+ */
223
+ computeConfidencePenalty(oldConfidence: number, newConfidence: number): number;
200
224
  /**
201
225
  * Clear all patterns and history (full reset)
202
226
  */
@@ -342,6 +342,65 @@ export class EWCConsolidator {
342
342
  resetFisher() {
343
343
  this.globalFisher = new Array(this.config.dimensions).fill(0);
344
344
  }
345
+ /**
346
+ * Update Fisher matrix from pattern confidence changes.
347
+ * Called by SONA after distillLearning to track which patterns
348
+ * are important and should be protected from forgetting.
349
+ *
350
+ * Uses online averaging: F_new = alpha * F_old + (1-alpha) * F_current
351
+ *
352
+ * @param confidenceChanges - Array of {id, embedding, oldConf, newConf}
353
+ */
354
+ updateFisherFromConfidences(confidenceChanges) {
355
+ if (confidenceChanges.length === 0)
356
+ return;
357
+ const alpha = this.config.fisherDecayRate;
358
+ const currentFisher = new Array(this.config.dimensions).fill(0);
359
+ let sampleCount = 0;
360
+ for (const change of confidenceChanges) {
361
+ if (!change.embedding || change.embedding.length === 0)
362
+ continue;
363
+ const confDelta = Math.abs(change.newConf - change.oldConf);
364
+ if (confDelta === 0)
365
+ continue;
366
+ sampleCount++;
367
+ const len = Math.min(change.embedding.length, this.config.dimensions);
368
+ // Squared gradient proxy: embedding scaled by confidence change magnitude
369
+ for (let i = 0; i < len; i++) {
370
+ const grad = change.embedding[i] * confDelta;
371
+ currentFisher[i] += grad * grad;
372
+ }
373
+ }
374
+ if (sampleCount > 0) {
375
+ for (let i = 0; i < this.config.dimensions; i++) {
376
+ currentFisher[i] /= sampleCount;
377
+ }
378
+ }
379
+ // Online EMA: F_new = alpha * F_old + (1-alpha) * F_current
380
+ for (let i = 0; i < this.config.dimensions; i++) {
381
+ this.globalFisher[i] = alpha * this.globalFisher[i] + (1 - alpha) * currentFisher[i];
382
+ }
383
+ this.saveToDisk();
384
+ }
385
+ /**
386
+ * Compute consolidation penalty for a proposed confidence update.
387
+ * Used by SONA to check whether a pattern update would cause forgetting.
388
+ *
389
+ * @param oldConfidence - Current confidence value
390
+ * @param newConfidence - Proposed new confidence value
391
+ * @returns Penalty value (higher = more forgetting risk)
392
+ */
393
+ computeConfidencePenalty(oldConfidence, newConfidence) {
394
+ // Use the global Fisher to estimate penalty for scalar confidence change
395
+ // Average Fisher value represents overall importance
396
+ let avgFisher = 0;
397
+ for (let i = 0; i < this.globalFisher.length; i++) {
398
+ avgFisher += this.globalFisher[i];
399
+ }
400
+ avgFisher = this.globalFisher.length > 0 ? avgFisher / this.globalFisher.length : 0;
401
+ const diff = newConfidence - oldConfidence;
402
+ return (this.config.lambda / 2) * avgFisher * diff * diff;
403
+ }
345
404
  /**
346
405
  * Clear all patterns and history (full reset)
347
406
  */
@@ -76,6 +76,7 @@ declare class LocalSonaCoordinator {
76
76
  private signalCount;
77
77
  private trajectories;
78
78
  private adaptationTimes;
79
+ private currentTrajectorySteps;
79
80
  constructor(config: SonaConfig);
80
81
  /**
81
82
  * Record a signal - O(1) operation
@@ -98,6 +99,37 @@ declare class LocalSonaCoordinator {
98
99
  * Get average adaptation time
99
100
  */
100
101
  getAvgAdaptationTime(): number;
102
+ /**
103
+ * Add a step to the current in-progress trajectory
104
+ */
105
+ addTrajectoryStep(step: TrajectoryStep): void;
106
+ /**
107
+ * End the current trajectory with a verdict and apply RL updates.
108
+ * Reward mapping: success=1.0, partial=0.5, failure=-0.5
109
+ *
110
+ * For successful/partial trajectories, boosts confidence of similar patterns
111
+ * in the ReasoningBank. For failures, reduces confidence scores.
112
+ */
113
+ endTrajectory(verdict: 'success' | 'failure' | 'partial', bank: LocalReasoningBank): Promise<{
114
+ reward: number;
115
+ patternsUpdated: number;
116
+ }>;
117
+ /**
118
+ * Distill learning from recent successful trajectories.
119
+ * Applies LoRA-style confidence updates and integrates EWC++ consolidation.
120
+ *
121
+ * For each successful trajectory step with high confidence,
122
+ * increases the pattern's stored confidence by loraLearningRate * reward.
123
+ * Before applying updates, checks EWC penalty to prevent catastrophic forgetting.
124
+ */
125
+ distillLearning(bank: LocalReasoningBank): Promise<{
126
+ patternsDistilled: number;
127
+ ewcPenalty: number;
128
+ }>;
129
+ /**
130
+ * Get current trajectory steps (for inspection)
131
+ */
132
+ getCurrentTrajectorySteps(): TrajectoryStep[];
101
133
  /**
102
134
  * Get statistics
103
135
  */
@@ -221,6 +253,27 @@ export declare function getSonaCoordinator(): LocalSonaCoordinator | null;
221
253
  * Get ReasoningBank for advanced operations
222
254
  */
223
255
  export declare function getReasoningBank(): LocalReasoningBank | null;
256
+ /**
257
+ * End the current trajectory with a verdict and apply RL updates.
258
+ * This is the public API for the SONA RL loop.
259
+ *
260
+ * @param verdict - 'success' (reward=1.0), 'partial' (0.5), or 'failure' (-0.5)
261
+ * @returns Update statistics or null if not initialized
262
+ */
263
+ export declare function endTrajectoryWithVerdict(verdict: 'success' | 'failure' | 'partial'): Promise<{
264
+ reward: number;
265
+ patternsUpdated: number;
266
+ } | null>;
267
+ /**
268
+ * Distill learning from recent successful trajectories.
269
+ * Applies LoRA-style confidence updates with EWC++ consolidation protection.
270
+ *
271
+ * @returns Distillation statistics or null if not initialized
272
+ */
273
+ export declare function distillLearning(): Promise<{
274
+ patternsDistilled: number;
275
+ ewcPenalty: number;
276
+ } | null>;
224
277
  /**
225
278
  * Clear intelligence state
226
279
  */