ruvector 0.1.70 → 0.1.71
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/.ruvector/intelligence.json +3225 -60
- package/bin/cli.js +286 -0
- package/bin/mcp-server.js +204 -0
- package/package.json +1 -1
- package/ruvector.db +0 -0
package/bin/cli.js
CHANGED
|
@@ -4429,6 +4429,292 @@ hooksCmd.command('learn')
|
|
|
4429
4429
|
console.log(JSON.stringify(result));
|
|
4430
4430
|
});
|
|
4431
4431
|
|
|
4432
|
+
// Batch learn - process multiple experiences at once
|
|
4433
|
+
hooksCmd.command('batch-learn')
|
|
4434
|
+
.description('Record multiple learning experiences in batch for efficiency')
|
|
4435
|
+
.option('-f, --file <file>', 'JSON file with experiences array')
|
|
4436
|
+
.option('-d, --data <json>', 'Inline JSON array of experiences')
|
|
4437
|
+
.option('-t, --task <type>', 'Task type for all experiences', 'agent-routing')
|
|
4438
|
+
.action(async (opts) => {
|
|
4439
|
+
if (!loadLearningModules()) {
|
|
4440
|
+
console.log(JSON.stringify({ success: false, error: 'Learning modules not available' }));
|
|
4441
|
+
return;
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
let experiences = [];
|
|
4445
|
+
|
|
4446
|
+
// Load from file or inline
|
|
4447
|
+
if (opts.file) {
|
|
4448
|
+
try {
|
|
4449
|
+
const content = fs.readFileSync(opts.file, 'utf-8');
|
|
4450
|
+
experiences = JSON.parse(content);
|
|
4451
|
+
} catch (e) {
|
|
4452
|
+
console.log(JSON.stringify({ success: false, error: `Failed to read file: ${e.message}` }));
|
|
4453
|
+
return;
|
|
4454
|
+
}
|
|
4455
|
+
} else if (opts.data) {
|
|
4456
|
+
try {
|
|
4457
|
+
experiences = JSON.parse(opts.data);
|
|
4458
|
+
} catch (e) {
|
|
4459
|
+
console.log(JSON.stringify({ success: false, error: `Invalid JSON: ${e.message}` }));
|
|
4460
|
+
return;
|
|
4461
|
+
}
|
|
4462
|
+
} else {
|
|
4463
|
+
console.log(JSON.stringify({ success: false, error: 'Provide --file or --data' }));
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4467
|
+
if (!Array.isArray(experiences)) {
|
|
4468
|
+
experiences = [experiences];
|
|
4469
|
+
}
|
|
4470
|
+
|
|
4471
|
+
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
|
|
4472
|
+
let data = {};
|
|
4473
|
+
try {
|
|
4474
|
+
if (fs.existsSync(dataPath)) {
|
|
4475
|
+
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
|
|
4476
|
+
}
|
|
4477
|
+
} catch (e) {}
|
|
4478
|
+
|
|
4479
|
+
const engine = new LearningEngineClass();
|
|
4480
|
+
if (data.learning) {
|
|
4481
|
+
engine.import(data.learning);
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
const results = [];
|
|
4485
|
+
let totalReward = 0;
|
|
4486
|
+
|
|
4487
|
+
for (const exp of experiences) {
|
|
4488
|
+
const experience = {
|
|
4489
|
+
state: exp.state,
|
|
4490
|
+
action: exp.action,
|
|
4491
|
+
reward: exp.reward ?? 0.5,
|
|
4492
|
+
nextState: exp.nextState ?? exp.state,
|
|
4493
|
+
done: exp.done ?? false,
|
|
4494
|
+
timestamp: exp.timestamp ?? Date.now()
|
|
4495
|
+
};
|
|
4496
|
+
|
|
4497
|
+
const delta = engine.update(opts.task, experience);
|
|
4498
|
+
totalReward += experience.reward;
|
|
4499
|
+
results.push({ state: exp.state, action: exp.action, delta });
|
|
4500
|
+
}
|
|
4501
|
+
|
|
4502
|
+
// Save
|
|
4503
|
+
data.learning = engine.export();
|
|
4504
|
+
fs.mkdirSync(path.dirname(dataPath), { recursive: true });
|
|
4505
|
+
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
|
|
4506
|
+
|
|
4507
|
+
const stats = engine.getStatsSummary();
|
|
4508
|
+
console.log(JSON.stringify({
|
|
4509
|
+
success: true,
|
|
4510
|
+
processed: experiences.length,
|
|
4511
|
+
avgReward: totalReward / experiences.length,
|
|
4512
|
+
results,
|
|
4513
|
+
stats: {
|
|
4514
|
+
bestAlgorithm: stats.bestAlgorithm,
|
|
4515
|
+
totalUpdates: stats.totalUpdates,
|
|
4516
|
+
avgReward: stats.avgReward
|
|
4517
|
+
}
|
|
4518
|
+
}));
|
|
4519
|
+
});
|
|
4520
|
+
|
|
4521
|
+
// Subscribe to learning updates - stream real-time learning events
|
|
4522
|
+
hooksCmd.command('subscribe')
|
|
4523
|
+
.description('Subscribe to real-time learning updates (streaming)')
|
|
4524
|
+
.option('-e, --events <types>', 'Event types to subscribe to (learn,compress,route,memory)', 'learn,route')
|
|
4525
|
+
.option('-f, --format <fmt>', 'Output format (json, text)', 'json')
|
|
4526
|
+
.option('--poll <ms>', 'Poll interval in ms', parseInt, 1000)
|
|
4527
|
+
.action(async (opts) => {
|
|
4528
|
+
const events = opts.events.split(',').map(e => e.trim());
|
|
4529
|
+
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
|
|
4530
|
+
|
|
4531
|
+
let lastStats = { patterns: 0, memories: 0, trajectories: 0 };
|
|
4532
|
+
let lastLearning = { totalUpdates: 0 };
|
|
4533
|
+
|
|
4534
|
+
console.error(chalk.cyan('🔴 Subscribed to learning updates. Press Ctrl+C to stop.\n'));
|
|
4535
|
+
console.error(chalk.dim(` Events: ${events.join(', ')}`));
|
|
4536
|
+
console.error(chalk.dim(` Poll interval: ${opts.poll}ms\n`));
|
|
4537
|
+
|
|
4538
|
+
const emit = (type, data) => {
|
|
4539
|
+
const event = { type, timestamp: Date.now(), data };
|
|
4540
|
+
if (opts.format === 'json') {
|
|
4541
|
+
console.log(JSON.stringify(event));
|
|
4542
|
+
} else {
|
|
4543
|
+
const icon = { learn: '🧠', compress: '📦', route: '🎯', memory: '💾' }[type] || '📡';
|
|
4544
|
+
console.log(`${icon} [${type}] ${JSON.stringify(data)}`);
|
|
4545
|
+
}
|
|
4546
|
+
};
|
|
4547
|
+
|
|
4548
|
+
const check = () => {
|
|
4549
|
+
try {
|
|
4550
|
+
if (!fs.existsSync(dataPath)) return;
|
|
4551
|
+
|
|
4552
|
+
const data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
|
|
4553
|
+
const stats = data.stats || {};
|
|
4554
|
+
const learning = data.learning?.stats || {};
|
|
4555
|
+
|
|
4556
|
+
// Check for new patterns (learn events)
|
|
4557
|
+
if (events.includes('learn')) {
|
|
4558
|
+
const currentPatterns = stats.total_patterns || 0;
|
|
4559
|
+
if (currentPatterns > lastStats.patterns) {
|
|
4560
|
+
emit('learn', {
|
|
4561
|
+
type: 'pattern',
|
|
4562
|
+
newPatterns: currentPatterns - lastStats.patterns,
|
|
4563
|
+
total: currentPatterns
|
|
4564
|
+
});
|
|
4565
|
+
lastStats.patterns = currentPatterns;
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
// Check learning engine updates
|
|
4569
|
+
let totalUpdates = 0;
|
|
4570
|
+
Object.values(learning).forEach(algo => {
|
|
4571
|
+
if (algo.updates) totalUpdates += algo.updates;
|
|
4572
|
+
});
|
|
4573
|
+
if (totalUpdates > lastLearning.totalUpdates) {
|
|
4574
|
+
const bestAlgo = Object.entries(learning)
|
|
4575
|
+
.filter(([, v]) => v.updates > 0)
|
|
4576
|
+
.sort((a, b) => b[1].avgReward - a[1].avgReward)[0];
|
|
4577
|
+
emit('learn', {
|
|
4578
|
+
type: 'algorithm_update',
|
|
4579
|
+
newUpdates: totalUpdates - lastLearning.totalUpdates,
|
|
4580
|
+
totalUpdates,
|
|
4581
|
+
bestAlgorithm: bestAlgo?.[0] || 'none'
|
|
4582
|
+
});
|
|
4583
|
+
lastLearning.totalUpdates = totalUpdates;
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4587
|
+
// Check for new memories
|
|
4588
|
+
if (events.includes('memory')) {
|
|
4589
|
+
const currentMemories = stats.total_memories || 0;
|
|
4590
|
+
if (currentMemories > lastStats.memories) {
|
|
4591
|
+
emit('memory', {
|
|
4592
|
+
newMemories: currentMemories - lastStats.memories,
|
|
4593
|
+
total: currentMemories
|
|
4594
|
+
});
|
|
4595
|
+
lastStats.memories = currentMemories;
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
// Check for new trajectories (route events)
|
|
4600
|
+
if (events.includes('route')) {
|
|
4601
|
+
const currentTrajectories = stats.total_trajectories || 0;
|
|
4602
|
+
if (currentTrajectories > lastStats.trajectories) {
|
|
4603
|
+
emit('route', {
|
|
4604
|
+
newTrajectories: currentTrajectories - lastStats.trajectories,
|
|
4605
|
+
total: currentTrajectories
|
|
4606
|
+
});
|
|
4607
|
+
lastStats.trajectories = currentTrajectories;
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4611
|
+
} catch (e) {
|
|
4612
|
+
// Ignore read errors during updates
|
|
4613
|
+
}
|
|
4614
|
+
};
|
|
4615
|
+
|
|
4616
|
+
// Initial state
|
|
4617
|
+
check();
|
|
4618
|
+
|
|
4619
|
+
// Poll for updates
|
|
4620
|
+
const interval = setInterval(check, opts.poll);
|
|
4621
|
+
|
|
4622
|
+
// Handle graceful shutdown
|
|
4623
|
+
process.on('SIGINT', () => {
|
|
4624
|
+
clearInterval(interval);
|
|
4625
|
+
console.error(chalk.dim('\n\n👋 Subscription ended.'));
|
|
4626
|
+
process.exit(0);
|
|
4627
|
+
});
|
|
4628
|
+
|
|
4629
|
+
// Keep alive
|
|
4630
|
+
await new Promise(() => {});
|
|
4631
|
+
});
|
|
4632
|
+
|
|
4633
|
+
// Watch and learn - monitor file changes and auto-learn
|
|
4634
|
+
hooksCmd.command('watch')
|
|
4635
|
+
.description('Watch for changes and auto-learn patterns in real-time')
|
|
4636
|
+
.option('-p, --path <dir>', 'Directory to watch', '.')
|
|
4637
|
+
.option('-i, --ignore <patterns>', 'Patterns to ignore (comma-separated)', 'node_modules,dist,.git')
|
|
4638
|
+
.option('--dry-run', 'Show what would be learned without saving')
|
|
4639
|
+
.action(async (opts) => {
|
|
4640
|
+
const watchDir = path.resolve(opts.path);
|
|
4641
|
+
const ignorePatterns = opts.ignore.split(',').map(p => p.trim());
|
|
4642
|
+
|
|
4643
|
+
console.error(chalk.cyan(`👁️ Watching ${watchDir} for changes...\n`));
|
|
4644
|
+
console.error(chalk.dim(` Ignoring: ${ignorePatterns.join(', ')}`));
|
|
4645
|
+
console.error(chalk.dim(` Press Ctrl+C to stop.\n`));
|
|
4646
|
+
|
|
4647
|
+
const intel = new Intelligence({ skipEngine: true });
|
|
4648
|
+
let lastEdit = null;
|
|
4649
|
+
let editCount = 0;
|
|
4650
|
+
|
|
4651
|
+
const shouldIgnore = (filePath) => {
|
|
4652
|
+
return ignorePatterns.some(pattern => filePath.includes(pattern));
|
|
4653
|
+
};
|
|
4654
|
+
|
|
4655
|
+
const processChange = (eventType, filename) => {
|
|
4656
|
+
if (!filename || shouldIgnore(filename)) return;
|
|
4657
|
+
|
|
4658
|
+
const ext = path.extname(filename);
|
|
4659
|
+
const state = `edit:${ext || 'unknown'}`;
|
|
4660
|
+
const now = Date.now();
|
|
4661
|
+
|
|
4662
|
+
// Determine likely action based on file type
|
|
4663
|
+
const agentMapping = {
|
|
4664
|
+
'.ts': 'typescript-developer',
|
|
4665
|
+
'.js': 'coder',
|
|
4666
|
+
'.rs': 'rust-developer',
|
|
4667
|
+
'.py': 'python-developer',
|
|
4668
|
+
'.go': 'go-developer',
|
|
4669
|
+
'.md': 'documentation',
|
|
4670
|
+
'.json': 'config-manager',
|
|
4671
|
+
'.yaml': 'devops-engineer',
|
|
4672
|
+
'.yml': 'devops-engineer',
|
|
4673
|
+
};
|
|
4674
|
+
const agent = agentMapping[ext] || 'coder';
|
|
4675
|
+
|
|
4676
|
+
// Co-edit pattern detection
|
|
4677
|
+
if (lastEdit && lastEdit.file !== filename && (now - lastEdit.time) < 60000) {
|
|
4678
|
+
// Files edited within 1 minute are co-edits
|
|
4679
|
+
const coEditKey = [lastEdit.file, filename].sort().join('|');
|
|
4680
|
+
if (!opts.dryRun) {
|
|
4681
|
+
if (!intel.data.sequences) intel.data.sequences = {};
|
|
4682
|
+
if (!intel.data.sequences[lastEdit.file]) intel.data.sequences[lastEdit.file] = [];
|
|
4683
|
+
const existing = intel.data.sequences[lastEdit.file].find(s => s.file === filename);
|
|
4684
|
+
if (existing) {
|
|
4685
|
+
existing.score++;
|
|
4686
|
+
} else {
|
|
4687
|
+
intel.data.sequences[lastEdit.file].push({ file: filename, score: 1 });
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
console.log(chalk.yellow(` 🔗 Co-edit: ${path.basename(lastEdit.file)} → ${path.basename(filename)}`));
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
// Update Q-value for this file type
|
|
4694
|
+
if (!opts.dryRun) {
|
|
4695
|
+
intel.updateQ(state, agent, 0.5);
|
|
4696
|
+
intel.save();
|
|
4697
|
+
}
|
|
4698
|
+
|
|
4699
|
+
editCount++;
|
|
4700
|
+
console.log(chalk.green(` ✏️ [${editCount}] ${filename} → ${agent}`));
|
|
4701
|
+
|
|
4702
|
+
lastEdit = { file: filename, time: now };
|
|
4703
|
+
};
|
|
4704
|
+
|
|
4705
|
+
// Use fs.watch for real-time monitoring
|
|
4706
|
+
const watcher = fs.watch(watchDir, { recursive: true }, processChange);
|
|
4707
|
+
|
|
4708
|
+
process.on('SIGINT', () => {
|
|
4709
|
+
watcher.close();
|
|
4710
|
+
console.error(chalk.dim(`\n\n📊 Learned from ${editCount} file changes.`));
|
|
4711
|
+
process.exit(0);
|
|
4712
|
+
});
|
|
4713
|
+
|
|
4714
|
+
// Keep alive
|
|
4715
|
+
await new Promise(() => {});
|
|
4716
|
+
});
|
|
4717
|
+
|
|
4432
4718
|
// ============================================
|
|
4433
4719
|
// END NEW CAPABILITY COMMANDS
|
|
4434
4720
|
// ============================================
|
package/bin/mcp-server.js
CHANGED
|
@@ -855,6 +855,67 @@ const TOOLS = [
|
|
|
855
855
|
},
|
|
856
856
|
required: ['key']
|
|
857
857
|
}
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
name: 'hooks_batch_learn',
|
|
861
|
+
description: 'Record multiple learning experiences in batch for efficiency. Processes an array of experiences at once.',
|
|
862
|
+
inputSchema: {
|
|
863
|
+
type: 'object',
|
|
864
|
+
properties: {
|
|
865
|
+
experiences: {
|
|
866
|
+
type: 'array',
|
|
867
|
+
description: 'Array of experiences to learn from',
|
|
868
|
+
items: {
|
|
869
|
+
type: 'object',
|
|
870
|
+
properties: {
|
|
871
|
+
state: { type: 'string', description: 'State identifier' },
|
|
872
|
+
action: { type: 'string', description: 'Action taken' },
|
|
873
|
+
reward: { type: 'number', description: 'Reward (-1 to 1)' },
|
|
874
|
+
nextState: { type: 'string', description: 'Next state (optional)' },
|
|
875
|
+
done: { type: 'boolean', description: 'Episode ended' }
|
|
876
|
+
},
|
|
877
|
+
required: ['state', 'action', 'reward']
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
task: { type: 'string', description: 'Task type for all experiences', default: 'agent-routing' }
|
|
881
|
+
},
|
|
882
|
+
required: ['experiences']
|
|
883
|
+
}
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
name: 'hooks_subscribe_snapshot',
|
|
887
|
+
description: 'Get current state snapshot for subscription-style updates. Returns counts and deltas since last call.',
|
|
888
|
+
inputSchema: {
|
|
889
|
+
type: 'object',
|
|
890
|
+
properties: {
|
|
891
|
+
events: {
|
|
892
|
+
type: 'array',
|
|
893
|
+
description: 'Event types to check',
|
|
894
|
+
items: { type: 'string', enum: ['learn', 'compress', 'route', 'memory'] },
|
|
895
|
+
default: ['learn', 'route']
|
|
896
|
+
},
|
|
897
|
+
lastState: {
|
|
898
|
+
type: 'object',
|
|
899
|
+
description: 'Previous state for delta calculation',
|
|
900
|
+
properties: {
|
|
901
|
+
patterns: { type: 'number' },
|
|
902
|
+
memories: { type: 'number' },
|
|
903
|
+
trajectories: { type: 'number' },
|
|
904
|
+
updates: { type: 'number' }
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
required: []
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
name: 'hooks_watch_status',
|
|
913
|
+
description: 'Get file watching status and recent changes detected',
|
|
914
|
+
inputSchema: {
|
|
915
|
+
type: 'object',
|
|
916
|
+
properties: {},
|
|
917
|
+
required: []
|
|
918
|
+
}
|
|
858
919
|
}
|
|
859
920
|
];
|
|
860
921
|
|
|
@@ -1862,6 +1923,149 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1862
1923
|
}, null, 2) }] };
|
|
1863
1924
|
}
|
|
1864
1925
|
|
|
1926
|
+
case 'hooks_batch_learn': {
|
|
1927
|
+
let LearningEngine;
|
|
1928
|
+
try {
|
|
1929
|
+
LearningEngine = require('../dist/core/learning-engine').default;
|
|
1930
|
+
} catch (e) {
|
|
1931
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'LearningEngine not available' }) }] };
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
const experiences = args.experiences || [];
|
|
1935
|
+
if (!Array.isArray(experiences) || experiences.length === 0) {
|
|
1936
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'experiences must be a non-empty array' }) }] };
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
const task = args.task || 'agent-routing';
|
|
1940
|
+
const engine = new LearningEngine();
|
|
1941
|
+
|
|
1942
|
+
// Import existing learning data
|
|
1943
|
+
if (intel.data.learning) {
|
|
1944
|
+
engine.import(intel.data.learning);
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
const results = [];
|
|
1948
|
+
let totalReward = 0;
|
|
1949
|
+
|
|
1950
|
+
for (const exp of experiences) {
|
|
1951
|
+
const experience = {
|
|
1952
|
+
state: exp.state,
|
|
1953
|
+
action: exp.action,
|
|
1954
|
+
reward: exp.reward ?? 0.5,
|
|
1955
|
+
nextState: exp.nextState ?? exp.state,
|
|
1956
|
+
done: exp.done ?? false,
|
|
1957
|
+
timestamp: Date.now()
|
|
1958
|
+
};
|
|
1959
|
+
|
|
1960
|
+
const delta = engine.update(task, experience);
|
|
1961
|
+
totalReward += experience.reward;
|
|
1962
|
+
results.push({ state: exp.state, action: exp.action, reward: experience.reward, delta });
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
// Save
|
|
1966
|
+
intel.data.learning = engine.export();
|
|
1967
|
+
intel.save();
|
|
1968
|
+
|
|
1969
|
+
const stats = engine.getStatsSummary();
|
|
1970
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
1971
|
+
success: true,
|
|
1972
|
+
processed: experiences.length,
|
|
1973
|
+
avgReward: totalReward / experiences.length,
|
|
1974
|
+
results,
|
|
1975
|
+
stats: {
|
|
1976
|
+
bestAlgorithm: stats.bestAlgorithm,
|
|
1977
|
+
totalUpdates: stats.totalUpdates,
|
|
1978
|
+
avgReward: stats.avgReward
|
|
1979
|
+
}
|
|
1980
|
+
}, null, 2) }] };
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
case 'hooks_subscribe_snapshot': {
|
|
1984
|
+
const events = args.events || ['learn', 'route'];
|
|
1985
|
+
const lastState = args.lastState || { patterns: 0, memories: 0, trajectories: 0, updates: 0 };
|
|
1986
|
+
|
|
1987
|
+
const stats = intel.data.stats || {};
|
|
1988
|
+
const learning = intel.data.learning?.stats || {};
|
|
1989
|
+
|
|
1990
|
+
// Calculate current state
|
|
1991
|
+
let totalUpdates = 0;
|
|
1992
|
+
let bestAlgorithm = null;
|
|
1993
|
+
let bestAvgReward = -Infinity;
|
|
1994
|
+
|
|
1995
|
+
Object.entries(learning).forEach(([algo, data]) => {
|
|
1996
|
+
if (data.updates) {
|
|
1997
|
+
totalUpdates += data.updates;
|
|
1998
|
+
if (data.avgReward > bestAvgReward) {
|
|
1999
|
+
bestAvgReward = data.avgReward;
|
|
2000
|
+
bestAlgorithm = algo;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
});
|
|
2004
|
+
|
|
2005
|
+
const currentState = {
|
|
2006
|
+
patterns: stats.total_patterns || 0,
|
|
2007
|
+
memories: stats.total_memories || 0,
|
|
2008
|
+
trajectories: stats.total_trajectories || 0,
|
|
2009
|
+
updates: totalUpdates
|
|
2010
|
+
};
|
|
2011
|
+
|
|
2012
|
+
// Calculate deltas
|
|
2013
|
+
const deltas = {
|
|
2014
|
+
patterns: currentState.patterns - (lastState.patterns || 0),
|
|
2015
|
+
memories: currentState.memories - (lastState.memories || 0),
|
|
2016
|
+
trajectories: currentState.trajectories - (lastState.trajectories || 0),
|
|
2017
|
+
updates: currentState.updates - (lastState.updates || 0)
|
|
2018
|
+
};
|
|
2019
|
+
|
|
2020
|
+
const hasChanges = Object.values(deltas).some(d => d > 0);
|
|
2021
|
+
|
|
2022
|
+
// Build events array
|
|
2023
|
+
const eventsList = [];
|
|
2024
|
+
if (events.includes('learn') && deltas.patterns > 0) {
|
|
2025
|
+
eventsList.push({ type: 'learn', subtype: 'pattern', delta: deltas.patterns, total: currentState.patterns });
|
|
2026
|
+
}
|
|
2027
|
+
if (events.includes('learn') && deltas.updates > 0) {
|
|
2028
|
+
eventsList.push({ type: 'learn', subtype: 'algorithm', delta: deltas.updates, total: currentState.updates, bestAlgorithm });
|
|
2029
|
+
}
|
|
2030
|
+
if (events.includes('memory') && deltas.memories > 0) {
|
|
2031
|
+
eventsList.push({ type: 'memory', delta: deltas.memories, total: currentState.memories });
|
|
2032
|
+
}
|
|
2033
|
+
if (events.includes('route') && deltas.trajectories > 0) {
|
|
2034
|
+
eventsList.push({ type: 'route', delta: deltas.trajectories, total: currentState.trajectories });
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
2038
|
+
success: true,
|
|
2039
|
+
hasChanges,
|
|
2040
|
+
currentState,
|
|
2041
|
+
deltas,
|
|
2042
|
+
events: eventsList,
|
|
2043
|
+
bestAlgorithm,
|
|
2044
|
+
timestamp: Date.now()
|
|
2045
|
+
}, null, 2) }] };
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
case 'hooks_watch_status': {
|
|
2049
|
+
// Return current intelligence state as a "watch" status
|
|
2050
|
+
const stats = intel.data.stats || {};
|
|
2051
|
+
const patterns = Object.keys(intel.data.patterns || {});
|
|
2052
|
+
const recentPatterns = patterns.slice(-5);
|
|
2053
|
+
|
|
2054
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
2055
|
+
success: true,
|
|
2056
|
+
watching: true,
|
|
2057
|
+
stats: {
|
|
2058
|
+
totalPatterns: stats.total_patterns || 0,
|
|
2059
|
+
totalMemories: stats.total_memories || 0,
|
|
2060
|
+
totalTrajectories: stats.total_trajectories || 0,
|
|
2061
|
+
sessionCount: stats.session_count || 0
|
|
2062
|
+
},
|
|
2063
|
+
recentPatterns,
|
|
2064
|
+
lastUpdate: stats.last_session || Date.now(),
|
|
2065
|
+
tip: 'Use hooks_subscribe_snapshot with lastState for delta tracking'
|
|
2066
|
+
}, null, 2) }] };
|
|
2067
|
+
}
|
|
2068
|
+
|
|
1865
2069
|
default:
|
|
1866
2070
|
return {
|
|
1867
2071
|
content: [{
|
package/package.json
CHANGED
package/ruvector.db
CHANGED
|
Binary file
|