ruvector 0.1.46 → 0.1.48
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/bin/cli.js +615 -3
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -2311,7 +2311,9 @@ hooksCmd.command('init')
|
|
|
2311
2311
|
.option('--no-gitignore', 'Skip .gitignore update')
|
|
2312
2312
|
.option('--no-mcp', 'Skip MCP server configuration')
|
|
2313
2313
|
.option('--no-statusline', 'Skip statusLine configuration')
|
|
2314
|
-
.
|
|
2314
|
+
.option('--pretrain', 'Run pretrain after init to bootstrap intelligence')
|
|
2315
|
+
.option('--build-agents [focus]', 'Generate optimized agents (quality|speed|security|testing|fullstack)')
|
|
2316
|
+
.action(async (opts) => {
|
|
2315
2317
|
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
|
|
2316
2318
|
const settingsDir = path.dirname(settingsPath);
|
|
2317
2319
|
if (!fs.existsSync(settingsDir)) fs.mkdirSync(settingsDir, { recursive: true });
|
|
@@ -2353,7 +2355,8 @@ hooksCmd.command('init')
|
|
|
2353
2355
|
'Bash(rm -rf /)',
|
|
2354
2356
|
'Bash(sudo rm:*)',
|
|
2355
2357
|
'Bash(chmod 777:*)',
|
|
2356
|
-
'Bash(
|
|
2358
|
+
'Bash(mkfs:*)',
|
|
2359
|
+
'Bash(dd if=/dev/zero:*)'
|
|
2357
2360
|
];
|
|
2358
2361
|
console.log(chalk.blue(' ✓ Permissions configured (project-specific)'));
|
|
2359
2362
|
}
|
|
@@ -2572,7 +2575,35 @@ npx ruvector hooks init --force # Overwrite existing
|
|
|
2572
2575
|
}
|
|
2573
2576
|
|
|
2574
2577
|
console.log(chalk.green('\n✅ RuVector hooks initialization complete!'));
|
|
2575
|
-
|
|
2578
|
+
|
|
2579
|
+
// Run pretrain if requested
|
|
2580
|
+
if (opts.pretrain) {
|
|
2581
|
+
console.log(chalk.yellow('\n📚 Running pretrain to bootstrap intelligence...\n'));
|
|
2582
|
+
const { execSync } = require('child_process');
|
|
2583
|
+
try {
|
|
2584
|
+
execSync('npx ruvector hooks pretrain', { stdio: 'inherit' });
|
|
2585
|
+
} catch (e) {
|
|
2586
|
+
console.log(chalk.yellow('⚠️ Pretrain completed with warnings'));
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// Build agents if requested
|
|
2591
|
+
if (opts.buildAgents) {
|
|
2592
|
+
const focus = typeof opts.buildAgents === 'string' ? opts.buildAgents : 'quality';
|
|
2593
|
+
console.log(chalk.yellow(`\n🏗️ Building optimized agents (focus: ${focus})...\n`));
|
|
2594
|
+
const { execSync } = require('child_process');
|
|
2595
|
+
try {
|
|
2596
|
+
execSync(`npx ruvector hooks build-agents --focus ${focus} --include-prompts`, { stdio: 'inherit' });
|
|
2597
|
+
} catch (e) {
|
|
2598
|
+
console.log(chalk.yellow('⚠️ Agent build completed with warnings'));
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
if (!opts.pretrain && !opts.buildAgents) {
|
|
2603
|
+
console.log(chalk.dim(' Run `npx ruvector hooks verify` to test the setup'));
|
|
2604
|
+
console.log(chalk.dim(' Run `npx ruvector hooks pretrain` to bootstrap intelligence'));
|
|
2605
|
+
console.log(chalk.dim(' Run `npx ruvector hooks build-agents` to generate optimized agents'));
|
|
2606
|
+
}
|
|
2576
2607
|
});
|
|
2577
2608
|
|
|
2578
2609
|
hooksCmd.command('stats').description('Show intelligence statistics').action(() => {
|
|
@@ -2996,4 +3027,585 @@ hooksCmd.command('import')
|
|
|
2996
3027
|
}
|
|
2997
3028
|
});
|
|
2998
3029
|
|
|
3030
|
+
// Pretrain - analyze repo and bootstrap learning with agent swarm
|
|
3031
|
+
hooksCmd.command('pretrain')
|
|
3032
|
+
.description('Pretrain intelligence by analyzing the repository with agent swarm')
|
|
3033
|
+
.option('--depth <n>', 'Git history depth to analyze', '100')
|
|
3034
|
+
.option('--workers <n>', 'Number of parallel analysis workers', '4')
|
|
3035
|
+
.option('--skip-git', 'Skip git history analysis')
|
|
3036
|
+
.option('--skip-files', 'Skip file structure analysis')
|
|
3037
|
+
.option('--verbose', 'Show detailed progress')
|
|
3038
|
+
.action(async (opts) => {
|
|
3039
|
+
const { execSync, spawn } = require('child_process');
|
|
3040
|
+
console.log(chalk.bold.cyan('\n🧠 RuVector Pretrain - Repository Intelligence Bootstrap\n'));
|
|
3041
|
+
|
|
3042
|
+
const intel = new Intelligence();
|
|
3043
|
+
const startTime = Date.now();
|
|
3044
|
+
const stats = { files: 0, patterns: 0, memories: 0, coedits: 0 };
|
|
3045
|
+
|
|
3046
|
+
// Agent types for different file patterns
|
|
3047
|
+
const agentMapping = {
|
|
3048
|
+
// Rust
|
|
3049
|
+
'.rs': 'rust-developer',
|
|
3050
|
+
'Cargo.toml': 'rust-developer',
|
|
3051
|
+
'Cargo.lock': 'rust-developer',
|
|
3052
|
+
// JavaScript/TypeScript
|
|
3053
|
+
'.js': 'javascript-developer',
|
|
3054
|
+
'.jsx': 'react-developer',
|
|
3055
|
+
'.ts': 'typescript-developer',
|
|
3056
|
+
'.tsx': 'react-developer',
|
|
3057
|
+
'.mjs': 'javascript-developer',
|
|
3058
|
+
'.cjs': 'javascript-developer',
|
|
3059
|
+
'package.json': 'node-developer',
|
|
3060
|
+
// Python
|
|
3061
|
+
'.py': 'python-developer',
|
|
3062
|
+
'requirements.txt': 'python-developer',
|
|
3063
|
+
'pyproject.toml': 'python-developer',
|
|
3064
|
+
'setup.py': 'python-developer',
|
|
3065
|
+
// Go
|
|
3066
|
+
'.go': 'go-developer',
|
|
3067
|
+
'go.mod': 'go-developer',
|
|
3068
|
+
// Web
|
|
3069
|
+
'.html': 'frontend-developer',
|
|
3070
|
+
'.css': 'frontend-developer',
|
|
3071
|
+
'.scss': 'frontend-developer',
|
|
3072
|
+
'.vue': 'vue-developer',
|
|
3073
|
+
'.svelte': 'svelte-developer',
|
|
3074
|
+
// Config
|
|
3075
|
+
'.json': 'config-specialist',
|
|
3076
|
+
'.yaml': 'config-specialist',
|
|
3077
|
+
'.yml': 'config-specialist',
|
|
3078
|
+
'.toml': 'config-specialist',
|
|
3079
|
+
// Docs
|
|
3080
|
+
'.md': 'documentation-specialist',
|
|
3081
|
+
'.mdx': 'documentation-specialist',
|
|
3082
|
+
// Tests
|
|
3083
|
+
'.test.js': 'test-engineer',
|
|
3084
|
+
'.test.ts': 'test-engineer',
|
|
3085
|
+
'.spec.js': 'test-engineer',
|
|
3086
|
+
'.spec.ts': 'test-engineer',
|
|
3087
|
+
'_test.go': 'test-engineer',
|
|
3088
|
+
'_test.rs': 'test-engineer',
|
|
3089
|
+
// DevOps
|
|
3090
|
+
'Dockerfile': 'devops-engineer',
|
|
3091
|
+
'docker-compose.yml': 'devops-engineer',
|
|
3092
|
+
'.github/workflows': 'cicd-engineer',
|
|
3093
|
+
'Makefile': 'devops-engineer',
|
|
3094
|
+
// SQL
|
|
3095
|
+
'.sql': 'database-specialist',
|
|
3096
|
+
};
|
|
3097
|
+
|
|
3098
|
+
// Phase 1: Analyze file structure
|
|
3099
|
+
if (!opts.skipFiles) {
|
|
3100
|
+
console.log(chalk.yellow('📁 Phase 1: Analyzing file structure...\n'));
|
|
3101
|
+
|
|
3102
|
+
try {
|
|
3103
|
+
// Get all files in repo
|
|
3104
|
+
const files = execSync('git ls-files 2>/dev/null || find . -type f -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./target/*"',
|
|
3105
|
+
{ encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 }).trim().split('\n').filter(f => f);
|
|
3106
|
+
|
|
3107
|
+
const filesByType = {};
|
|
3108
|
+
const dirPatterns = {};
|
|
3109
|
+
|
|
3110
|
+
files.forEach(file => {
|
|
3111
|
+
stats.files++;
|
|
3112
|
+
const ext = path.extname(file);
|
|
3113
|
+
const basename = path.basename(file);
|
|
3114
|
+
const dir = path.dirname(file);
|
|
3115
|
+
|
|
3116
|
+
// Determine agent for this file
|
|
3117
|
+
let agent = 'coder'; // default
|
|
3118
|
+
if (agentMapping[basename]) {
|
|
3119
|
+
agent = agentMapping[basename];
|
|
3120
|
+
} else if (agentMapping[ext]) {
|
|
3121
|
+
agent = agentMapping[ext];
|
|
3122
|
+
} else if (file.includes('.test.') || file.includes('.spec.') || file.includes('_test.')) {
|
|
3123
|
+
agent = 'test-engineer';
|
|
3124
|
+
} else if (file.includes('.github/workflows')) {
|
|
3125
|
+
agent = 'cicd-engineer';
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3128
|
+
// Track file types
|
|
3129
|
+
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
3130
|
+
|
|
3131
|
+
// Track directory patterns
|
|
3132
|
+
const parts = dir.split('/');
|
|
3133
|
+
if (parts[0]) {
|
|
3134
|
+
dirPatterns[parts[0]] = dirPatterns[parts[0]] || { count: 0, agents: {} };
|
|
3135
|
+
dirPatterns[parts[0]].count++;
|
|
3136
|
+
dirPatterns[parts[0]].agents[agent] = (dirPatterns[parts[0]].agents[agent] || 0) + 1;
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
// Create Q-learning pattern for this file type
|
|
3140
|
+
const state = `edit:${ext || 'unknown'}`;
|
|
3141
|
+
if (!intel.data.patterns[state]) {
|
|
3142
|
+
intel.data.patterns[state] = {};
|
|
3143
|
+
}
|
|
3144
|
+
intel.data.patterns[state][agent] = (intel.data.patterns[state][agent] || 0) + 0.5;
|
|
3145
|
+
stats.patterns++;
|
|
3146
|
+
});
|
|
3147
|
+
|
|
3148
|
+
// Log summary
|
|
3149
|
+
if (opts.verbose) {
|
|
3150
|
+
console.log(chalk.dim(' File types found:'));
|
|
3151
|
+
Object.entries(filesByType).sort((a, b) => b[1] - a[1]).slice(0, 10).forEach(([ext, count]) => {
|
|
3152
|
+
console.log(chalk.dim(` ${ext || '(no ext)'}: ${count} files`));
|
|
3153
|
+
});
|
|
3154
|
+
}
|
|
3155
|
+
console.log(chalk.green(` ✓ Analyzed ${stats.files} files`));
|
|
3156
|
+
console.log(chalk.green(` ✓ Created ${Object.keys(intel.data.patterns).length} routing patterns`));
|
|
3157
|
+
|
|
3158
|
+
} catch (e) {
|
|
3159
|
+
console.log(chalk.yellow(` ⚠ File analysis skipped: ${e.message}`));
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
// Phase 2: Analyze git history for co-edit patterns
|
|
3164
|
+
if (!opts.skipGit) {
|
|
3165
|
+
console.log(chalk.yellow('\n📜 Phase 2: Analyzing git history for co-edit patterns...\n'));
|
|
3166
|
+
|
|
3167
|
+
try {
|
|
3168
|
+
// Get commits with files changed
|
|
3169
|
+
const gitLog = execSync(
|
|
3170
|
+
`git log --name-only --pretty=format:"COMMIT:%H" -n ${opts.depth} 2>/dev/null`,
|
|
3171
|
+
{ encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 }
|
|
3172
|
+
);
|
|
3173
|
+
|
|
3174
|
+
const commits = gitLog.split('COMMIT:').filter(c => c.trim());
|
|
3175
|
+
const coEditMap = {};
|
|
3176
|
+
|
|
3177
|
+
commits.forEach(commit => {
|
|
3178
|
+
const lines = commit.trim().split('\n').filter(l => l && !l.startsWith('COMMIT:'));
|
|
3179
|
+
const files = lines.slice(1).filter(f => f.trim()); // Skip the hash
|
|
3180
|
+
|
|
3181
|
+
// Track which files are edited together
|
|
3182
|
+
files.forEach(file1 => {
|
|
3183
|
+
files.forEach(file2 => {
|
|
3184
|
+
if (file1 !== file2) {
|
|
3185
|
+
const key = [file1, file2].sort().join('|');
|
|
3186
|
+
coEditMap[key] = (coEditMap[key] || 0) + 1;
|
|
3187
|
+
}
|
|
3188
|
+
});
|
|
3189
|
+
});
|
|
3190
|
+
});
|
|
3191
|
+
|
|
3192
|
+
// Find strong co-edit patterns (files edited together 3+ times)
|
|
3193
|
+
const strongPatterns = Object.entries(coEditMap)
|
|
3194
|
+
.filter(([, count]) => count >= 3)
|
|
3195
|
+
.sort((a, b) => b[1] - a[1]);
|
|
3196
|
+
|
|
3197
|
+
// Store as sequence patterns
|
|
3198
|
+
strongPatterns.slice(0, 100).forEach(([key, count]) => {
|
|
3199
|
+
const [file1, file2] = key.split('|');
|
|
3200
|
+
if (!intel.data.sequences) intel.data.sequences = {};
|
|
3201
|
+
if (!intel.data.sequences[file1]) intel.data.sequences[file1] = [];
|
|
3202
|
+
|
|
3203
|
+
const existing = intel.data.sequences[file1].find(s => s.file === file2);
|
|
3204
|
+
if (existing) {
|
|
3205
|
+
existing.score += count;
|
|
3206
|
+
} else {
|
|
3207
|
+
intel.data.sequences[file1].push({ file: file2, score: count });
|
|
3208
|
+
}
|
|
3209
|
+
stats.coedits++;
|
|
3210
|
+
});
|
|
3211
|
+
|
|
3212
|
+
console.log(chalk.green(` ✓ Analyzed ${commits.length} commits`));
|
|
3213
|
+
console.log(chalk.green(` ✓ Found ${strongPatterns.length} co-edit patterns`));
|
|
3214
|
+
|
|
3215
|
+
if (opts.verbose && strongPatterns.length > 0) {
|
|
3216
|
+
console.log(chalk.dim(' Top co-edit patterns:'));
|
|
3217
|
+
strongPatterns.slice(0, 5).forEach(([key, count]) => {
|
|
3218
|
+
const [f1, f2] = key.split('|');
|
|
3219
|
+
console.log(chalk.dim(` ${path.basename(f1)} ↔ ${path.basename(f2)}: ${count} times`));
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
} catch (e) {
|
|
3224
|
+
console.log(chalk.yellow(` ⚠ Git analysis skipped: ${e.message}`));
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
// Phase 3: Create vector memories from important files
|
|
3229
|
+
console.log(chalk.yellow('\n💾 Phase 3: Creating vector memories from key files...\n'));
|
|
3230
|
+
|
|
3231
|
+
try {
|
|
3232
|
+
const importantFiles = [
|
|
3233
|
+
'README.md', 'CLAUDE.md', 'package.json', 'Cargo.toml',
|
|
3234
|
+
'pyproject.toml', 'go.mod', '.claude/settings.json'
|
|
3235
|
+
];
|
|
3236
|
+
|
|
3237
|
+
for (const filename of importantFiles) {
|
|
3238
|
+
const filePath = path.join(process.cwd(), filename);
|
|
3239
|
+
if (fs.existsSync(filePath)) {
|
|
3240
|
+
try {
|
|
3241
|
+
const content = fs.readFileSync(filePath, 'utf-8').slice(0, 2000); // First 2KB
|
|
3242
|
+
intel.data.memories = intel.data.memories || [];
|
|
3243
|
+
intel.data.memories.push({
|
|
3244
|
+
content: `[${filename}] ${content.replace(/\n/g, ' ').slice(0, 500)}`,
|
|
3245
|
+
type: 'project',
|
|
3246
|
+
created: new Date().toISOString(),
|
|
3247
|
+
embedding: intel.simpleEmbed ? intel.simpleEmbed(content) : null
|
|
3248
|
+
});
|
|
3249
|
+
stats.memories++;
|
|
3250
|
+
if (opts.verbose) console.log(chalk.dim(` ✓ ${filename}`));
|
|
3251
|
+
} catch (e) { /* skip unreadable files */ }
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
console.log(chalk.green(` ✓ Created ${stats.memories} memory entries`));
|
|
3256
|
+
|
|
3257
|
+
} catch (e) {
|
|
3258
|
+
console.log(chalk.yellow(` ⚠ Memory creation skipped: ${e.message}`));
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
// Phase 4: Analyze directory structure for agent recommendations
|
|
3262
|
+
console.log(chalk.yellow('\n🗂️ Phase 4: Building directory-agent mappings...\n'));
|
|
3263
|
+
|
|
3264
|
+
try {
|
|
3265
|
+
const dirs = execSync('find . -type d -maxdepth 2 -not -path "./.git*" -not -path "./node_modules*" -not -path "./target*" 2>/dev/null || echo "."',
|
|
3266
|
+
{ encoding: 'utf-8' }).trim().split('\n');
|
|
3267
|
+
|
|
3268
|
+
const dirAgentMap = {};
|
|
3269
|
+
dirs.forEach(dir => {
|
|
3270
|
+
const name = path.basename(dir);
|
|
3271
|
+
// Infer agent from directory name
|
|
3272
|
+
if (['src', 'lib', 'core'].includes(name)) dirAgentMap[dir] = 'coder';
|
|
3273
|
+
else if (['test', 'tests', '__tests__', 'spec'].includes(name)) dirAgentMap[dir] = 'test-engineer';
|
|
3274
|
+
else if (['docs', 'documentation'].includes(name)) dirAgentMap[dir] = 'documentation-specialist';
|
|
3275
|
+
else if (['scripts', 'bin'].includes(name)) dirAgentMap[dir] = 'devops-engineer';
|
|
3276
|
+
else if (['components', 'views', 'pages'].includes(name)) dirAgentMap[dir] = 'frontend-developer';
|
|
3277
|
+
else if (['api', 'routes', 'handlers'].includes(name)) dirAgentMap[dir] = 'backend-developer';
|
|
3278
|
+
else if (['models', 'entities', 'schemas'].includes(name)) dirAgentMap[dir] = 'database-specialist';
|
|
3279
|
+
else if (['.github', '.gitlab', 'ci'].includes(name)) dirAgentMap[dir] = 'cicd-engineer';
|
|
3280
|
+
});
|
|
3281
|
+
|
|
3282
|
+
// Store directory patterns
|
|
3283
|
+
intel.data.dirPatterns = dirAgentMap;
|
|
3284
|
+
console.log(chalk.green(` ✓ Mapped ${Object.keys(dirAgentMap).length} directories to agents`));
|
|
3285
|
+
|
|
3286
|
+
} catch (e) {
|
|
3287
|
+
console.log(chalk.yellow(` ⚠ Directory analysis skipped: ${e.message}`));
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
// Save all learning data
|
|
3291
|
+
intel.data.pretrained = {
|
|
3292
|
+
date: new Date().toISOString(),
|
|
3293
|
+
stats: stats
|
|
3294
|
+
};
|
|
3295
|
+
intel.save();
|
|
3296
|
+
|
|
3297
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
3298
|
+
console.log(chalk.bold.green(`\n✅ Pretrain complete in ${elapsed}s!\n`));
|
|
3299
|
+
console.log(chalk.cyan('Summary:'));
|
|
3300
|
+
console.log(` 📁 ${stats.files} files analyzed`);
|
|
3301
|
+
console.log(` 🧠 ${stats.patterns} agent routing patterns`);
|
|
3302
|
+
console.log(` 🔗 ${stats.coedits} co-edit patterns`);
|
|
3303
|
+
console.log(` 💾 ${stats.memories} memory entries`);
|
|
3304
|
+
console.log(chalk.dim('\nThe intelligence layer will now provide better recommendations.'));
|
|
3305
|
+
});
|
|
3306
|
+
|
|
3307
|
+
// Agent Builder - generate optimized agent configs based on pretrain
|
|
3308
|
+
hooksCmd.command('build-agents')
|
|
3309
|
+
.description('Generate optimized agent configurations based on repository analysis')
|
|
3310
|
+
.option('--focus <type>', 'Focus type: quality, speed, security, testing, fullstack', 'quality')
|
|
3311
|
+
.option('--output <dir>', 'Output directory', '.claude/agents')
|
|
3312
|
+
.option('--format <fmt>', 'Format: yaml, json, md', 'yaml')
|
|
3313
|
+
.option('--include-prompts', 'Include detailed system prompts')
|
|
3314
|
+
.action((opts) => {
|
|
3315
|
+
console.log(chalk.bold.cyan('\n🏗️ RuVector Agent Builder\n'));
|
|
3316
|
+
|
|
3317
|
+
const intel = new Intelligence();
|
|
3318
|
+
const outputDir = path.join(process.cwd(), opts.output);
|
|
3319
|
+
|
|
3320
|
+
// Check if pretrained
|
|
3321
|
+
if (!intel.data.pretrained && Object.keys(intel.data.patterns || {}).length === 0) {
|
|
3322
|
+
console.log(chalk.yellow('⚠️ No pretrain data found. Running quick analysis...\n'));
|
|
3323
|
+
// Quick file analysis
|
|
3324
|
+
try {
|
|
3325
|
+
const { execSync } = require('child_process');
|
|
3326
|
+
const files = execSync('git ls-files 2>/dev/null', { encoding: 'utf-8' }).trim().split('\n');
|
|
3327
|
+
files.forEach(f => {
|
|
3328
|
+
const ext = path.extname(f);
|
|
3329
|
+
intel.data.patterns = intel.data.patterns || {};
|
|
3330
|
+
intel.data.patterns[`edit:${ext}`] = intel.data.patterns[`edit:${ext}`] || {};
|
|
3331
|
+
});
|
|
3332
|
+
} catch (e) { /* continue without git */ }
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
// Analyze patterns to determine relevant agents
|
|
3336
|
+
const patterns = intel.data.patterns || {};
|
|
3337
|
+
const detectedLangs = new Set();
|
|
3338
|
+
const detectedFrameworks = new Set();
|
|
3339
|
+
|
|
3340
|
+
Object.keys(patterns).forEach(state => {
|
|
3341
|
+
if (state.includes('.rs')) detectedLangs.add('rust');
|
|
3342
|
+
if (state.includes('.ts') || state.includes('.js')) detectedLangs.add('typescript');
|
|
3343
|
+
if (state.includes('.tsx') || state.includes('.jsx')) detectedFrameworks.add('react');
|
|
3344
|
+
if (state.includes('.py')) detectedLangs.add('python');
|
|
3345
|
+
if (state.includes('.go')) detectedLangs.add('go');
|
|
3346
|
+
if (state.includes('.vue')) detectedFrameworks.add('vue');
|
|
3347
|
+
if (state.includes('.sql')) detectedFrameworks.add('database');
|
|
3348
|
+
});
|
|
3349
|
+
|
|
3350
|
+
// Detect project type from files
|
|
3351
|
+
const projectTypes = detectProjectType();
|
|
3352
|
+
|
|
3353
|
+
console.log(chalk.blue(` Detected languages: ${[...detectedLangs].join(', ') || 'generic'}`));
|
|
3354
|
+
console.log(chalk.blue(` Detected frameworks: ${[...detectedFrameworks].join(', ') || 'none'}`));
|
|
3355
|
+
console.log(chalk.blue(` Focus mode: ${opts.focus}\n`));
|
|
3356
|
+
|
|
3357
|
+
// Focus configurations
|
|
3358
|
+
const focusConfigs = {
|
|
3359
|
+
quality: {
|
|
3360
|
+
description: 'Emphasizes code quality, best practices, and maintainability',
|
|
3361
|
+
priorities: ['code-review', 'refactoring', 'documentation', 'testing'],
|
|
3362
|
+
temperature: 0.3
|
|
3363
|
+
},
|
|
3364
|
+
speed: {
|
|
3365
|
+
description: 'Optimized for rapid development and iteration',
|
|
3366
|
+
priorities: ['implementation', 'prototyping', 'quick-fixes'],
|
|
3367
|
+
temperature: 0.7
|
|
3368
|
+
},
|
|
3369
|
+
security: {
|
|
3370
|
+
description: 'Security-first development with vulnerability awareness',
|
|
3371
|
+
priorities: ['security-audit', 'input-validation', 'authentication', 'encryption'],
|
|
3372
|
+
temperature: 0.2
|
|
3373
|
+
},
|
|
3374
|
+
testing: {
|
|
3375
|
+
description: 'Test-driven development with comprehensive coverage',
|
|
3376
|
+
priorities: ['unit-tests', 'integration-tests', 'e2e-tests', 'mocking'],
|
|
3377
|
+
temperature: 0.4
|
|
3378
|
+
},
|
|
3379
|
+
fullstack: {
|
|
3380
|
+
description: 'Balanced full-stack development capabilities',
|
|
3381
|
+
priorities: ['frontend', 'backend', 'database', 'api-design'],
|
|
3382
|
+
temperature: 0.5
|
|
3383
|
+
}
|
|
3384
|
+
};
|
|
3385
|
+
|
|
3386
|
+
const focus = focusConfigs[opts.focus] || focusConfigs.quality;
|
|
3387
|
+
|
|
3388
|
+
// Agent templates based on detected stack
|
|
3389
|
+
const agents = [];
|
|
3390
|
+
|
|
3391
|
+
// Core agents based on detected languages
|
|
3392
|
+
if (detectedLangs.has('rust')) {
|
|
3393
|
+
agents.push({
|
|
3394
|
+
name: 'rust-specialist',
|
|
3395
|
+
type: 'rust-developer',
|
|
3396
|
+
description: 'Rust development specialist for this codebase',
|
|
3397
|
+
capabilities: ['cargo', 'unsafe-rust', 'async-rust', 'wasm', 'error-handling'],
|
|
3398
|
+
focus: focus.priorities,
|
|
3399
|
+
systemPrompt: opts.includePrompts ? `You are a Rust specialist for this project.
|
|
3400
|
+
Focus on: memory safety, zero-cost abstractions, idiomatic Rust patterns.
|
|
3401
|
+
Use cargo conventions, prefer Result over panic, leverage the type system.
|
|
3402
|
+
${focus.description}` : null
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
|
|
3406
|
+
if (detectedLangs.has('typescript')) {
|
|
3407
|
+
agents.push({
|
|
3408
|
+
name: 'typescript-specialist',
|
|
3409
|
+
type: 'typescript-developer',
|
|
3410
|
+
description: 'TypeScript development specialist',
|
|
3411
|
+
capabilities: ['types', 'generics', 'decorators', 'async-await', 'modules'],
|
|
3412
|
+
focus: focus.priorities,
|
|
3413
|
+
systemPrompt: opts.includePrompts ? `You are a TypeScript specialist for this project.
|
|
3414
|
+
Focus on: strict typing, type inference, generic patterns, module organization.
|
|
3415
|
+
Prefer type safety over any, use discriminated unions, leverage utility types.
|
|
3416
|
+
${focus.description}` : null
|
|
3417
|
+
});
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
if (detectedLangs.has('python')) {
|
|
3421
|
+
agents.push({
|
|
3422
|
+
name: 'python-specialist',
|
|
3423
|
+
type: 'python-developer',
|
|
3424
|
+
description: 'Python development specialist',
|
|
3425
|
+
capabilities: ['typing', 'async', 'testing', 'packaging', 'data-science'],
|
|
3426
|
+
focus: focus.priorities,
|
|
3427
|
+
systemPrompt: opts.includePrompts ? `You are a Python specialist for this project.
|
|
3428
|
+
Focus on: type hints, PEP standards, pythonic idioms, virtual environments.
|
|
3429
|
+
Use dataclasses, prefer pathlib, leverage context managers.
|
|
3430
|
+
${focus.description}` : null
|
|
3431
|
+
});
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
if (detectedLangs.has('go')) {
|
|
3435
|
+
agents.push({
|
|
3436
|
+
name: 'go-specialist',
|
|
3437
|
+
type: 'go-developer',
|
|
3438
|
+
description: 'Go development specialist',
|
|
3439
|
+
capabilities: ['goroutines', 'channels', 'interfaces', 'testing', 'modules'],
|
|
3440
|
+
focus: focus.priorities,
|
|
3441
|
+
systemPrompt: opts.includePrompts ? `You are a Go specialist for this project.
|
|
3442
|
+
Focus on: simplicity, explicit error handling, goroutines, interface composition.
|
|
3443
|
+
Follow Go conventions, use go fmt, prefer composition over inheritance.
|
|
3444
|
+
${focus.description}` : null
|
|
3445
|
+
});
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
// Framework-specific agents
|
|
3449
|
+
if (detectedFrameworks.has('react')) {
|
|
3450
|
+
agents.push({
|
|
3451
|
+
name: 'react-specialist',
|
|
3452
|
+
type: 'react-developer',
|
|
3453
|
+
description: 'React/Next.js development specialist',
|
|
3454
|
+
capabilities: ['hooks', 'state-management', 'components', 'ssr', 'testing'],
|
|
3455
|
+
focus: focus.priorities,
|
|
3456
|
+
systemPrompt: opts.includePrompts ? `You are a React specialist for this project.
|
|
3457
|
+
Focus on: functional components, hooks, state management, performance optimization.
|
|
3458
|
+
Prefer composition, use memo wisely, follow React best practices.
|
|
3459
|
+
${focus.description}` : null
|
|
3460
|
+
});
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
if (detectedFrameworks.has('database')) {
|
|
3464
|
+
agents.push({
|
|
3465
|
+
name: 'database-specialist',
|
|
3466
|
+
type: 'database-specialist',
|
|
3467
|
+
description: 'Database design and optimization specialist',
|
|
3468
|
+
capabilities: ['schema-design', 'queries', 'indexing', 'migrations', 'orm'],
|
|
3469
|
+
focus: focus.priorities,
|
|
3470
|
+
systemPrompt: opts.includePrompts ? `You are a database specialist for this project.
|
|
3471
|
+
Focus on: normalized schemas, efficient queries, proper indexing, data integrity.
|
|
3472
|
+
Consider performance implications, use transactions appropriately.
|
|
3473
|
+
${focus.description}` : null
|
|
3474
|
+
});
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
// Focus-specific agents
|
|
3478
|
+
if (opts.focus === 'testing' || opts.focus === 'quality') {
|
|
3479
|
+
agents.push({
|
|
3480
|
+
name: 'test-architect',
|
|
3481
|
+
type: 'test-engineer',
|
|
3482
|
+
description: 'Testing and quality assurance specialist',
|
|
3483
|
+
capabilities: ['unit-tests', 'integration-tests', 'mocking', 'coverage', 'tdd'],
|
|
3484
|
+
focus: ['testing', 'quality', 'reliability'],
|
|
3485
|
+
systemPrompt: opts.includePrompts ? `You are a testing specialist for this project.
|
|
3486
|
+
Focus on: comprehensive test coverage, meaningful assertions, test isolation.
|
|
3487
|
+
Write tests first when possible, mock external dependencies, aim for >80% coverage.
|
|
3488
|
+
${focus.description}` : null
|
|
3489
|
+
});
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3492
|
+
if (opts.focus === 'security') {
|
|
3493
|
+
agents.push({
|
|
3494
|
+
name: 'security-auditor',
|
|
3495
|
+
type: 'security-specialist',
|
|
3496
|
+
description: 'Security audit and hardening specialist',
|
|
3497
|
+
capabilities: ['vulnerability-scan', 'auth', 'encryption', 'input-validation', 'owasp'],
|
|
3498
|
+
focus: ['security', 'compliance', 'hardening'],
|
|
3499
|
+
systemPrompt: opts.includePrompts ? `You are a security specialist for this project.
|
|
3500
|
+
Focus on: OWASP top 10, input validation, authentication, authorization, encryption.
|
|
3501
|
+
Never trust user input, use parameterized queries, implement defense in depth.
|
|
3502
|
+
${focus.description}` : null
|
|
3503
|
+
});
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
// Add coordinator agent
|
|
3507
|
+
agents.push({
|
|
3508
|
+
name: 'project-coordinator',
|
|
3509
|
+
type: 'coordinator',
|
|
3510
|
+
description: 'Coordinates multi-agent workflows for this project',
|
|
3511
|
+
capabilities: ['task-decomposition', 'agent-routing', 'context-management'],
|
|
3512
|
+
focus: focus.priorities,
|
|
3513
|
+
routes: agents.filter(a => a.name !== 'project-coordinator').map(a => ({
|
|
3514
|
+
pattern: a.capabilities[0],
|
|
3515
|
+
agent: a.name
|
|
3516
|
+
}))
|
|
3517
|
+
});
|
|
3518
|
+
|
|
3519
|
+
// Create output directory
|
|
3520
|
+
if (!fs.existsSync(outputDir)) {
|
|
3521
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
// Generate agent files
|
|
3525
|
+
agents.forEach(agent => {
|
|
3526
|
+
let content;
|
|
3527
|
+
const filename = `${agent.name}.${opts.format}`;
|
|
3528
|
+
const filepath = path.join(outputDir, filename);
|
|
3529
|
+
|
|
3530
|
+
if (opts.format === 'yaml') {
|
|
3531
|
+
const yaml = [
|
|
3532
|
+
`# Auto-generated by RuVector Agent Builder`,
|
|
3533
|
+
`# Focus: ${opts.focus}`,
|
|
3534
|
+
`# Generated: ${new Date().toISOString()}`,
|
|
3535
|
+
``,
|
|
3536
|
+
`name: ${agent.name}`,
|
|
3537
|
+
`type: ${agent.type}`,
|
|
3538
|
+
`description: ${agent.description}`,
|
|
3539
|
+
``,
|
|
3540
|
+
`capabilities:`,
|
|
3541
|
+
...agent.capabilities.map(c => ` - ${c}`),
|
|
3542
|
+
``,
|
|
3543
|
+
`focus:`,
|
|
3544
|
+
...agent.focus.map(f => ` - ${f}`),
|
|
3545
|
+
];
|
|
3546
|
+
if (agent.systemPrompt) {
|
|
3547
|
+
yaml.push(``, `system_prompt: |`);
|
|
3548
|
+
agent.systemPrompt.split('\n').forEach(line => yaml.push(` ${line}`));
|
|
3549
|
+
}
|
|
3550
|
+
if (agent.routes) {
|
|
3551
|
+
yaml.push(``, `routes:`);
|
|
3552
|
+
agent.routes.forEach(r => yaml.push(` - pattern: "${r.pattern}"`, ` agent: ${r.agent}`));
|
|
3553
|
+
}
|
|
3554
|
+
content = yaml.join('\n');
|
|
3555
|
+
} else if (opts.format === 'json') {
|
|
3556
|
+
content = JSON.stringify(agent, null, 2);
|
|
3557
|
+
} else {
|
|
3558
|
+
// Markdown format
|
|
3559
|
+
content = [
|
|
3560
|
+
`# ${agent.name}`,
|
|
3561
|
+
``,
|
|
3562
|
+
`**Type:** ${agent.type}`,
|
|
3563
|
+
`**Description:** ${agent.description}`,
|
|
3564
|
+
``,
|
|
3565
|
+
`## Capabilities`,
|
|
3566
|
+
...agent.capabilities.map(c => `- ${c}`),
|
|
3567
|
+
``,
|
|
3568
|
+
`## Focus Areas`,
|
|
3569
|
+
...agent.focus.map(f => `- ${f}`),
|
|
3570
|
+
].join('\n');
|
|
3571
|
+
if (agent.systemPrompt) {
|
|
3572
|
+
content += `\n\n## System Prompt\n\n\`\`\`\n${agent.systemPrompt}\n\`\`\``;
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
fs.writeFileSync(filepath, content);
|
|
3577
|
+
console.log(chalk.green(` ✓ Created ${filename}`));
|
|
3578
|
+
});
|
|
3579
|
+
|
|
3580
|
+
// Create index file
|
|
3581
|
+
const indexContent = opts.format === 'yaml'
|
|
3582
|
+
? `# RuVector Agent Configuration\n# Focus: ${opts.focus}\n\nagents:\n${agents.map(a => ` - ${a.name}`).join('\n')}`
|
|
3583
|
+
: JSON.stringify({ focus: opts.focus, agents: agents.map(a => a.name) }, null, 2);
|
|
3584
|
+
|
|
3585
|
+
fs.writeFileSync(path.join(outputDir, `index.${opts.format === 'md' ? 'json' : opts.format}`), indexContent);
|
|
3586
|
+
|
|
3587
|
+
// Update settings to reference agents
|
|
3588
|
+
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
|
|
3589
|
+
if (fs.existsSync(settingsPath)) {
|
|
3590
|
+
try {
|
|
3591
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
3592
|
+
settings.agentConfig = {
|
|
3593
|
+
directory: opts.output,
|
|
3594
|
+
focus: opts.focus,
|
|
3595
|
+
agents: agents.map(a => a.name),
|
|
3596
|
+
generated: new Date().toISOString()
|
|
3597
|
+
};
|
|
3598
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
3599
|
+
console.log(chalk.blue('\n ✓ Updated .claude/settings.json with agent config'));
|
|
3600
|
+
} catch (e) { /* ignore settings errors */ }
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
console.log(chalk.bold.green(`\n✅ Generated ${agents.length} optimized agents in ${opts.output}/\n`));
|
|
3604
|
+
console.log(chalk.cyan('Agents created:'));
|
|
3605
|
+
agents.forEach(a => {
|
|
3606
|
+
console.log(` 🤖 ${chalk.bold(a.name)}: ${a.description}`);
|
|
3607
|
+
});
|
|
3608
|
+
console.log(chalk.dim(`\nFocus mode "${opts.focus}": ${focus.description}`));
|
|
3609
|
+
});
|
|
3610
|
+
|
|
2999
3611
|
program.parse();
|