923 lines
41 KiB
JavaScript
923 lines
41 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* CLI Hooks Commands
|
|
* Provides CLI interface for agentic-flow hook tools
|
|
*
|
|
* NOW WITH FULL RUVECTOR INTELLIGENCE:
|
|
* - @ruvector/sona: Micro-LoRA (~0.05ms), EWC++, Trajectory tracking
|
|
* - @ruvector/attention: MoE, Flash, Hyperbolic, Graph attention
|
|
* - ruvector core: HNSW indexing (150x faster)
|
|
*
|
|
* Available as BOTH:
|
|
* 1. CLI Commands (agentic-flow hooks ...)
|
|
* 2. MCP Tools (via hooks-server.ts)
|
|
*/
|
|
import { Command } from 'commander';
|
|
import * as path from 'path';
|
|
// Import hook tools
|
|
import { hookPreEditTool } from '../../mcp/fastmcp/tools/hooks/pre-edit.js';
|
|
import { hookPostEditTool } from '../../mcp/fastmcp/tools/hooks/post-edit.js';
|
|
import { hookPreCommandTool } from '../../mcp/fastmcp/tools/hooks/pre-command.js';
|
|
import { hookPostCommandTool } from '../../mcp/fastmcp/tools/hooks/post-command.js';
|
|
import { hookRouteTool } from '../../mcp/fastmcp/tools/hooks/route.js';
|
|
import { hookExplainTool } from '../../mcp/fastmcp/tools/hooks/explain.js';
|
|
import { hookPretrainTool } from '../../mcp/fastmcp/tools/hooks/pretrain.js';
|
|
import { hookBuildAgentsTool } from '../../mcp/fastmcp/tools/hooks/build-agents.js';
|
|
import { hookMetricsTool } from '../../mcp/fastmcp/tools/hooks/metrics.js';
|
|
import { hookTransferTool } from '../../mcp/fastmcp/tools/hooks/transfer.js';
|
|
// Import intelligence tools (RuVector SONA + Attention + HNSW)
|
|
import { intelligenceRouteTool, intelligenceTrajectoryStartTool, intelligenceTrajectoryStepTool, intelligenceTrajectoryEndTool, intelligencePatternStoreTool, intelligencePatternSearchTool, intelligenceStatsTool, intelligenceLearnTool, intelligenceAttentionTool } from '../../mcp/fastmcp/tools/hooks/intelligence-tools.js';
|
|
const mockContext = {
|
|
onProgress: (update) => {
|
|
if (process.env.VERBOSE) {
|
|
console.log(`[${Math.round(update.progress * 100)}%] ${update.message}`);
|
|
}
|
|
}
|
|
};
|
|
export function createHooksCommand() {
|
|
const hooks = new Command('hooks')
|
|
.description('Self-learning intelligence hooks for agent routing and optimization');
|
|
// Pre-edit hook
|
|
hooks
|
|
.command('pre-edit <filePath>')
|
|
.description('Get context and agent suggestion before editing a file')
|
|
.option('-t, --task <task>', 'Task description')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (filePath, options) => {
|
|
try {
|
|
const result = await hookPreEditTool.execute({ filePath, task: options.task }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🎯 Suggested Agent: ${result.suggestedAgent}`);
|
|
console.log(`📊 Confidence: ${(result.confidence * 100).toFixed(1)}%`);
|
|
if (result.relatedFiles?.length > 0) {
|
|
console.log(`📁 Related Files:`);
|
|
result.relatedFiles.forEach((f) => console.log(` - ${f}`));
|
|
}
|
|
console.log(`⏱️ Latency: ${result.latencyMs}ms`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Post-edit hook
|
|
hooks
|
|
.command('post-edit <filePath>')
|
|
.description('Record edit outcome for learning')
|
|
.option('-s, --success', 'Mark as successful edit')
|
|
.option('-f, --fail', 'Mark as failed edit')
|
|
.option('-a, --agent <agent>', 'Agent that performed the edit')
|
|
.option('-d, --duration <ms>', 'Edit duration in milliseconds', parseInt)
|
|
.option('-e, --error <message>', 'Error message if failed')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (filePath, options) => {
|
|
try {
|
|
const success = options.success || !options.fail;
|
|
const result = await hookPostEditTool.execute({
|
|
filePath,
|
|
success,
|
|
agent: options.agent,
|
|
duration: options.duration,
|
|
errorMessage: options.error
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n${success ? '✅' : '❌'} Edit recorded: ${filePath}`);
|
|
console.log(`📈 Pattern updated: ${result.newPatternValue?.toFixed(2) || 'N/A'}`);
|
|
console.log(`📊 Routing accuracy: ${(result.routingAccuracy * 100).toFixed(1)}%`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Pre-command hook
|
|
hooks
|
|
.command('pre-command <command>')
|
|
.description('Assess command risk before execution')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (command, options) => {
|
|
try {
|
|
const result = await hookPreCommandTool.execute({ command }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
const riskIcon = result.blocked ? '🚫' :
|
|
result.riskCategory === 'safe' ? '✅' :
|
|
result.riskCategory === 'caution' ? '⚠️' : '❌';
|
|
console.log(`\n${riskIcon} Risk Level: ${result.riskCategory.toUpperCase()} (${(result.riskLevel * 100).toFixed(0)}%)`);
|
|
if (result.blocked) {
|
|
console.log(`🚫 Command BLOCKED - dangerous operation detected`);
|
|
}
|
|
else if (result.approved) {
|
|
console.log(`✅ Command APPROVED`);
|
|
}
|
|
if (result.suggestions?.length > 0) {
|
|
console.log(`💡 Suggestions:`);
|
|
result.suggestions.forEach((s) => console.log(` - ${s}`));
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Post-command hook
|
|
hooks
|
|
.command('post-command <command>')
|
|
.description('Record command outcome for learning')
|
|
.option('-c, --exit-code <code>', 'Exit code', parseInt, 0)
|
|
.option('-o, --stdout <output>', 'Command stdout')
|
|
.option('-e, --stderr <error>', 'Command stderr')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (command, options) => {
|
|
try {
|
|
const result = await hookPostCommandTool.execute({
|
|
command,
|
|
exitCode: options.exitCode ?? 0,
|
|
stdout: options.stdout,
|
|
stderr: options.stderr
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n${result.commandSuccess ? '✅' : '❌'} Command outcome recorded`);
|
|
console.log(`📚 Learned: ${result.learned ? 'Yes' : 'No'}`);
|
|
if (result.errorType) {
|
|
console.log(`🔍 Error type: ${result.errorType}`);
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Route hook
|
|
hooks
|
|
.command('route <task>')
|
|
.description('Route task to optimal agent using learned patterns')
|
|
.option('-f, --file <filePath>', 'Context file path')
|
|
.option('-e, --explore', 'Enable exploration mode')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (task, options) => {
|
|
try {
|
|
const result = await hookRouteTool.execute({
|
|
task,
|
|
context: options.file ? { file: options.file } : undefined,
|
|
explore: options.explore
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🎯 Recommended Agent: ${result.agent}`);
|
|
console.log(`📊 Confidence: ${(result.confidence * 100).toFixed(1)}%`);
|
|
if (result.explored) {
|
|
console.log(`🔍 Exploration mode: Active`);
|
|
}
|
|
console.log(`\n📋 Routing Factors:`);
|
|
result.factors.forEach((f) => {
|
|
console.log(` • ${f.name}: ${(f.score * 100).toFixed(0)}%`);
|
|
});
|
|
if (result.alternatives?.length > 0) {
|
|
console.log(`\n🔄 Alternatives:`);
|
|
result.alternatives.forEach((a) => {
|
|
console.log(` - ${a.agent} (${(a.score * 100).toFixed(0)}%)`);
|
|
});
|
|
}
|
|
console.log(`\n⏱️ Latency: ${result.latencyMs}ms`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Explain hook
|
|
hooks
|
|
.command('explain <task>')
|
|
.description('Explain routing decision with full transparency')
|
|
.option('-f, --file <filePath>', 'Context file path')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (task, options) => {
|
|
try {
|
|
const result = await hookExplainTool.execute({ task, file: options.file }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n📝 Summary: ${result.summary}`);
|
|
console.log(`\n🎯 Recommended: ${result.recommendedAgent}`);
|
|
console.log(`\n💡 Reasons:`);
|
|
result.reasons.forEach((r) => console.log(` • ${r}`));
|
|
console.log(`\n🏆 Agent Ranking:`);
|
|
result.ranking.forEach((r) => {
|
|
console.log(` ${r.rank}. ${r.agent} - ${(r.score * 100).toFixed(1)}%`);
|
|
});
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Pretrain hook
|
|
hooks
|
|
.command('pretrain')
|
|
.description('Analyze repository to bootstrap intelligence')
|
|
.option('-d, --depth <n>', 'Git history depth', parseInt, 50)
|
|
.option('--skip-git', 'Skip git history analysis')
|
|
.option('--skip-files', 'Skip file structure analysis')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (options) => {
|
|
try {
|
|
console.log('🧠 Analyzing repository...\n');
|
|
const result = await hookPretrainTool.execute({
|
|
depth: options.depth ?? 50,
|
|
skipGit: options.skipGit ?? false,
|
|
skipFiles: options.skipFiles ?? false
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n📊 Pretrain Complete!`);
|
|
console.log(` 📁 Files analyzed: ${result.filesAnalyzed}`);
|
|
console.log(` 🧩 Patterns created: ${result.patternsCreated}`);
|
|
console.log(` 💾 Memories stored: ${result.memoriesStored}`);
|
|
console.log(` 🔗 Co-edits found: ${result.coEditsFound || 0}`);
|
|
if (result.languages?.length > 0) {
|
|
console.log(` 🌐 Languages: ${result.languages.join(', ')}`);
|
|
}
|
|
console.log(` ⏱️ Duration: ${result.durationMs}ms`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Build-agents hook
|
|
hooks
|
|
.command('build-agents')
|
|
.description('Generate optimized agent configurations from pretrain data')
|
|
.option('-f, --focus <mode>', 'Focus mode: quality|speed|security|testing|fullstack', 'quality')
|
|
.option('-o, --output <dir>', 'Output directory', '.claude/agents')
|
|
.option('--format <fmt>', 'Output format: yaml|json', 'yaml')
|
|
.option('--no-prompts', 'Exclude system prompts')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (options) => {
|
|
try {
|
|
console.log(`🏗️ Building agents with focus: ${options.focus}...\n`);
|
|
const result = await hookBuildAgentsTool.execute({
|
|
focus: options.focus,
|
|
output: options.output,
|
|
format: options.format,
|
|
includePrompts: options.prompts !== false
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n✅ Agents Generated!`);
|
|
console.log(` 📦 Total: ${result.agentsGenerated}`);
|
|
console.log(` 📂 Output: ${result.outputDir}`);
|
|
console.log(` 🎯 Focus: ${result.focus}`);
|
|
console.log(`\n Agents created:`);
|
|
result.agents.forEach((a) => console.log(` • ${a}`));
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Metrics hook
|
|
hooks
|
|
.command('metrics')
|
|
.alias('stats')
|
|
.description('View learning metrics and performance dashboard')
|
|
.option('-t, --timeframe <period>', 'Timeframe: 1h|24h|7d|30d', '24h')
|
|
.option('-d, --detailed', 'Show detailed metrics')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (options) => {
|
|
try {
|
|
const result = await hookMetricsTool.execute({
|
|
timeframe: options.timeframe,
|
|
detailed: options.detailed
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n📊 Learning Metrics (${options.timeframe || '24h'})\n`);
|
|
console.log(`🎯 Routing:`);
|
|
console.log(` Total routes: ${result.routing.total}`);
|
|
console.log(` Successful: ${result.routing.successful}`);
|
|
console.log(` Accuracy: ${(result.routing.accuracy * 100).toFixed(1)}%`);
|
|
console.log(`\n📚 Learning:`);
|
|
console.log(` Patterns: ${result.learning.patterns}`);
|
|
console.log(` Memories: ${result.learning.memories}`);
|
|
console.log(` Error patterns: ${result.learning.errorPatterns}`);
|
|
console.log(`\n💚 Health: ${result.health.status.toUpperCase()}`);
|
|
if (result.health.issues?.length > 0) {
|
|
console.log(` Issues:`);
|
|
result.health.issues.forEach((i) => console.log(` ⚠️ ${i}`));
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Transfer hook
|
|
hooks
|
|
.command('transfer <sourceProject>')
|
|
.description('Transfer learned patterns from another project')
|
|
.option('-c, --min-confidence <n>', 'Minimum confidence threshold', parseFloat, 0.7)
|
|
.option('-m, --max-patterns <n>', 'Maximum patterns to transfer', parseInt, 50)
|
|
.option('--mode <mode>', 'Transfer mode: merge|replace|additive', 'merge')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (sourceProject, options) => {
|
|
try {
|
|
console.log(`📤 Transferring patterns from: ${sourceProject}...\n`);
|
|
const result = await hookTransferTool.execute({
|
|
sourceProject,
|
|
minConfidence: options.minConfidence,
|
|
maxPatterns: options.maxPatterns,
|
|
mode: options.mode
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n✅ Transfer Complete!`);
|
|
console.log(` 📥 Patterns transferred: ${result.transferred}`);
|
|
console.log(` 🔄 Patterns adapted: ${result.adapted}`);
|
|
console.log(` 🎯 Mode: ${result.mode}`);
|
|
if (result.targetStack?.length > 0) {
|
|
console.log(` 🛠️ Target stack: ${result.targetStack.join(', ')}`);
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Init command (creates .claude/settings.json with hooks)
|
|
hooks
|
|
.command('init')
|
|
.description('Initialize hooks in project with .claude/settings.json')
|
|
.option('--minimal', 'Minimal configuration')
|
|
.option('--force', 'Overwrite existing configuration')
|
|
.option('--no-statusline', 'Skip statusline generation')
|
|
.action(async (options) => {
|
|
try {
|
|
const fs = await import('fs');
|
|
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
|
|
const statuslinePath = path.join(process.cwd(), '.claude', 'statusline.mjs');
|
|
const claudeDir = path.dirname(settingsPath);
|
|
// Check if exists
|
|
if (fs.existsSync(settingsPath) && !options.force) {
|
|
console.log('⚠️ Settings file already exists. Use --force to overwrite.');
|
|
return;
|
|
}
|
|
// Create .claude directory
|
|
if (!fs.existsSync(claudeDir)) {
|
|
fs.mkdirSync(claudeDir, { recursive: true });
|
|
}
|
|
// Create statusline.mjs (compact colored format with agent stats)
|
|
if (options.statusline !== false) {
|
|
const statuslineContent = `#!/usr/bin/env node
|
|
// Agentic Flow Intelligence Status Line - Compact Format with Colors
|
|
// Works on Windows, Mac, and Linux - Queries SQLite for real stats
|
|
|
|
import { readFileSync, statSync, existsSync } from 'fs';
|
|
import { execSync } from 'child_process';
|
|
|
|
const INTEL_FILE = '.agentic-flow/intelligence.json';
|
|
const INTEL_DB = '.agentic-flow/intelligence.db';
|
|
|
|
// Detect dark/light mode
|
|
const isDarkMode = (() => {
|
|
const colorScheme = process.env.COLORFGBG || '';
|
|
const termBg = process.env.TERM_BACKGROUND || '';
|
|
const vscodeTheme = process.env.VSCODE_TERMINAL_COLOR_THEME || '';
|
|
if (termBg === 'light') return false;
|
|
if (vscodeTheme.toLowerCase().includes('light')) return false;
|
|
if (colorScheme.startsWith('0;') || colorScheme.includes(';15')) return false;
|
|
if (process.env.CLAUDE_CODE_THEME === 'light') return false;
|
|
return true;
|
|
})();
|
|
|
|
// Color palettes
|
|
const colors = {
|
|
dark: {
|
|
reset: '\\x1b[0m', dim: '\\x1b[2m', bold: '\\x1b[1m',
|
|
model: '\\x1b[38;5;208m', project: '\\x1b[38;5;39m', branch: '\\x1b[38;5;156m',
|
|
brain: '\\x1b[38;5;213m', patterns: '\\x1b[38;5;220m', memory: '\\x1b[38;5;117m',
|
|
trajectories: '\\x1b[38;5;183m', agents: '\\x1b[38;5;156m',
|
|
target: '\\x1b[38;5;196m', learning: '\\x1b[38;5;226m', epsilon: '\\x1b[38;5;51m',
|
|
success: '\\x1b[38;5;46m', symbol: '\\x1b[38;5;245m'
|
|
},
|
|
light: {
|
|
reset: '\\x1b[0m', dim: '\\x1b[2m', bold: '\\x1b[1m',
|
|
model: '\\x1b[38;5;166m', project: '\\x1b[38;5;27m', branch: '\\x1b[38;5;28m',
|
|
brain: '\\x1b[38;5;129m', patterns: '\\x1b[38;5;136m', memory: '\\x1b[38;5;30m',
|
|
trajectories: '\\x1b[38;5;91m', agents: '\\x1b[38;5;28m',
|
|
target: '\\x1b[38;5;160m', learning: '\\x1b[38;5;136m', epsilon: '\\x1b[38;5;31m',
|
|
success: '\\x1b[38;5;28m', symbol: '\\x1b[38;5;240m'
|
|
}
|
|
};
|
|
const c = isDarkMode ? colors.dark : colors.light;
|
|
|
|
function readJson(file) {
|
|
try { return JSON.parse(readFileSync(file, 'utf8')); } catch { return null; }
|
|
}
|
|
|
|
function querySqlite(db, sql) {
|
|
try {
|
|
return execSync(\`sqlite3 "\${db}" "\${sql}"\`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 1000 }).trim();
|
|
} catch { return null; }
|
|
}
|
|
|
|
function getGitBranch() {
|
|
try { return execSync('git branch --show-current', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim(); }
|
|
catch { return ''; }
|
|
}
|
|
|
|
function getProjectName() {
|
|
try { return process.cwd().split('/').pop() || 'project'; } catch { return 'project'; }
|
|
}
|
|
|
|
function formatSize(bytes) {
|
|
if (bytes < 1024) return \`\${bytes}B\`;
|
|
if (bytes < 1024 * 1024) return \`\${Math.round(bytes / 1024)}K\`;
|
|
return \`\${(bytes / (1024 * 1024)).toFixed(1)}M\`;
|
|
}
|
|
|
|
const LEARNING_RATE = parseFloat(process.env.AGENTIC_FLOW_LEARNING_RATE || '0.1');
|
|
const EPSILON = parseFloat(process.env.AGENTIC_FLOW_EPSILON || '0.1');
|
|
|
|
const intel = readJson(INTEL_FILE);
|
|
let dbStats = { totalTrajectories: 0, successfulRoutings: 0, totalRoutings: 0, totalPatterns: 0, totalAgents: 0, activeAgents: 0 };
|
|
|
|
if (existsSync(INTEL_DB)) {
|
|
const statsRow = querySqlite(INTEL_DB, 'SELECT * FROM stats LIMIT 1');
|
|
if (statsRow) {
|
|
const cols = statsRow.split('|');
|
|
dbStats.totalTrajectories = parseInt(cols[1]) || 0;
|
|
dbStats.totalRoutings = parseInt(cols[3]) || 0;
|
|
dbStats.successfulRoutings = parseInt(cols[4]) || 0;
|
|
dbStats.totalPatterns = parseInt(cols[5]) || 0;
|
|
}
|
|
const trajCount = querySqlite(INTEL_DB, 'SELECT COUNT(*) FROM trajectories');
|
|
if (trajCount) dbStats.totalTrajectories = parseInt(trajCount) || dbStats.totalTrajectories;
|
|
const patternCount = querySqlite(INTEL_DB, 'SELECT COUNT(*) FROM patterns');
|
|
if (patternCount) dbStats.totalPatterns = parseInt(patternCount) || 0;
|
|
}
|
|
|
|
const routes = dbStats.totalRoutings > 0 ? dbStats.totalRoutings : (intel?.metrics?.totalRoutes || 0);
|
|
const patterns = dbStats.totalPatterns > 0 ? dbStats.totalPatterns : (intel?.patterns ? Object.keys(intel.patterns).length : 0);
|
|
const memories = intel?.memories?.length || 0;
|
|
const trajectories = dbStats.totalTrajectories;
|
|
|
|
let agents = intel?.agents ? Object.keys(intel.agents).length : 66;
|
|
let activeAgents = intel?.agents ? Object.values(intel.agents).filter(a => a.status === 'active').length : 0;
|
|
|
|
const branch = getGitBranch();
|
|
const project = getProjectName();
|
|
|
|
let dbSize = 0;
|
|
if (existsSync(INTEL_DB)) {
|
|
try { dbSize = statSync(INTEL_DB).size; } catch {}
|
|
}
|
|
|
|
const lines = [];
|
|
|
|
// Line 1: Model + project + branch (colored)
|
|
let line1 = \`\${c.model}\${c.bold}Opus 4.5\${c.reset}\`;
|
|
line1 += \` \${c.dim}in\${c.reset} \${c.project}\${project}\${c.reset}\`;
|
|
if (branch) line1 += \` \${c.dim}on\${c.reset} \${c.symbol}⎇\${c.reset} \${c.branch}\${branch}\${c.reset}\`;
|
|
lines.push(line1);
|
|
|
|
// Line 2: RuVector stats (compact with symbols)
|
|
let line2 = \`\${c.brain}🧠 RuVector\${c.reset}\`;
|
|
line2 += \` \${c.symbol}◆\${c.reset} \${c.patterns}\${patterns}\${c.reset} \${c.dim}patterns\${c.reset}\`;
|
|
if (memories > 0 || dbSize > 0) {
|
|
line2 += \` \${c.symbol}⬡\${c.reset} \${c.memory}\${memories > 0 ? memories : formatSize(dbSize)}\${c.reset} \${c.dim}mem\${c.reset}\`;
|
|
}
|
|
if (trajectories > 0) line2 += \` \${c.symbol}↝\${c.reset}\${c.trajectories}\${trajectories}\${c.reset}\`;
|
|
if (agents > 0) line2 += \` \${c.symbol}#\${c.reset}\${c.agents}\${activeAgents > 0 ? activeAgents + '/' : ''}\${agents}\${c.reset}\`;
|
|
lines.push(line2);
|
|
|
|
// Line 3: Routing info (compact)
|
|
const lrPercent = Math.round(LEARNING_RATE * 100);
|
|
const epsPercent = Math.round(EPSILON * 100);
|
|
let line3 = \`\${c.target}🎯 Routing\${c.reset} \${c.dim}q-learning\${c.reset}\`;
|
|
line3 += \` \${c.learning}lr:\${lrPercent}%\${c.reset} \${c.epsilon}ε:\${epsPercent}%\${c.reset}\`;
|
|
if (routes > 0) {
|
|
const successRate = dbStats.successfulRoutings > 0 ? Math.round((dbStats.successfulRoutings / routes) * 100) : 100;
|
|
line3 += \` \${c.symbol}|\${c.reset} \${c.success}\${successRate}% ✓\${c.reset}\`;
|
|
}
|
|
lines.push(line3);
|
|
|
|
console.log(lines.join('\\n'));
|
|
`;
|
|
fs.writeFileSync(statuslinePath, statuslineContent);
|
|
console.log(` 📊 Created: ${statuslinePath}`);
|
|
}
|
|
// Create settings
|
|
const settings = {
|
|
env: {
|
|
AGENTIC_FLOW_INTELLIGENCE: 'true',
|
|
AGENTIC_FLOW_LEARNING_RATE: '0.1',
|
|
AGENTIC_FLOW_MEMORY_BACKEND: 'agentdb'
|
|
},
|
|
hooks: {
|
|
PreToolUse: [
|
|
{
|
|
matcher: 'Edit|Write',
|
|
hooks: [
|
|
{
|
|
type: 'command',
|
|
command: 'npx agentic-flow hooks pre-edit "$TOOL_INPUT_file_path"'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
matcher: 'Bash',
|
|
hooks: [
|
|
{
|
|
type: 'command',
|
|
command: 'npx agentic-flow hooks pre-command "$TOOL_INPUT_command"'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
PostToolUse: [
|
|
{
|
|
matcher: 'Edit|Write',
|
|
hooks: [
|
|
{
|
|
type: 'command',
|
|
command: 'npx agentic-flow hooks post-edit "$TOOL_INPUT_file_path" --success'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
SessionStart: [
|
|
{
|
|
hooks: [
|
|
{
|
|
type: 'command',
|
|
command: 'npx agentic-flow hooks intelligence stats'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
UserPromptSubmit: [
|
|
{
|
|
hooks: [
|
|
{
|
|
type: 'command',
|
|
timeout: 2000,
|
|
command: 'npx agentic-flow hooks intelligence stats'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
permissions: {
|
|
allow: [
|
|
'Bash(npx:*)',
|
|
'Bash(agentic-flow:*)',
|
|
'mcp__agentic-flow'
|
|
]
|
|
},
|
|
statusLine: options.statusline !== false ? {
|
|
type: 'command',
|
|
command: 'node .claude/statusline.mjs'
|
|
} : undefined
|
|
};
|
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
console.log('✅ Hooks initialized!');
|
|
console.log(` 📁 Created: ${settingsPath}`);
|
|
console.log('\n💡 Next steps:');
|
|
console.log(' 1. Run: npx agentic-flow hooks pretrain');
|
|
console.log(' 2. Run: npx agentic-flow hooks build-agents');
|
|
console.log(' 3. Start using Claude Code with intelligent routing!');
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// ============================================
|
|
// RUVECTOR INTELLIGENCE COMMANDS
|
|
// SONA Micro-LoRA + MoE Attention + HNSW
|
|
// ============================================
|
|
// Create intelligence subcommand group
|
|
const intelligence = new Command('intelligence')
|
|
.alias('intel')
|
|
.description('RuVector intelligence: SONA Micro-LoRA (~0.05ms) + MoE attention + HNSW (150x faster)');
|
|
// Intelligence route command
|
|
intelligence
|
|
.command('route <task>')
|
|
.description('Route task using SONA + MoE + HNSW (150x faster than brute force)')
|
|
.option('-f, --file <path>', 'File context')
|
|
.option('-e, --error <context>', 'Error context for debugging')
|
|
.option('-k, --top-k <n>', 'Number of candidates', parseInt, 5)
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (task, options) => {
|
|
try {
|
|
const result = await intelligenceRouteTool.execute({ task, file: options.file, errorContext: options.error, topK: options.topK }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n⚡ RuVector Intelligence Route`);
|
|
console.log(`🎯 Agent: ${result.agent}`);
|
|
console.log(`📊 Confidence: ${((result.confidence || 0) * 100).toFixed(1)}%`);
|
|
console.log(`🔧 Engine: ${result.engine}`);
|
|
console.log(`⏱️ Latency: ${result.latencyMs?.toFixed(2)}ms`);
|
|
if (result.features?.length > 0) {
|
|
console.log(`🧠 Features: ${result.features.join(', ')}`);
|
|
}
|
|
if (result.alternatives?.length > 0) {
|
|
console.log(`\n🔄 Alternatives:`);
|
|
result.alternatives.forEach((a) => {
|
|
console.log(` - ${a.agent} (${((a.confidence || 0) * 100).toFixed(1)}%)`);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Trajectory start command
|
|
intelligence
|
|
.command('trajectory-start <task>')
|
|
.description('Begin SONA trajectory for reinforcement learning')
|
|
.requiredOption('-a, --agent <name>', 'Agent executing the task')
|
|
.option('-c, --context <text>', 'Additional context')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (task, options) => {
|
|
try {
|
|
const result = await intelligenceTrajectoryStartTool.execute({ task, agent: options.agent, context: options.context }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🎬 Trajectory Started`);
|
|
console.log(`📝 ID: ${result.trajectoryId}`);
|
|
console.log(`🤖 Agent: ${options.agent}`);
|
|
console.log(`🧠 Features: ${result.features?.join(', ')}`);
|
|
console.log(`\n💡 Use this ID with trajectory-step and trajectory-end commands`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Trajectory step command
|
|
intelligence
|
|
.command('trajectory-step <trajectoryId>')
|
|
.description('Record step in trajectory for reinforcement learning')
|
|
.requiredOption('-a, --action <action>', 'Action taken')
|
|
.requiredOption('-r, --reward <n>', 'Reward signal (-1 to 1)', parseFloat)
|
|
.option('-f, --file <path>', 'File involved')
|
|
.option('--error-fixed', 'Mark as error fix')
|
|
.option('--test-passed', 'Mark as test passed')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (trajectoryId, options) => {
|
|
try {
|
|
const result = await intelligenceTrajectoryStepTool.execute({
|
|
trajectoryId: parseInt(trajectoryId),
|
|
action: options.action,
|
|
reward: options.reward,
|
|
file: options.file,
|
|
errorFixed: options.errorFixed,
|
|
testPassed: options.testPassed
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n📍 Step Recorded`);
|
|
console.log(` Action: ${options.action}`);
|
|
console.log(` Reward: ${options.reward}`);
|
|
console.log(` Trajectory: ${trajectoryId}`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Trajectory end command
|
|
intelligence
|
|
.command('trajectory-end <trajectoryId>')
|
|
.description('End trajectory and trigger SONA learning with EWC++')
|
|
.option('-s, --success', 'Mark as successful')
|
|
.option('-f, --fail', 'Mark as failed')
|
|
.option('-q, --quality <n>', 'Quality score (0-1)', parseFloat, 0.8)
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (trajectoryId, options) => {
|
|
try {
|
|
const success = options.success || !options.fail;
|
|
const result = await intelligenceTrajectoryEndTool.execute({ trajectoryId: parseInt(trajectoryId), success, quality: options.quality }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🏁 Trajectory Completed`);
|
|
console.log(` ${success ? '✅ Success' : '❌ Failed'}`);
|
|
console.log(` Quality: ${(options.quality || 0.8) * 100}%`);
|
|
console.log(` Learning: EWC++ consolidation applied`);
|
|
if (result.learningOutcome) {
|
|
console.log(` Outcome: ${JSON.stringify(result.learningOutcome)}`);
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Pattern store command
|
|
intelligence
|
|
.command('pattern-store')
|
|
.description('Store pattern in ReasoningBank (HNSW-indexed)')
|
|
.requiredOption('-t, --task <task>', 'Task description')
|
|
.requiredOption('-r, --resolution <text>', 'How it was resolved')
|
|
.option('-s, --score <n>', 'Success score (0-1)', parseFloat, 0.9)
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (options) => {
|
|
try {
|
|
const result = await intelligencePatternStoreTool.execute({ task: options.task, resolution: options.resolution, reward: options.score || 0.9 }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n💾 Pattern Stored`);
|
|
console.log(` Task: ${options.task.slice(0, 50)}...`);
|
|
console.log(` Score: ${((options.score || 0.9) * 100).toFixed(0)}%`);
|
|
console.log(` Index: HNSW (150x faster retrieval)`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Pattern search command
|
|
intelligence
|
|
.command('pattern-search <query>')
|
|
.description('Search ReasoningBank using HNSW (150x faster)')
|
|
.option('-k, --top-k <n>', 'Number of results', parseInt, 5)
|
|
.option('-m, --min-reward <n>', 'Minimum reward filter', parseFloat)
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (query, options) => {
|
|
try {
|
|
const result = await intelligencePatternSearchTool.execute({ query, topK: options.topK, minReward: options.minReward }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🔍 Pattern Search Results`);
|
|
console.log(` Query: "${query.slice(0, 50)}"`);
|
|
console.log(` Engine: ${result.searchEngine}`);
|
|
console.log(` Found: ${result.count} patterns`);
|
|
if (result.patterns?.length > 0) {
|
|
console.log(`\n 📋 Results:`);
|
|
result.patterns.forEach((p, i) => {
|
|
console.log(` ${i + 1}. [${((p.similarity || 0) * 100).toFixed(0)}%] ${p.resolution?.slice(0, 40)}...`);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Intelligence stats command
|
|
intelligence
|
|
.command('stats')
|
|
.description('Get RuVector intelligence layer statistics')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (options) => {
|
|
try {
|
|
const result = await intelligenceStatsTool.execute({}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n📊 RuVector Intelligence Stats`);
|
|
console.log(`\n🧠 SONA Engine:`);
|
|
console.log(` Micro-LoRA: ${result.features?.sona?.microLora || 'rank-1 (~0.05ms)'}`);
|
|
console.log(` Base-LoRA: ${result.features?.sona?.baseLora || 'rank-8'}`);
|
|
console.log(` EWC Lambda: ${result.features?.sona?.ewcLambda || 1000.0}`);
|
|
console.log(`\n⚡ Attention:`);
|
|
console.log(` Type: ${result.features?.attention?.type || 'moe'}`);
|
|
console.log(` Experts: ${result.features?.attention?.experts || 4}`);
|
|
console.log(` Top-K: ${result.features?.attention?.topK || 2}`);
|
|
console.log(`\n🔍 HNSW:`);
|
|
console.log(` Enabled: ${result.features?.hnsw?.enabled ?? true}`);
|
|
console.log(` Speedup: ${result.features?.hnsw?.speedup || '150x vs brute-force'}`);
|
|
console.log(`\n📈 Learning:`);
|
|
console.log(` Trajectories: ${result.persistence?.trajectories ?? result.stats?.trajectoryCount ?? 0}`);
|
|
console.log(` Active: ${result.stats?.activeTrajectories || 0}`);
|
|
console.log(`\n💾 Persistence (SQLite):`);
|
|
console.log(` Backend: ${result.persistence?.backend || 'sqlite'}`);
|
|
console.log(` Routings: ${result.persistence?.routings ?? 0}`);
|
|
console.log(` Patterns: ${result.persistence?.patterns ?? 0}`);
|
|
console.log(` Operations: ${result.persistence?.operations ?? 0}`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Force learning command
|
|
intelligence
|
|
.command('learn')
|
|
.description('Force immediate SONA learning cycle with EWC++ consolidation')
|
|
.option('-r, --reason <text>', 'Reason for forcing learning')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (options) => {
|
|
try {
|
|
const result = await intelligenceLearnTool.execute({ reason: options.reason }, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🎓 Learning Cycle Complete`);
|
|
console.log(` ${result.success ? '✅' : '❌'} ${result.message}`);
|
|
console.log(` Reason: ${result.reason || 'manual trigger'}`);
|
|
console.log(` Features: ${result.features?.join(', ')}`);
|
|
console.log(` Latency: ${result.latencyMs?.toFixed(2)}ms`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Attention compute command
|
|
intelligence
|
|
.command('attention <query>')
|
|
.description('Compute attention-weighted similarity using MoE/Flash/Hyperbolic')
|
|
.requiredOption('-c, --candidates <texts...>', 'Candidate texts to score')
|
|
.option('-t, --type <type>', 'Attention type: moe|flash|hyperbolic|graph|dual', 'moe')
|
|
.option('-j, --json', 'Output as JSON')
|
|
.action(async (query, options) => {
|
|
try {
|
|
const result = await intelligenceAttentionTool.execute({
|
|
query,
|
|
candidates: options.candidates,
|
|
attentionType: options.type
|
|
}, mockContext);
|
|
if (options.json) {
|
|
console.log(JSON.stringify(result, null, 2));
|
|
}
|
|
else {
|
|
console.log(`\n🧠 Attention Scores (${options.type || 'moe'})`);
|
|
console.log(` Query: "${query.slice(0, 40)}..."`);
|
|
console.log(`\n 📊 Results:`);
|
|
result.results?.forEach((r, i) => {
|
|
const bar = '█'.repeat(Math.round(r.score * 20));
|
|
console.log(` ${i + 1}. ${bar} ${(r.score * 100).toFixed(1)}% "${r.text}"`);
|
|
});
|
|
console.log(`\n ⏱️ Latency: ${result.latencyMs?.toFixed(2)}ms`);
|
|
}
|
|
}
|
|
catch (error) {
|
|
console.error('Error:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
// Add intelligence subcommand to hooks
|
|
hooks.addCommand(intelligence);
|
|
return hooks;
|
|
}
|
|
export default createHooksCommand;
|
|
//# sourceMappingURL=hooks.js.map
|