@jigyasudham/veto 0.8.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +209 -52
- package/dist/agents/executor.js +36 -3
- package/dist/cli.js +246 -7
- package/dist/context/reader.js +113 -0
- package/dist/council/index.js +3 -1
- package/dist/plugins/loader.js +49 -0
- package/dist/router/index.js +2 -2
- package/dist/router/learning-updater.js +45 -1
- package/dist/server.js +478 -14
- package/dist/watcher/index.js +77 -0
- package/dist/workflow/pipeline.js +64 -0
- package/package.json +12 -3
- package/.claude/settings.local.json +0 -9
- package/src/adapters/claude.ts +0 -70
- package/src/adapters/codex.ts +0 -71
- package/src/adapters/gemini.ts +0 -71
- package/src/adapters/index.ts +0 -217
- package/src/agents/development/api.ts +0 -120
- package/src/agents/development/backend.ts +0 -85
- package/src/agents/development/coder.ts +0 -213
- package/src/agents/development/database.ts +0 -83
- package/src/agents/development/debugger.ts +0 -238
- package/src/agents/development/devops.ts +0 -86
- package/src/agents/development/frontend.ts +0 -85
- package/src/agents/development/migration.ts +0 -144
- package/src/agents/development/performance.ts +0 -144
- package/src/agents/development/refactor.ts +0 -86
- package/src/agents/development/reviewer.ts +0 -268
- package/src/agents/development/tester.ts +0 -151
- package/src/agents/executor.ts +0 -158
- package/src/agents/memory/context-manager.ts +0 -171
- package/src/agents/memory/decision-logger.ts +0 -160
- package/src/agents/memory/knowledge-base.ts +0 -124
- package/src/agents/memory/pattern-learner.ts +0 -143
- package/src/agents/memory/project-mapper.ts +0 -118
- package/src/agents/quality/accessibility.ts +0 -99
- package/src/agents/quality/code-quality.ts +0 -115
- package/src/agents/quality/compatibility.ts +0 -58
- package/src/agents/quality/documentation.ts +0 -105
- package/src/agents/quality/error-handling.ts +0 -96
- package/src/agents/research/competitor-analyzer.ts +0 -45
- package/src/agents/research/cost-analyzer.ts +0 -54
- package/src/agents/research/estimator.ts +0 -60
- package/src/agents/research/ethics-bias.ts +0 -113
- package/src/agents/research/researcher.ts +0 -114
- package/src/agents/research/risk-assessor.ts +0 -63
- package/src/agents/research/tech-advisor.ts +0 -55
- package/src/agents/security/auth.ts +0 -287
- package/src/agents/security/dependency-audit.ts +0 -337
- package/src/agents/security/penetration.ts +0 -262
- package/src/agents/security/privacy.ts +0 -285
- package/src/agents/security/scanner.ts +0 -322
- package/src/agents/security/secrets.ts +0 -249
- package/src/agents/types.ts +0 -66
- package/src/agents/workflow/automation.ts +0 -59
- package/src/agents/workflow/file-manager.ts +0 -52
- package/src/agents/workflow/git-agent.ts +0 -55
- package/src/agents/workflow/reporter.ts +0 -51
- package/src/agents/workflow/search-agent.ts +0 -40
- package/src/agents/workflow/task-coordinator.ts +0 -41
- package/src/agents/workflow/task-planner.ts +0 -47
- package/src/cli.ts +0 -204
- package/src/council/decision-engine.ts +0 -171
- package/src/council/devil-advocate.ts +0 -116
- package/src/council/index.ts +0 -44
- package/src/council/lead-developer.ts +0 -118
- package/src/council/legal-compliance.ts +0 -152
- package/src/council/product-manager.ts +0 -102
- package/src/council/security.ts +0 -172
- package/src/council/system-architect.ts +0 -132
- package/src/council/types.ts +0 -33
- package/src/council/ux-designer.ts +0 -121
- package/src/memory/local.ts +0 -305
- package/src/memory/schema.ts +0 -174
- package/src/memory/sync.ts +0 -274
- package/src/router/complexity-scorer.ts +0 -96
- package/src/router/context-compressor.ts +0 -74
- package/src/router/index.ts +0 -60
- package/src/router/learning-updater.ts +0 -271
- package/src/router/model-selector.ts +0 -83
- package/src/router/rate-monitor.ts +0 -103
- package/src/server.ts +0 -1038
- package/src/skills/development/skill-api-design.ts +0 -329
- package/src/skills/development/skill-auth.ts +0 -271
- package/src/skills/development/skill-ci-cd.ts +0 -0
- package/src/skills/development/skill-crud.ts +0 -209
- package/src/skills/development/skill-db-schema.ts +0 -0
- package/src/skills/development/skill-docker.ts +0 -0
- package/src/skills/development/skill-env-setup.ts +0 -0
- package/src/skills/development/skill-scaffold.ts +0 -323
- package/src/skills/intelligence/skill-complexity-score.ts +0 -69
- package/src/skills/intelligence/skill-cost-track.ts +0 -39
- package/src/skills/intelligence/skill-learning-loop.ts +0 -69
- package/src/skills/intelligence/skill-pattern-detect.ts +0 -38
- package/src/skills/intelligence/skill-rate-watch.ts +0 -61
- package/src/skills/memory/skill-context-compress.ts +0 -98
- package/src/skills/memory/skill-cross-sync.ts +0 -104
- package/src/skills/memory/skill-decision-log.ts +0 -119
- package/src/skills/memory/skill-session-restore.ts +0 -59
- package/src/skills/memory/skill-session-save.ts +0 -94
- package/src/skills/quality/skill-accessibility.ts +0 -0
- package/src/skills/quality/skill-code-review.ts +0 -84
- package/src/skills/quality/skill-docs-gen.ts +0 -0
- package/src/skills/quality/skill-perf-audit.ts +0 -0
- package/src/skills/quality/skill-security-scan.ts +0 -91
- package/src/skills/quality/skill-test-suite.ts +0 -290
- package/src/skills/workflow/skill-deploy.ts +0 -0
- package/src/skills/workflow/skill-git-workflow.ts +0 -0
- package/src/skills/workflow/skill-rollback.ts +0 -0
- package/src/skills/workflow/skill-task-breakdown.ts +0 -0
- package/tsconfig.json +0 -20
package/dist/cli.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Veto CLI — entry point for `npx veto init`
|
|
3
3
|
// Suppress Node experimental warnings (node:sqlite) for clean UX
|
|
4
4
|
process.removeAllListeners('warning');
|
|
5
|
-
import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
|
-
import { join, dirname } from 'node:path';
|
|
5
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
|
|
6
|
+
import { join, dirname, extname, resolve } from 'node:path';
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
|
-
const VERSION = '0.
|
|
8
|
+
const VERSION = '1.0.0';
|
|
9
9
|
const VETO_DIR = join(homedir(), '.veto');
|
|
10
10
|
const HOME = homedir();
|
|
11
11
|
const c = {
|
|
@@ -25,7 +25,7 @@ function printBanner() {
|
|
|
25
25
|
console.log(c.bold(c.cyan(' ╚████╔╝ ███████╗ ██║ ╚██████╔╝')));
|
|
26
26
|
console.log(c.bold(c.cyan(' ╚═══╝ ╚══════╝ ╚═╝ ╚═════╝')));
|
|
27
27
|
console.log('');
|
|
28
|
-
console.log(c.dim(` 50 agents.
|
|
28
|
+
console.log(c.dim(` 50 agents. 33 tools. 3 AIs. Self-learning. Zero extra cost.`));
|
|
29
29
|
console.log(c.dim(` v${VERSION}`));
|
|
30
30
|
console.log('');
|
|
31
31
|
}
|
|
@@ -127,7 +127,20 @@ async function initCommand() {
|
|
|
127
127
|
console.error(c.red(` Error initializing database: ${msg}`));
|
|
128
128
|
process.exit(1);
|
|
129
129
|
}
|
|
130
|
-
// 3. Auto-
|
|
130
|
+
// 3. Auto-scan current project and store project map
|
|
131
|
+
const cwd = resolve(process.cwd());
|
|
132
|
+
const { getDb: _getDb, updateProjectMap } = await import('./memory/local.js');
|
|
133
|
+
try {
|
|
134
|
+
process.stdout.write(' · Scanning project directory...');
|
|
135
|
+
const { structure, key_modules, tech_stack } = scanProjectDir(cwd);
|
|
136
|
+
updateProjectMap({ project_dir: cwd, structure: JSON.stringify(structure), key_modules, tech_stack });
|
|
137
|
+
const stackStr = tech_stack.length ? ` (${tech_stack.slice(0, 4).join(', ')})` : '';
|
|
138
|
+
console.log(c.green(' ✓') + ` Project map saved${stackStr}`);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
console.log(c.dim(' skipped'));
|
|
142
|
+
}
|
|
143
|
+
// 4. Auto-configure every AI CLI / IDE found on this machine
|
|
131
144
|
console.log('');
|
|
132
145
|
console.log(' Configuring all AI tools found on this machine...');
|
|
133
146
|
console.log('');
|
|
@@ -168,6 +181,203 @@ async function initCommand() {
|
|
|
168
181
|
console.log('');
|
|
169
182
|
}
|
|
170
183
|
}
|
|
184
|
+
// ─── Project Map Scanner ────────────────────────────────────────────────────────
|
|
185
|
+
function scanProjectDir(dir) {
|
|
186
|
+
const structure = {};
|
|
187
|
+
const key_modules = [];
|
|
188
|
+
const tech_stack = [];
|
|
189
|
+
// Read package.json for stack detection
|
|
190
|
+
const pkgPath = join(dir, 'package.json');
|
|
191
|
+
if (existsSync(pkgPath)) {
|
|
192
|
+
try {
|
|
193
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
194
|
+
structure['name'] = pkg.name;
|
|
195
|
+
structure['version'] = pkg.version;
|
|
196
|
+
const allDeps = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies });
|
|
197
|
+
structure['dep_count'] = allDeps.length;
|
|
198
|
+
const stackMap = [
|
|
199
|
+
[['next'], 'Next.js'], [['react'], 'React'], [['vue'], 'Vue'],
|
|
200
|
+
[['express'], 'Express'], [['fastify'], 'Fastify'], [['hono'], 'Hono'],
|
|
201
|
+
[['prisma'], 'Prisma'], [['drizzle-orm'], 'Drizzle'], [['typeorm'], 'TypeORM'],
|
|
202
|
+
[['@modelcontextprotocol/sdk'], 'MCP'], [['typescript'], 'TypeScript'],
|
|
203
|
+
[['jest'], 'Jest'], [['vitest'], 'Vitest'], [['tailwindcss'], 'Tailwind'],
|
|
204
|
+
[['zod'], 'Zod'], [['graphql'], 'GraphQL'],
|
|
205
|
+
];
|
|
206
|
+
for (const [keywords, label] of stackMap) {
|
|
207
|
+
if (keywords.some(k => allDeps.some(d => d.toLowerCase().includes(k)))) {
|
|
208
|
+
tech_stack.push(label);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch { /* malformed */ }
|
|
213
|
+
}
|
|
214
|
+
// Detect key config files
|
|
215
|
+
const CONFIG_FILES = ['tsconfig.json', 'vite.config.ts', 'vite.config.js', 'next.config.ts',
|
|
216
|
+
'next.config.js', 'tailwind.config.ts', 'drizzle.config.ts', 'prisma/schema.prisma',
|
|
217
|
+
'docker-compose.yml', '.env.example'];
|
|
218
|
+
const foundConfigs = CONFIG_FILES.filter(f => existsSync(join(dir, f)));
|
|
219
|
+
if (foundConfigs.length)
|
|
220
|
+
structure['config_files'] = foundConfigs;
|
|
221
|
+
// Scan src/ directory
|
|
222
|
+
const srcDir = join(dir, 'src');
|
|
223
|
+
if (existsSync(srcDir)) {
|
|
224
|
+
let tsCount = 0;
|
|
225
|
+
let testCount = 0;
|
|
226
|
+
const topDirs = [];
|
|
227
|
+
for (const entry of readdirSync(srcDir)) {
|
|
228
|
+
const full = join(srcDir, entry);
|
|
229
|
+
try {
|
|
230
|
+
if (statSync(full).isDirectory()) {
|
|
231
|
+
topDirs.push(entry);
|
|
232
|
+
key_modules.push(`src/${entry}`);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
const ext = extname(entry);
|
|
236
|
+
if (['.ts', '.tsx', '.js', '.jsx'].includes(ext))
|
|
237
|
+
tsCount++;
|
|
238
|
+
if (entry.includes('.test.') || entry.includes('.spec.'))
|
|
239
|
+
testCount++;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch { /* skip */ }
|
|
243
|
+
}
|
|
244
|
+
structure['src_dirs'] = topDirs;
|
|
245
|
+
structure['ts_files_in_src'] = tsCount;
|
|
246
|
+
if (testCount > 0)
|
|
247
|
+
structure['test_files'] = testCount;
|
|
248
|
+
}
|
|
249
|
+
// Entry points
|
|
250
|
+
const entryPoints = ['src/index.ts', 'src/main.ts', 'src/app.ts', 'src/server.ts', 'src/cli.ts', 'index.ts'];
|
|
251
|
+
const found = entryPoints.filter(f => existsSync(join(dir, f)));
|
|
252
|
+
if (found.length)
|
|
253
|
+
structure['entry_points'] = found;
|
|
254
|
+
return { structure, key_modules, tech_stack };
|
|
255
|
+
}
|
|
256
|
+
// ─── CLI Subcommands ────────────────────────────────────────────────────────────
|
|
257
|
+
async function statusCommand() {
|
|
258
|
+
const { getDbPath } = await import('./memory/local.js');
|
|
259
|
+
const { getDb } = await import('./memory/local.js');
|
|
260
|
+
const db = getDb();
|
|
261
|
+
const sessionCount = db.prepare('SELECT COUNT(*) as c FROM sessions').get().c;
|
|
262
|
+
const memoryCount = db.prepare('SELECT COUNT(*) as c FROM knowledge_base').get().c;
|
|
263
|
+
const patternCount = db.prepare('SELECT COUNT(*) as c FROM patterns').get().c;
|
|
264
|
+
const outcomeCount = db.prepare('SELECT COUNT(*) as c FROM learning_data').get().c;
|
|
265
|
+
console.log('');
|
|
266
|
+
console.log(c.bold(' Veto Status'));
|
|
267
|
+
console.log(c.dim(' ─────────────────────────────'));
|
|
268
|
+
console.log(` Version ${c.cyan(VERSION)}`);
|
|
269
|
+
console.log(` DB ${c.dim(getDbPath())}`);
|
|
270
|
+
console.log(` Sessions ${c.cyan(String(sessionCount))}`);
|
|
271
|
+
console.log(` Memory ${c.cyan(String(memoryCount))} knowledge entries`);
|
|
272
|
+
console.log(` Patterns ${c.cyan(String(patternCount))}`);
|
|
273
|
+
console.log(` Outcomes ${c.cyan(String(outcomeCount))} recorded`);
|
|
274
|
+
console.log('');
|
|
275
|
+
}
|
|
276
|
+
async function sessionsCommand() {
|
|
277
|
+
const { listSessions } = await import('./memory/local.js');
|
|
278
|
+
const sessions = listSessions(20);
|
|
279
|
+
console.log('');
|
|
280
|
+
console.log(c.bold(' Saved Sessions') + c.dim(` (${sessions.length})`));
|
|
281
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────────────'));
|
|
282
|
+
if (sessions.length === 0) {
|
|
283
|
+
console.log(c.dim(' No sessions saved yet. Use veto_session_save inside an AI session.'));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
for (const s of sessions) {
|
|
287
|
+
const date = new Date(s.started_at).toLocaleString();
|
|
288
|
+
console.log(` ${c.cyan(s.id.slice(0, 8))} ${c.dim(date)} ${c.bold(s.platform ?? 'claude')} ${s.summary?.slice(0, 60) ?? ''}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
console.log('');
|
|
292
|
+
}
|
|
293
|
+
async function memoryCommand() {
|
|
294
|
+
const args = process.argv.slice(3);
|
|
295
|
+
const query = args.join(' ') || undefined;
|
|
296
|
+
const { searchKnowledge } = await import('./memory/local.js');
|
|
297
|
+
const results = searchKnowledge({ query, limit: 20 });
|
|
298
|
+
console.log('');
|
|
299
|
+
console.log(c.bold(' Knowledge Base') + (query ? c.dim(` — "${query}"`) : '') + c.dim(` (${results.length} results)`));
|
|
300
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────────────'));
|
|
301
|
+
if (results.length === 0) {
|
|
302
|
+
console.log(c.dim(' No entries found.'));
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
for (const r of results) {
|
|
306
|
+
const tags = r.tags ? JSON.parse(r.tags).join(', ') : '';
|
|
307
|
+
console.log(` ${c.cyan(`[${r.type}]`)} ${c.bold(r.title)}`);
|
|
308
|
+
if (tags)
|
|
309
|
+
console.log(` ${c.dim('tags: ' + tags)}`);
|
|
310
|
+
console.log(` ${c.dim(r.content.slice(0, 100).replace(/\n/g, ' ') + (r.content.length > 100 ? '...' : ''))}`);
|
|
311
|
+
console.log('');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function patternsCommand() {
|
|
316
|
+
const { getPatterns } = await import('./memory/local.js');
|
|
317
|
+
const prefix = process.argv[3];
|
|
318
|
+
const patterns = getPatterns(prefix, 30);
|
|
319
|
+
console.log('');
|
|
320
|
+
console.log(c.bold(' Learned Patterns') + c.dim(` (${patterns.length})`));
|
|
321
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────────────'));
|
|
322
|
+
if (patterns.length === 0) {
|
|
323
|
+
console.log(c.dim(' No patterns yet. Record outcomes with veto_record_outcome to build up patterns.'));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
for (const p of patterns) {
|
|
327
|
+
const conf = Math.round(p.confidence * 100);
|
|
328
|
+
const confColor = conf >= 80 ? c.green : conf >= 60 ? c.yellow : c.dim;
|
|
329
|
+
console.log(` ${confColor(`${conf}%`)} ${c.cyan(p.pattern_key)} ${c.dim('→')} ${p.pattern_val} ${c.dim(`(seen ${p.seen_count}x)`)}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
console.log('');
|
|
333
|
+
}
|
|
334
|
+
function helpCommand() {
|
|
335
|
+
console.log('');
|
|
336
|
+
console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(' — 50 agents. 34 tools. 3 AIs. Self-learning. Zero extra cost.'));
|
|
337
|
+
console.log('');
|
|
338
|
+
console.log(c.bold(' CLI Commands'));
|
|
339
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
340
|
+
console.log(` ${c.cyan('veto init')} Configure all AI tools + scan project`);
|
|
341
|
+
console.log(` ${c.cyan('veto status')} Version, DB path, memory/session counts`);
|
|
342
|
+
console.log(` ${c.cyan('veto sessions')} List last 20 saved sessions`);
|
|
343
|
+
console.log(` ${c.cyan('veto memory')} ${c.dim('[query]')} Search knowledge base`);
|
|
344
|
+
console.log(` ${c.cyan('veto patterns')} ${c.dim('[prefix]')} List learned agent/routing patterns`);
|
|
345
|
+
console.log(` ${c.cyan('veto help')} Show this help`);
|
|
346
|
+
console.log('');
|
|
347
|
+
console.log(c.bold(' MCP Tools (34)'));
|
|
348
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
349
|
+
console.log(` ${c.dim('Session')} veto_status · veto_session_save · veto_session_restore · veto_sessions_list`);
|
|
350
|
+
console.log(` ${c.dim('Router')} veto_route_task · veto_rate_status`);
|
|
351
|
+
console.log(` ${c.dim('Council')} veto_council_debate`);
|
|
352
|
+
console.log(` ${c.dim('Agents')} veto_agent_plan · veto_execute_parallel · veto_explain`);
|
|
353
|
+
console.log(` ${c.dim('Review')} veto_code_review · veto_security_scan · veto_secrets_scan · veto_diff_review`);
|
|
354
|
+
console.log(` ${c.dim('Pipeline')} veto_workflow`);
|
|
355
|
+
console.log(` ${c.dim('Watch')} veto_watch · veto_watch_poll · veto_watch_stop`);
|
|
356
|
+
console.log(` ${c.dim('Memory')} veto_memory_store · veto_memory_search · veto_memory_delete`);
|
|
357
|
+
console.log(` veto_project_map_update · veto_project_map_get`);
|
|
358
|
+
console.log(` veto_pattern_store · veto_patterns_list`);
|
|
359
|
+
console.log(` veto_memory_export · veto_memory_import`);
|
|
360
|
+
console.log(` ${c.dim('Learning')} veto_record_outcome · veto_learning_stats · veto_learning_apply`);
|
|
361
|
+
console.log(` ${c.dim('Handoff')} veto_handoff · veto_continue · veto_platform_setup`);
|
|
362
|
+
console.log(` ${c.dim('Plugins')} veto_plugins`);
|
|
363
|
+
console.log('');
|
|
364
|
+
console.log(c.bold(' MCP Resources'));
|
|
365
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
366
|
+
console.log(` ${c.cyan('veto://sessions')} All saved sessions`);
|
|
367
|
+
console.log(` ${c.cyan('veto://project-map?dir=<path>')} Project structure map`);
|
|
368
|
+
console.log(` ${c.cyan('veto://memory?q=<query>')} Knowledge base search`);
|
|
369
|
+
console.log(` ${c.cyan('veto://patterns')} Learned patterns`);
|
|
370
|
+
console.log('');
|
|
371
|
+
console.log(c.bold(' MCP Prompts'));
|
|
372
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
373
|
+
console.log(` ${c.cyan('code-review')} · ${c.cyan('security-audit')} · ${c.cyan('deploy-checklist')} · ${c.cyan('explain-file')}`);
|
|
374
|
+
console.log('');
|
|
375
|
+
console.log(c.bold(' Docs'));
|
|
376
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
377
|
+
console.log(` ${c.dim('GitHub:')} https://github.com/jigyasudham/veto`);
|
|
378
|
+
console.log(` ${c.dim('npm:')} https://www.npmjs.com/package/@jigyasudham/veto`);
|
|
379
|
+
console.log('');
|
|
380
|
+
}
|
|
171
381
|
// ─── Router ────────────────────────────────────────────────────────────────────
|
|
172
382
|
const command = process.argv[2] ?? 'init';
|
|
173
383
|
switch (command) {
|
|
@@ -177,9 +387,38 @@ switch (command) {
|
|
|
177
387
|
process.exit(1);
|
|
178
388
|
});
|
|
179
389
|
break;
|
|
390
|
+
case 'status':
|
|
391
|
+
statusCommand().catch((err) => {
|
|
392
|
+
console.error(c.red(`Error: ${err.message}`));
|
|
393
|
+
process.exit(1);
|
|
394
|
+
});
|
|
395
|
+
break;
|
|
396
|
+
case 'sessions':
|
|
397
|
+
sessionsCommand().catch((err) => {
|
|
398
|
+
console.error(c.red(`Error: ${err.message}`));
|
|
399
|
+
process.exit(1);
|
|
400
|
+
});
|
|
401
|
+
break;
|
|
402
|
+
case 'memory':
|
|
403
|
+
memoryCommand().catch((err) => {
|
|
404
|
+
console.error(c.red(`Error: ${err.message}`));
|
|
405
|
+
process.exit(1);
|
|
406
|
+
});
|
|
407
|
+
break;
|
|
408
|
+
case 'patterns':
|
|
409
|
+
patternsCommand().catch((err) => {
|
|
410
|
+
console.error(c.red(`Error: ${err.message}`));
|
|
411
|
+
process.exit(1);
|
|
412
|
+
});
|
|
413
|
+
break;
|
|
414
|
+
case 'help':
|
|
415
|
+
case '--help':
|
|
416
|
+
case '-h':
|
|
417
|
+
helpCommand();
|
|
418
|
+
break;
|
|
180
419
|
default:
|
|
181
|
-
console.error(`Unknown command: ${command}`);
|
|
182
|
-
|
|
420
|
+
console.error(c.red(` Unknown command: ${command}`));
|
|
421
|
+
helpCommand();
|
|
183
422
|
process.exit(1);
|
|
184
423
|
}
|
|
185
424
|
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
const STACK_INDICATORS = [
|
|
5
|
+
[['next', 'next.js'], 'Next.js'],
|
|
6
|
+
[['react', 'react-dom'], 'React'],
|
|
7
|
+
[['vue'], 'Vue'],
|
|
8
|
+
[['svelte'], 'Svelte'],
|
|
9
|
+
[['express'], 'Express'],
|
|
10
|
+
[['fastify'], 'Fastify'],
|
|
11
|
+
[['hono'], 'Hono'],
|
|
12
|
+
[['prisma'], 'Prisma'],
|
|
13
|
+
[['drizzle-orm'], 'Drizzle'],
|
|
14
|
+
[['typeorm'], 'TypeORM'],
|
|
15
|
+
[['mongoose'], 'Mongoose'],
|
|
16
|
+
[['@modelcontextprotocol/sdk'], 'MCP'],
|
|
17
|
+
[['typescript', 'ts-node', 'tsx'], 'TypeScript'],
|
|
18
|
+
[['jest', 'vitest'], 'Testing'],
|
|
19
|
+
[['tailwindcss'], 'Tailwind'],
|
|
20
|
+
[['zod'], 'Zod'],
|
|
21
|
+
[['trpc', '@trpc/server'], 'tRPC'],
|
|
22
|
+
[['graphql'], 'GraphQL'],
|
|
23
|
+
];
|
|
24
|
+
function detectStack(deps) {
|
|
25
|
+
const names = Object.keys(deps).map(k => k.toLowerCase());
|
|
26
|
+
const stack = [];
|
|
27
|
+
for (const [keywords, label] of STACK_INDICATORS) {
|
|
28
|
+
if (keywords.some(k => names.some(n => n.includes(k)))) {
|
|
29
|
+
stack.push(label);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return stack;
|
|
33
|
+
}
|
|
34
|
+
function safeRead(filePath) {
|
|
35
|
+
try {
|
|
36
|
+
return readFileSync(filePath, 'utf8');
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function safeExec(cmd, cwd) {
|
|
43
|
+
try {
|
|
44
|
+
return execSync(cmd, { cwd, timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function readProjectContext(projectDir) {
|
|
51
|
+
const dir = resolve(projectDir);
|
|
52
|
+
if (!existsSync(dir)) {
|
|
53
|
+
return { summary: '', tech_stack: [], git_diff: '', key_files: [], error: `Directory not found: ${dir}` };
|
|
54
|
+
}
|
|
55
|
+
// package.json
|
|
56
|
+
let packageName;
|
|
57
|
+
let packageVersion;
|
|
58
|
+
let techStack = [];
|
|
59
|
+
const pkgRaw = safeRead(join(dir, 'package.json'));
|
|
60
|
+
if (pkgRaw) {
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(pkgRaw);
|
|
63
|
+
packageName = pkg.name;
|
|
64
|
+
packageVersion = pkg.version;
|
|
65
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
66
|
+
techStack = detectStack(allDeps);
|
|
67
|
+
}
|
|
68
|
+
catch { /* malformed package.json */ }
|
|
69
|
+
}
|
|
70
|
+
// git diff — last 60 lines of unstaged + staged changes
|
|
71
|
+
const gitDiff = safeExec('git diff HEAD --stat --no-color', dir);
|
|
72
|
+
// git recent commits (last 5 one-liners for context)
|
|
73
|
+
const gitLog = safeExec('git log --oneline -5 --no-color', dir);
|
|
74
|
+
// key config files present
|
|
75
|
+
const CONFIG_FILES = [
|
|
76
|
+
'tsconfig.json', 'vite.config.ts', 'vite.config.js',
|
|
77
|
+
'next.config.ts', 'next.config.js', 'tailwind.config.ts',
|
|
78
|
+
'drizzle.config.ts', 'prisma/schema.prisma', '.env.example',
|
|
79
|
+
];
|
|
80
|
+
const keyFiles = CONFIG_FILES.filter(f => existsSync(join(dir, f)));
|
|
81
|
+
// build compact summary string
|
|
82
|
+
const lines = ['[CODEBASE CONTEXT]'];
|
|
83
|
+
if (packageName)
|
|
84
|
+
lines.push(`Project: ${packageName}${packageVersion ? ` v${packageVersion}` : ''}`);
|
|
85
|
+
if (techStack.length)
|
|
86
|
+
lines.push(`Stack: ${techStack.join(', ')}`);
|
|
87
|
+
if (keyFiles.length)
|
|
88
|
+
lines.push(`Config files: ${keyFiles.join(', ')}`);
|
|
89
|
+
if (gitDiff)
|
|
90
|
+
lines.push(`Recent changes:\n${gitDiff}`);
|
|
91
|
+
if (gitLog)
|
|
92
|
+
lines.push(`Recent commits:\n${gitLog}`);
|
|
93
|
+
return {
|
|
94
|
+
summary: lines.join('\n'),
|
|
95
|
+
package_name: packageName,
|
|
96
|
+
package_version: packageVersion,
|
|
97
|
+
tech_stack: techStack,
|
|
98
|
+
git_diff: gitDiff,
|
|
99
|
+
key_files: keyFiles,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function buildContextString(projectDir, existingContext) {
|
|
103
|
+
if (!projectDir)
|
|
104
|
+
return existingContext ?? '';
|
|
105
|
+
const ctx = readProjectContext(projectDir);
|
|
106
|
+
if (ctx.error)
|
|
107
|
+
return existingContext ?? '';
|
|
108
|
+
const parts = [ctx.summary];
|
|
109
|
+
if (existingContext)
|
|
110
|
+
parts.push(existingContext);
|
|
111
|
+
return parts.join('\n\n');
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=reader.js.map
|
package/dist/council/index.js
CHANGED
|
@@ -7,8 +7,10 @@ import { analyze as devilAnalyze } from './devil-advocate.js';
|
|
|
7
7
|
import { analyze as legalAnalyze } from './legal-compliance.js';
|
|
8
8
|
import { analyze as securityAnalyze } from './security.js';
|
|
9
9
|
import { decide, formatDebate } from './decision-engine.js';
|
|
10
|
+
import { buildContextString } from '../context/reader.js';
|
|
10
11
|
export async function runDebate(input) {
|
|
11
|
-
const
|
|
12
|
+
const enrichedContext = buildContextString(input.project_dir, input.context);
|
|
13
|
+
const fullText = enrichedContext ? `${input.task}\n\n${enrichedContext}` : input.task;
|
|
12
14
|
// All 7 agents run in parallel — none depend on each other
|
|
13
15
|
const [lead_dev, pm, architect, ux, devil, legal, security] = await Promise.all([
|
|
14
16
|
Promise.resolve(leadDevAnalyze(fullText)),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { readdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join, basename, extname } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
const PLUGIN_DIR = join(homedir(), '.veto', 'agents');
|
|
5
|
+
const registry = new Map();
|
|
6
|
+
let loaded = false;
|
|
7
|
+
function pluginName(file) {
|
|
8
|
+
return basename(file, extname(file));
|
|
9
|
+
}
|
|
10
|
+
export async function loadPlugins() {
|
|
11
|
+
if (loaded)
|
|
12
|
+
return Array.from(registry.keys());
|
|
13
|
+
loaded = true;
|
|
14
|
+
if (!existsSync(PLUGIN_DIR))
|
|
15
|
+
return [];
|
|
16
|
+
const files = readdirSync(PLUGIN_DIR).filter(f => /\.(js|mjs)$/.test(f));
|
|
17
|
+
const names = [];
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
const name = pluginName(file);
|
|
20
|
+
try {
|
|
21
|
+
const mod = await import(join(PLUGIN_DIR, file));
|
|
22
|
+
if (mod && typeof mod === 'object' &&
|
|
23
|
+
'plan' in mod && typeof mod.plan === 'function') {
|
|
24
|
+
registry.set(name, mod);
|
|
25
|
+
names.push(name);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
process.stderr.write(`[veto] Plugin "${file}" skipped — must export plan(task, context?)\n`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
process.stderr.write(`[veto] Plugin "${file}" failed to load: ${err}\n`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return names;
|
|
36
|
+
}
|
|
37
|
+
export function getPlugin(name) {
|
|
38
|
+
return registry.get(name);
|
|
39
|
+
}
|
|
40
|
+
export function isPlugin(name) {
|
|
41
|
+
return registry.has(name);
|
|
42
|
+
}
|
|
43
|
+
export function listPlugins() {
|
|
44
|
+
return Array.from(registry.entries()).map(([name, mod]) => ({
|
|
45
|
+
name,
|
|
46
|
+
has_analyze: typeof mod.analyze === 'function',
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=loader.js.map
|
package/dist/router/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { scoreComplexity } from './complexity-scorer.js';
|
|
|
3
3
|
import { selectModel } from './model-selector.js';
|
|
4
4
|
import { getRateStatus, trackRequest, getRoutingAdvice } from './rate-monitor.js';
|
|
5
5
|
import { compressContext, estimateTokens } from './context-compressor.js';
|
|
6
|
-
import { recordOutcome, getLearningStats, getLearnedThresholds, applyLearnedThresholds, getAgentPerformanceStats, getTaskTypeBreakdown, getCouncilInsights } from './learning-updater.js';
|
|
7
|
-
export { estimateTokens, getRateStatus, trackRequest, recordOutcome, getLearningStats, getLearnedThresholds, applyLearnedThresholds, getAgentPerformanceStats, getTaskTypeBreakdown, getCouncilInsights };
|
|
6
|
+
import { recordOutcome, getLearningStats, getLearnedThresholds, applyLearnedThresholds, getAgentPerformanceStats, getTaskTypeBreakdown, getCouncilInsights, getRecommendedAgent } from './learning-updater.js';
|
|
7
|
+
export { estimateTokens, getRateStatus, trackRequest, recordOutcome, getLearningStats, getLearnedThresholds, applyLearnedThresholds, getAgentPerformanceStats, getTaskTypeBreakdown, getCouncilInsights, getRecommendedAgent };
|
|
8
8
|
export function routeTask(task, options = {}) {
|
|
9
9
|
const learned = getLearnedThresholds();
|
|
10
10
|
const complexity = scoreComplexity(task, options.filesAffected, options.forceCouncil, learned.source === 'learned' ? learned : undefined);
|
|
@@ -2,10 +2,54 @@
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { getDb } from '../memory/local.js';
|
|
4
4
|
// ─── Record ───────────────────────────────────────────────────────────────────
|
|
5
|
-
export function recordOutcome(taskType, complexity, modelTier, agent, outputQuality, tokensUsed = 0) {
|
|
5
|
+
export function recordOutcome(taskType, complexity, modelTier, agent, outputQuality, tokensUsed = 0, fileExt) {
|
|
6
6
|
const db = getDb();
|
|
7
7
|
db.prepare(`INSERT INTO learning_data (id, task_type, complexity, model_tier, output_quality, tokens_used, agent)
|
|
8
8
|
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(randomUUID(), taskType, complexity, modelTier, outputQuality, tokensUsed, agent);
|
|
9
|
+
// Predictive routing: track agent quality per file extension and task type keyword
|
|
10
|
+
if (agent && agent !== 'dynamic' && outputQuality > 0) {
|
|
11
|
+
const now = new Date().toISOString();
|
|
12
|
+
const upsert = (key) => {
|
|
13
|
+
const existing = db.prepare('SELECT id, pattern_val, confidence, seen_count FROM patterns WHERE pattern_key = ?').get(key);
|
|
14
|
+
if (existing) {
|
|
15
|
+
// running average quality as confidence (0–1)
|
|
16
|
+
const newConf = ((existing.confidence * existing.seen_count) + (outputQuality / 100)) / (existing.seen_count + 1);
|
|
17
|
+
db.prepare('UPDATE patterns SET confidence = ?, seen_count = ?, updated_at = ? WHERE pattern_key = ?')
|
|
18
|
+
.run(Math.min(1, newConf), existing.seen_count + 1, now, key);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
db.prepare('INSERT INTO patterns (id, pattern_key, pattern_val, confidence, seen_count, updated_at) VALUES (?, ?, ?, ?, ?, ?)')
|
|
22
|
+
.run(randomUUID(), key, agent, outputQuality / 100, 1, now);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
if (fileExt)
|
|
26
|
+
upsert(`file_agent:${fileExt.toLowerCase()}:${agent}`);
|
|
27
|
+
const keyword = taskType.toLowerCase().split(/[\s_-]/)[0];
|
|
28
|
+
if (keyword)
|
|
29
|
+
upsert(`task_agent:${keyword}:${agent}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// ─── Predictive Agent Recommendation ─────────────────────────────────────────
|
|
33
|
+
export function getRecommendedAgent(taskType, fileExt) {
|
|
34
|
+
const db = getDb();
|
|
35
|
+
// Try file extension match first (more specific)
|
|
36
|
+
if (fileExt) {
|
|
37
|
+
const rows = db.prepare(`SELECT pattern_key, pattern_val, confidence, seen_count FROM patterns
|
|
38
|
+
WHERE pattern_key LIKE ? AND seen_count >= 3
|
|
39
|
+
ORDER BY confidence DESC LIMIT 1`).all(`file_agent:${fileExt.toLowerCase()}:%`);
|
|
40
|
+
if (rows.length > 0 && rows[0].confidence >= 0.7)
|
|
41
|
+
return rows[0].pattern_val;
|
|
42
|
+
}
|
|
43
|
+
// Fall back to task keyword match
|
|
44
|
+
const keyword = taskType.toLowerCase().split(/[\s_-]/)[0];
|
|
45
|
+
if (keyword) {
|
|
46
|
+
const rows = db.prepare(`SELECT pattern_key, pattern_val, confidence, seen_count FROM patterns
|
|
47
|
+
WHERE pattern_key LIKE ? AND seen_count >= 3
|
|
48
|
+
ORDER BY confidence DESC LIMIT 1`).all(`task_agent:${keyword}:%`);
|
|
49
|
+
if (rows.length > 0 && rows[0].confidence >= 0.7)
|
|
50
|
+
return rows[0].pattern_val;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
9
53
|
}
|
|
10
54
|
// ─── Stats ────────────────────────────────────────────────────────────────────
|
|
11
55
|
export function getLearningStats() {
|