@jigyasudham/veto 1.4.4 → 2.0.1
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/AGENTS.md +134 -0
- package/README.md +28 -146
- package/dist/adapters/index.d.ts +3 -2
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +128 -5
- package/dist/adapters/index.js.map +1 -1
- package/dist/agents/executor.d.ts +2 -0
- package/dist/agents/executor.d.ts.map +1 -1
- package/dist/agents/executor.js +50 -3
- package/dist/agents/executor.js.map +1 -1
- package/dist/agents/llm-runner.d.ts +11 -0
- package/dist/agents/llm-runner.d.ts.map +1 -0
- package/dist/agents/llm-runner.js +252 -0
- package/dist/agents/llm-runner.js.map +1 -0
- package/dist/agents/local-llm.d.ts +14 -0
- package/dist/agents/local-llm.d.ts.map +1 -0
- package/dist/agents/local-llm.js +51 -0
- package/dist/agents/local-llm.js.map +1 -0
- package/dist/agents/manifest.d.ts +13 -0
- package/dist/agents/manifest.d.ts.map +1 -0
- package/dist/agents/manifest.js +55 -0
- package/dist/agents/manifest.js.map +1 -0
- package/dist/agents/quality/clone-detector.d.ts +16 -0
- package/dist/agents/quality/clone-detector.d.ts.map +1 -0
- package/dist/agents/quality/clone-detector.js +72 -0
- package/dist/agents/quality/clone-detector.js.map +1 -0
- package/dist/agents/research/cost-analyzer.js +1 -1
- package/dist/agents/research/cost-analyzer.js.map +1 -1
- package/dist/agents/types.d.ts +15 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/validate.d.ts +11 -0
- package/dist/agents/validate.d.ts.map +1 -0
- package/dist/agents/validate.js +54 -0
- package/dist/agents/validate.js.map +1 -0
- package/dist/cli.js +339 -22
- package/dist/cli.js.map +1 -1
- package/dist/council/llm-council.d.ts.map +1 -1
- package/dist/council/llm-council.js +10 -9
- package/dist/council/llm-council.js.map +1 -1
- package/dist/council/types.d.ts +2 -0
- package/dist/council/types.d.ts.map +1 -1
- package/dist/memory/config.d.ts +1 -0
- package/dist/memory/config.d.ts.map +1 -1
- package/dist/memory/config.js +2 -0
- package/dist/memory/config.js.map +1 -1
- package/dist/memory/local.d.ts +12 -1
- package/dist/memory/local.d.ts.map +1 -1
- package/dist/memory/local.js +56 -2
- package/dist/memory/local.js.map +1 -1
- package/dist/memory/schema.d.ts +28 -43
- package/dist/memory/schema.d.ts.map +1 -1
- package/dist/memory/schema.js +31 -0
- package/dist/memory/schema.js.map +1 -1
- package/dist/memory/sync.d.ts +13 -0
- package/dist/memory/sync.d.ts.map +1 -1
- package/dist/memory/sync.js +113 -0
- package/dist/memory/sync.js.map +1 -1
- package/dist/repo-map/ignore.d.ts +8 -0
- package/dist/repo-map/ignore.d.ts.map +1 -0
- package/dist/repo-map/ignore.js +65 -0
- package/dist/repo-map/ignore.js.map +1 -0
- package/dist/repo-map/index.d.ts +29 -0
- package/dist/repo-map/index.d.ts.map +1 -0
- package/dist/repo-map/index.js +240 -0
- package/dist/repo-map/index.js.map +1 -0
- package/dist/router/context-compressor.d.ts +1 -1
- package/dist/router/context-compressor.d.ts.map +1 -1
- package/dist/router/context-compressor.js +9 -3
- package/dist/router/context-compressor.js.map +1 -1
- package/dist/router/index.d.ts +8 -3
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +20 -4
- package/dist/router/index.js.map +1 -1
- package/dist/router/learning-updater.d.ts +41 -0
- package/dist/router/learning-updater.d.ts.map +1 -1
- package/dist/router/learning-updater.js +62 -0
- package/dist/router/learning-updater.js.map +1 -1
- package/dist/router/model-selector.d.ts +4 -1
- package/dist/router/model-selector.d.ts.map +1 -1
- package/dist/router/model-selector.js +24 -28
- package/dist/router/model-selector.js.map +1 -1
- package/dist/router/rate-monitor.d.ts +2 -1
- package/dist/router/rate-monitor.d.ts.map +1 -1
- package/dist/router/rate-monitor.js +3 -0
- package/dist/router/rate-monitor.js.map +1 -1
- package/dist/server.js +3124 -1655
- package/dist/server.js.map +1 -1
- package/dist/tools/definitions.d.ts +1205 -171
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +678 -4
- package/dist/tools/definitions.js.map +1 -1
- package/dist/watcher/index.d.ts +1 -0
- package/dist/watcher/index.d.ts.map +1 -1
- package/dist/watcher/index.js +7 -6
- package/dist/watcher/index.js.map +1 -1
- package/dist/workflow/pipeline.d.ts +12 -2
- package/dist/workflow/pipeline.d.ts.map +1 -1
- package/dist/workflow/pipeline.js +395 -16
- package/dist/workflow/pipeline.js.map +1 -1
- package/package.json +9 -4
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import { homedir } from 'node:os';
|
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
const { version: VERSION } = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
|
|
12
|
-
const TAGLINE = '50 agents.
|
|
12
|
+
const TAGLINE = '50 agents. 62 tools. 4 AIs. Self-learning. Zero extra cost.';
|
|
13
13
|
const VETO_DIR = join(homedir(), '.veto');
|
|
14
14
|
const HOME = homedir();
|
|
15
15
|
const c = {
|
|
@@ -104,6 +104,12 @@ const PLATFORMS = [
|
|
|
104
104
|
format: 'mcpServers',
|
|
105
105
|
detectionDir: join(HOME, '.gemini'),
|
|
106
106
|
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Antigravity CLI',
|
|
109
|
+
path: join(HOME, '.gemini', 'antigravity-cli', 'mcp_config.json'),
|
|
110
|
+
format: 'mcpServers',
|
|
111
|
+
detectionDir: join(HOME, '.gemini', 'antigravity-cli'),
|
|
112
|
+
},
|
|
107
113
|
{
|
|
108
114
|
name: 'Cursor',
|
|
109
115
|
path: join(HOME, '.cursor', 'mcp.json'),
|
|
@@ -162,8 +168,21 @@ async function initCommand() {
|
|
|
162
168
|
console.error(c.red(` Error initializing database: ${msg}`));
|
|
163
169
|
process.exit(1);
|
|
164
170
|
}
|
|
165
|
-
// 3. Auto-
|
|
171
|
+
// 3. Auto-import VETO_MEMORY.md if present in cwd
|
|
166
172
|
const cwd = resolve(process.cwd());
|
|
173
|
+
const vetoMemoryPath = join(cwd, 'VETO_MEMORY.md');
|
|
174
|
+
if (existsSync(vetoMemoryPath)) {
|
|
175
|
+
process.stdout.write(' · Importing VETO_MEMORY.md...');
|
|
176
|
+
try {
|
|
177
|
+
const { importMemoryMarkdown } = await import('./memory/sync.js');
|
|
178
|
+
const importResult = importMemoryMarkdown(vetoMemoryPath);
|
|
179
|
+
console.log(c.green(' ✓') + ` ${importResult.imported} knowledge entries imported`);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
console.log(c.dim(' skipped'));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// 4. Auto-scan current project and store project map
|
|
167
186
|
const { updateProjectMap } = await import('./memory/local.js');
|
|
168
187
|
const { discoverProject } = await import('./discover.js');
|
|
169
188
|
try {
|
|
@@ -282,6 +301,171 @@ async function initCommand() {
|
|
|
282
301
|
}
|
|
283
302
|
}
|
|
284
303
|
console.log('');
|
|
304
|
+
// 5. Write platform-specific context guidance files
|
|
305
|
+
// These are read at session start by each AI client — zero tool calls needed.
|
|
306
|
+
console.log(' Writing context guidance files...');
|
|
307
|
+
console.log('');
|
|
308
|
+
const VETO_GUIDE = `# Veto MCP Server
|
|
309
|
+
|
|
310
|
+
Veto is active. 49 tools across 5 categories:
|
|
311
|
+
|
|
312
|
+
**Session & Context** — veto_status · veto_session_save · veto_continue · veto_handoff
|
|
313
|
+
Save work at 60–70% context capacity. veto_status triggers auto-save above 70%.
|
|
314
|
+
|
|
315
|
+
**Code Intelligence** — veto_diff_review · veto_code_review · veto_security_scan · veto_secrets_scan · veto_ci_gate
|
|
316
|
+
Run veto_diff_review before any merge — it runs all three scans in parallel.
|
|
317
|
+
|
|
318
|
+
**Council & Routing** — veto_council_debate · veto_route_task · veto_execute_parallel
|
|
319
|
+
Council = 7 specialist agents (Lead Dev, PM, Architect, UX, Devil's Advocate, Legal, Security).
|
|
320
|
+
Verdicts: GREEN (proceed) · YELLOW (warnings) · RED (blocked) · DEADLOCK (human decision needed).
|
|
321
|
+
Two-phase LLM-backed flow: call with { task } → get debate_prompt → reason as all 7 agents → call again with { task, agent_responses }.
|
|
322
|
+
|
|
323
|
+
**Memory & Discovery** — veto_discover · veto_summarize · veto_memory_store · veto_memory_search
|
|
324
|
+
Run veto_discover on any unfamiliar repo before touching files.
|
|
325
|
+
|
|
326
|
+
**Observability** — veto_usage_status · veto_health · veto_audit_log · veto_learning_stats
|
|
327
|
+
|
|
328
|
+
Recommended start sequence:
|
|
329
|
+
1. veto_status — confirm running
|
|
330
|
+
2. veto_discover — map the project
|
|
331
|
+
3. veto_route_task — pick the right agent
|
|
332
|
+
4. veto_diff_review — validate before shipping
|
|
333
|
+
5. veto_session_save — checkpoint before context fills
|
|
334
|
+
`;
|
|
335
|
+
let ctxWritten = 0;
|
|
336
|
+
// Gemini & Antigravity CLI: ~/.gemini/GEMINI.md
|
|
337
|
+
const geminiDir = join(HOME, '.gemini');
|
|
338
|
+
if (existsSync(geminiDir)) {
|
|
339
|
+
try {
|
|
340
|
+
writeFileSync(join(geminiDir, 'GEMINI.md'), VETO_GUIDE, 'utf8');
|
|
341
|
+
console.log(c.green(' ✓ ') + 'Gemini/Antigravity CLI — wrote ~/.gemini/GEMINI.md');
|
|
342
|
+
ctxWritten++;
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
console.log(c.yellow(' ⚠ ') + 'Gemini/Antigravity CLI — could not write GEMINI.md');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Codex CLI: project AGENTS.md + global ~/.codex/AGENTS.override.md
|
|
349
|
+
const codexDir2 = join(HOME, '.codex');
|
|
350
|
+
if (existsSync(codexDir2)) {
|
|
351
|
+
// Project-level: only write if not already present (user may have customized it)
|
|
352
|
+
const projectAgents = join(cwd, 'AGENTS.md');
|
|
353
|
+
if (!existsSync(projectAgents)) {
|
|
354
|
+
try {
|
|
355
|
+
writeFileSync(projectAgents, VETO_GUIDE, 'utf8');
|
|
356
|
+
console.log(c.green(' ✓ ') + `Codex CLI — wrote AGENTS.md in ${cwd}`);
|
|
357
|
+
ctxWritten++;
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
console.log(c.yellow(' ⚠ ') + 'Codex CLI — could not write AGENTS.md');
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
console.log(c.dim(' · ') + c.dim('Codex CLI — AGENTS.md already exists, skipping'));
|
|
365
|
+
}
|
|
366
|
+
// Global override
|
|
367
|
+
try {
|
|
368
|
+
writeFileSync(join(codexDir2, 'AGENTS.override.md'), VETO_GUIDE, 'utf8');
|
|
369
|
+
console.log(c.green(' ✓ ') + 'Codex CLI — wrote ~/.codex/AGENTS.override.md');
|
|
370
|
+
ctxWritten++;
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
console.log(c.yellow(' ⚠ ') + 'Codex CLI — could not write AGENTS.override.md');
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// Windsurf: ~/.codeium/windsurf/rules/veto.md
|
|
377
|
+
const windsurfRulesDir = join(HOME, '.codeium', 'windsurf', 'rules');
|
|
378
|
+
if (existsSync(join(HOME, '.codeium', 'windsurf'))) {
|
|
379
|
+
try {
|
|
380
|
+
mkdirSync(windsurfRulesDir, { recursive: true });
|
|
381
|
+
writeFileSync(join(windsurfRulesDir, 'veto.md'), VETO_GUIDE, 'utf8');
|
|
382
|
+
console.log(c.green(' ✓ ') + 'Windsurf — wrote ~/.codeium/windsurf/rules/veto.md');
|
|
383
|
+
ctxWritten++;
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
console.log(c.yellow(' ⚠ ') + 'Windsurf — could not write rules/veto.md');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (ctxWritten > 0)
|
|
390
|
+
console.log('');
|
|
391
|
+
// 6. Write Claude Code hook templates to .claude/hooks/ in current project
|
|
392
|
+
// Hooks enforce secrets scanning on every file write and auto-save before compaction.
|
|
393
|
+
if (existsSync(claudeDir)) {
|
|
394
|
+
const hooksDir = join(cwd, '.claude', 'hooks');
|
|
395
|
+
const settingsPath = join(cwd, '.claude', 'settings.json');
|
|
396
|
+
try {
|
|
397
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
398
|
+
// Secrets scan — bash (Mac/Linux)
|
|
399
|
+
const shLines = [
|
|
400
|
+
'#!/usr/bin/env bash',
|
|
401
|
+
'# Veto hook: scan written files for exposed secrets (no API key needed).',
|
|
402
|
+
'# Triggered by Claude Code PostToolUse after Write/Edit tool calls.',
|
|
403
|
+
'FILE="$1"',
|
|
404
|
+
'[ -z "$FILE" ] && exit 0',
|
|
405
|
+
'[ ! -f "$FILE" ] && exit 0',
|
|
406
|
+
"PATTERNS='(api[_-]?key|secret[_-]?key|password|passwd|token|access[_-]?key|private[_-]?key)\\s*[=:]\\s*[A-Za-z0-9+/]{20,}'",
|
|
407
|
+
'if grep -qiE "$PATTERNS" "$FILE" 2>/dev/null; then',
|
|
408
|
+
' echo "Veto: possible secret detected in $FILE — run veto_secrets_scan to confirm"',
|
|
409
|
+
' exit 1',
|
|
410
|
+
'fi',
|
|
411
|
+
'exit 0',
|
|
412
|
+
'',
|
|
413
|
+
];
|
|
414
|
+
writeFileSync(join(hooksDir, 'veto-secrets-scan.sh'), shLines.join('\n'), 'utf8');
|
|
415
|
+
// Secrets scan — PowerShell (Windows)
|
|
416
|
+
const ps1Lines = [
|
|
417
|
+
'# Veto hook: scan written files for exposed secrets (no API key needed).',
|
|
418
|
+
'param([string]$File)',
|
|
419
|
+
'if (-not $File -or -not (Test-Path $File)) { exit 0 }',
|
|
420
|
+
"$pattern = '(api[_-]?key|secret[_-]?key|password|passwd|token|access[_-]?key|private[_-]?key)\\s*[=:]\\s*[A-Za-z0-9+/]{20,}'",
|
|
421
|
+
'if (Select-String -Path $File -Pattern $pattern -Quiet -CaseSensitive:$false) {',
|
|
422
|
+
' Write-Host "Veto: possible secret detected in $File — run veto_secrets_scan to confirm"',
|
|
423
|
+
' exit 1',
|
|
424
|
+
'}',
|
|
425
|
+
'exit 0',
|
|
426
|
+
'',
|
|
427
|
+
];
|
|
428
|
+
writeFileSync(join(hooksDir, 'veto-secrets-scan.ps1'), ps1Lines.join('\n'), 'utf8');
|
|
429
|
+
// Phase 1.4: Write standard hook files that Claude Code looks for
|
|
430
|
+
const postFileWrite = process.platform === 'win32'
|
|
431
|
+
? `@powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\\hooks\\veto-secrets-scan.ps1" "%1"`
|
|
432
|
+
: `#!/bin/sh\n./.claude/hooks/veto-secrets-scan.sh "$1"`;
|
|
433
|
+
const preCompact = process.platform === 'win32'
|
|
434
|
+
? `@npx -y @jigyasudham/veto veto_session_save --auto_summarize=true`
|
|
435
|
+
: `#!/bin/sh\nnpx -y @jigyasudham/veto veto_session_save --auto_summarize=true`;
|
|
436
|
+
writeFileSync(join(hooksDir, 'post-file-write'), postFileWrite, { mode: 0o755 });
|
|
437
|
+
writeFileSync(join(hooksDir, 'pre-compact'), preCompact, { mode: 0o755 });
|
|
438
|
+
// Wire hooks into .claude/settings.json if it exists or create it
|
|
439
|
+
let projectSettings = {};
|
|
440
|
+
if (existsSync(settingsPath)) {
|
|
441
|
+
try {
|
|
442
|
+
projectSettings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
443
|
+
}
|
|
444
|
+
catch { /* leave empty */ }
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
448
|
+
}
|
|
449
|
+
const hooks = projectSettings.hooks ?? {};
|
|
450
|
+
// Only add if not already configured
|
|
451
|
+
if (!hooks['PostToolUse']) {
|
|
452
|
+
const scanCmd = process.platform === 'win32'
|
|
453
|
+
? 'powershell -ExecutionPolicy Bypass -File .claude/hooks/veto-secrets-scan.ps1 "$CLAUDE_TOOL_INPUT_FILE_PATH"'
|
|
454
|
+
: 'bash .claude/hooks/veto-secrets-scan.sh "$CLAUDE_TOOL_INPUT_FILE_PATH"';
|
|
455
|
+
hooks['PostToolUse'] = [{ matcher: 'Write|Edit', hooks: [{ type: 'command', command: scanCmd }] }];
|
|
456
|
+
projectSettings.hooks = hooks;
|
|
457
|
+
writeFileSync(settingsPath, JSON.stringify(projectSettings, null, 2) + '\n', 'utf8');
|
|
458
|
+
console.log(c.green(' ✓ ') + 'Claude Code — wrote .claude/hooks/veto-secrets-scan + PostToolUse hook entry');
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
console.log(c.dim(' · ') + c.dim('Claude Code — PostToolUse hook already configured, skipping'));
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
console.log(c.yellow(' ⚠ ') + 'Claude Code — could not write hook templates (permission denied?)');
|
|
466
|
+
}
|
|
467
|
+
console.log('');
|
|
468
|
+
}
|
|
285
469
|
if (configured === 0 && skipped === 0) {
|
|
286
470
|
console.log(c.yellow(' ⚠ No AI tools detected.'));
|
|
287
471
|
console.log(' Install Claude Code, Gemini CLI, or Codex CLI and run veto init again.');
|
|
@@ -417,6 +601,7 @@ async function doctorCommand() {
|
|
|
417
601
|
// Other platforms — check their config JSON files
|
|
418
602
|
const platforms = [
|
|
419
603
|
{ name: 'Gemini CLI', configPath: join(HOME, '.gemini', 'settings.json'), detectionDir: join(HOME, '.gemini'), key: 'mcpServers' },
|
|
604
|
+
{ name: 'Antigravity CLI', configPath: join(HOME, '.gemini', 'antigravity-cli', 'mcp_config.json'), detectionDir: join(HOME, '.gemini', 'antigravity-cli'), key: 'mcpServers' },
|
|
420
605
|
{ name: 'Cursor', configPath: join(HOME, '.cursor', 'mcp.json'), detectionDir: join(HOME, '.cursor'), key: 'mcpServers' },
|
|
421
606
|
{ name: 'Windsurf', configPath: join(HOME, '.codeium', 'windsurf', 'mcp_config.json'), detectionDir: join(HOME, '.codeium', 'windsurf'), key: 'mcpServers' },
|
|
422
607
|
{
|
|
@@ -513,6 +698,57 @@ async function sessionsCommand() {
|
|
|
513
698
|
}
|
|
514
699
|
async function memoryCommand() {
|
|
515
700
|
const args = process.argv.slice(3);
|
|
701
|
+
const subcommand = args[0];
|
|
702
|
+
// veto memory export [--format=markdown] [--output=path]
|
|
703
|
+
if (subcommand === 'export') {
|
|
704
|
+
const formatArg = args.find(a => a.startsWith('--format='));
|
|
705
|
+
const outputArg = args.find(a => a.startsWith('--output='));
|
|
706
|
+
const format = formatArg?.split('=')[1] ?? 'json';
|
|
707
|
+
const outputPath = outputArg?.split('=')[1];
|
|
708
|
+
const { exportMemory, exportMemoryMarkdown } = await import('./memory/sync.js');
|
|
709
|
+
if (format === 'markdown') {
|
|
710
|
+
const cwd = resolve(process.cwd());
|
|
711
|
+
const result = exportMemoryMarkdown(cwd, outputPath);
|
|
712
|
+
if (result.success) {
|
|
713
|
+
console.log(c.green(' ✓') + ` VETO_MEMORY.md written to ${result.output_path}`);
|
|
714
|
+
console.log(c.dim(` Sections: ${JSON.stringify(result.sections)}`));
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
console.error(c.red(` ✗ Export failed: ${result.error}`));
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
const result = exportMemory(outputPath);
|
|
722
|
+
if (result.success) {
|
|
723
|
+
console.log(c.green(' ✓') + ` Exported to ${result.export_path}`);
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
console.error(c.red(` ✗ Export failed: ${result.error}`));
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
// veto memory import [--format=markdown] <path>
|
|
732
|
+
if (subcommand === 'import') {
|
|
733
|
+
const formatArg = args.find(a => a.startsWith('--format='));
|
|
734
|
+
const format = formatArg?.split('=')[1] ?? 'json';
|
|
735
|
+
const inputPath = args.find(a => !a.startsWith('--')) ?? '';
|
|
736
|
+
const { importMemory, importMemoryMarkdown } = await import('./memory/sync.js');
|
|
737
|
+
if (format === 'markdown') {
|
|
738
|
+
if (!inputPath) {
|
|
739
|
+
console.error(c.red(' ✗ Provide a file path: veto memory import --format=markdown <path>'));
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const result = importMemoryMarkdown(inputPath);
|
|
743
|
+
console.log(result.success ? c.green(' ✓') + ` ${result.message}` : c.red(` ✗ ${result.message}`));
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
const result = importMemory(inputPath || undefined);
|
|
747
|
+
console.log(result.success ? c.green(' ✓') + ` Import complete` : c.red(` ✗ Import failed: ${result.error}`));
|
|
748
|
+
}
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
// veto memory [query]
|
|
516
752
|
const query = args.join(' ') || undefined;
|
|
517
753
|
const { searchKnowledge } = await import('./memory/local.js');
|
|
518
754
|
const results = searchKnowledge({ query, limit: 20 });
|
|
@@ -554,7 +790,7 @@ async function patternsCommand() {
|
|
|
554
790
|
}
|
|
555
791
|
function shortHelpCommand() {
|
|
556
792
|
console.log('');
|
|
557
|
-
console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(` —
|
|
793
|
+
console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(` — 62 agentic tools. 50+ specialists. Zero cost.`));
|
|
558
794
|
console.log('');
|
|
559
795
|
console.log(c.bold(' CLI Commands'));
|
|
560
796
|
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
@@ -564,6 +800,8 @@ function shortHelpCommand() {
|
|
|
564
800
|
console.log(` ${c.cyan('veto sessions')} List last 20 saved sessions`);
|
|
565
801
|
console.log(` ${c.cyan('veto memory')} ${c.dim('[query]')} Search knowledge base`);
|
|
566
802
|
console.log(` ${c.cyan('veto patterns')} ${c.dim('[prefix]')} List learned agent/routing patterns`);
|
|
803
|
+
console.log(` ${c.cyan('veto routing')} ${c.dim('[status|enable|disable|reset|log]')}`);
|
|
804
|
+
console.log(` Routing feedback loop (opt-in signal storage)`);
|
|
567
805
|
console.log(` ${c.cyan('veto version')} Show version (alias for status)`);
|
|
568
806
|
console.log(` ${c.cyan('veto hook install')} Install pre-commit secrets scan hook`);
|
|
569
807
|
console.log(` ${c.cyan('veto hook remove')} Remove the veto pre-commit hook`);
|
|
@@ -571,26 +809,20 @@ function shortHelpCommand() {
|
|
|
571
809
|
console.log(` ${c.cyan('veto help')} Show this help`);
|
|
572
810
|
console.log(` ${c.cyan('veto help --troubleshoot')} Show troubleshooting guide`);
|
|
573
811
|
console.log('');
|
|
574
|
-
console.log(c.bold(' MCP Tools (
|
|
812
|
+
console.log(c.bold(' MCP Tools (62 Agentic Tools)'));
|
|
575
813
|
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
576
|
-
console.log(` ${c.dim('Session')} veto_status ·
|
|
577
|
-
console.log(` ${c.dim('
|
|
578
|
-
console.log(` ${c.dim('
|
|
579
|
-
console.log(` ${c.dim('
|
|
580
|
-
console.log(` ${c.dim('
|
|
581
|
-
console.log(` ${c.dim('
|
|
582
|
-
console.log(` ${c.dim('
|
|
583
|
-
console.log(` ${c.dim('
|
|
584
|
-
console.log(`
|
|
585
|
-
console.log(`
|
|
586
|
-
console.log(`
|
|
587
|
-
console.log(` ${c.dim('
|
|
588
|
-
console.log(` ${c.dim('Handoff')} veto_handoff · veto_continue · veto_platform_setup`);
|
|
589
|
-
console.log(` ${c.dim('Intelligence')} veto_docs_fetch · veto_context_status · veto_task_parse`);
|
|
590
|
-
console.log(` ${c.dim('Observability')} veto_usage_status · veto_audit_log · veto_health · veto_metrics`);
|
|
591
|
-
console.log(` ${c.dim('CI/CD')} veto_ci_gate · veto_pr_review`);
|
|
592
|
-
console.log(` ${c.dim('Discover')} veto_discover · veto_summarize · veto_git_blame · veto_changelog`);
|
|
593
|
-
console.log(` ${c.dim('Plugins')} veto_plugins`);
|
|
814
|
+
console.log(` ${c.dim('Session')} veto_status · veto_session_save · veto_session_restore · veto_sessions_list · veto_session_replay · veto_autosave_status`);
|
|
815
|
+
console.log(` ${c.dim('Council')} veto_council_debate · veto_benchmark · veto_adr`);
|
|
816
|
+
console.log(` ${c.dim('Intelligence')} veto_agent_plan · veto_execute_parallel · veto_explain · veto_delegate · veto_compose_agents`);
|
|
817
|
+
console.log(` ${c.dim('Scanning')} veto_code_review · veto_security_scan · veto_secrets_scan · veto_diff_review · veto_full_review · veto_pr_review`);
|
|
818
|
+
console.log(` ${c.dim('Pipelines')} veto_workflow · veto_task_parse · veto_new_feature · veto_pre_commit · veto_ci_gate`);
|
|
819
|
+
console.log(` ${c.dim('Watching')} veto_watch · veto_watch_poll · veto_watch_stop`);
|
|
820
|
+
console.log(` ${c.dim('Advanced')} veto_local_llm · veto_semantic_search · veto_sdd_agent · veto_playwright · veto_notify_ide · veto_translate · veto_a11y_advisor`);
|
|
821
|
+
console.log(` ${c.dim('Quality')} veto_type_coverage · veto_test_gaps · veto_clone_detector · veto_lint_rules · veto_api_contract`);
|
|
822
|
+
console.log(` ${c.dim('Discovery')} veto_discover · veto_summarize · veto_git_blame · veto_changelog · veto_onboard · veto_debt_register`);
|
|
823
|
+
console.log(` ${c.dim('DevTools')} veto_docs_fetch · veto_context_status · veto_openapi_gen · veto_flag_auditor · veto_env_setup · veto_diagram · veto_rca`);
|
|
824
|
+
console.log(` veto_commit_message · veto_pr_description · veto_pr_post · veto_prompt_optimizer · veto_sre_advisor · veto_merge_conflict`);
|
|
825
|
+
console.log(` ${c.dim('System')} veto_route_task · veto_rate_status · veto_audit_log · veto_health · veto_metrics · veto_learning_stats · veto_learning_apply · veto_handoff · veto_continue · veto_platform_setup · veto_plugins`);
|
|
594
826
|
console.log('');
|
|
595
827
|
console.log(c.bold(' MCP Resources'));
|
|
596
828
|
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
@@ -602,6 +834,7 @@ function shortHelpCommand() {
|
|
|
602
834
|
console.log(c.bold(' MCP Prompts'));
|
|
603
835
|
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
604
836
|
console.log(` ${c.cyan('code-review')} · ${c.cyan('security-audit')} · ${c.cyan('deploy-checklist')} · ${c.cyan('explain-file')}`);
|
|
837
|
+
console.log(` ${c.cyan('full-review')} · ${c.cyan('new-feature')} · ${c.cyan('debug-incident')} · ${c.cyan('onboard')}`);
|
|
605
838
|
console.log('');
|
|
606
839
|
console.log(c.bold(' Docs & Support'));
|
|
607
840
|
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
@@ -679,6 +912,84 @@ function troubleshootCommand() {
|
|
|
679
912
|
console.log(` ${c.dim('→')} Then restart the AI client on that machine`);
|
|
680
913
|
console.log('');
|
|
681
914
|
}
|
|
915
|
+
// ─── Routing Command ────────────────────────────────────────────────────────────
|
|
916
|
+
async function routingCommand() {
|
|
917
|
+
const { getRoutingFeedbackStats, resetRoutingFeedback, listRoutingFeedback, isFeedbackEnabled, setFeedbackEnabled } = await import('./router/learning-updater.js');
|
|
918
|
+
const sub = process.argv[3];
|
|
919
|
+
if (sub === 'enable') {
|
|
920
|
+
setFeedbackEnabled(true);
|
|
921
|
+
console.log('');
|
|
922
|
+
console.log(c.green(' ✓ Routing feedback enabled.'));
|
|
923
|
+
console.log(c.dim(' Every veto_route_task call now records a routing signal (30-day TTL).'));
|
|
924
|
+
console.log(c.dim(' Disable with: veto routing disable | Clear with: veto routing reset'));
|
|
925
|
+
console.log('');
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
if (sub === 'disable') {
|
|
929
|
+
setFeedbackEnabled(false);
|
|
930
|
+
console.log('');
|
|
931
|
+
console.log(c.yellow(' ✓ Routing feedback disabled.'));
|
|
932
|
+
console.log(c.dim(' No new signals will be recorded. Existing data is retained.'));
|
|
933
|
+
console.log(c.dim(' Re-enable with: veto routing enable'));
|
|
934
|
+
console.log('');
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (sub === 'reset') {
|
|
938
|
+
const result = resetRoutingFeedback();
|
|
939
|
+
console.log('');
|
|
940
|
+
console.log(c.green(' ✓ Routing feedback reset.'));
|
|
941
|
+
console.log(` ${c.dim('Deleted:')} ${c.cyan(String(result.deleted_feedback))} feedback signal${result.deleted_feedback !== 1 ? 's' : ''}`);
|
|
942
|
+
if (result.reset_thresholds) {
|
|
943
|
+
console.log(` ${c.dim('Thresholds:')} reset to defaults (30/70)`);
|
|
944
|
+
}
|
|
945
|
+
console.log('');
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (sub === 'log') {
|
|
949
|
+
const limit = parseInt(process.argv[4] ?? '20', 10);
|
|
950
|
+
const entries = listRoutingFeedback(isNaN(limit) ? 20 : limit);
|
|
951
|
+
console.log('');
|
|
952
|
+
console.log(c.bold(' Routing Feedback Log') + c.dim(` (${entries.length})`));
|
|
953
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────────────'));
|
|
954
|
+
if (entries.length === 0) {
|
|
955
|
+
console.log(c.dim(' No feedback signals yet. Enable feedback: veto routing enable'));
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
for (const e of entries) {
|
|
959
|
+
const outcomeColor = e.outcome === 'accepted' ? c.green : e.outcome === 'overridden' ? c.yellow : c.dim;
|
|
960
|
+
const exp = new Date(e.expires_at).toLocaleDateString();
|
|
961
|
+
console.log(` ${c.dim(e.recorded_at.slice(0, 10))} T${e.model_tier} ${outcomeColor(e.outcome.padEnd(10))} ${c.dim(`q:${e.quality ?? '-'}`)} ${e.task_snippet.slice(0, 55)}`);
|
|
962
|
+
console.log(` ${c.dim(` expires: ${exp} agent: ${e.agent ?? 'dynamic'}`)}`);
|
|
963
|
+
console.log('');
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
// Default: status
|
|
969
|
+
const stats = getRoutingFeedbackStats();
|
|
970
|
+
const enabled = isFeedbackEnabled();
|
|
971
|
+
const statusStr = enabled ? c.green('enabled') : c.dim('disabled');
|
|
972
|
+
console.log('');
|
|
973
|
+
console.log(c.bold(' Routing Feedback') + c.dim(' — loop status'));
|
|
974
|
+
console.log(c.dim(' ─────────────────────────────────────────────────────'));
|
|
975
|
+
console.log(` Status ${statusStr}`);
|
|
976
|
+
console.log(` TTL ${c.cyan(String(stats.ttl_days))} days`);
|
|
977
|
+
console.log(` Signals ${c.cyan(String(stats.active))} active · ${c.dim(String(stats.expired))} expired · ${String(stats.total)} total`);
|
|
978
|
+
if (Object.keys(stats.by_outcome).length > 0) {
|
|
979
|
+
const parts = Object.entries(stats.by_outcome).map(([k, v]) => `${k}: ${v}`).join(' · ');
|
|
980
|
+
console.log(` Outcomes ${c.dim(parts)}`);
|
|
981
|
+
}
|
|
982
|
+
if (Object.keys(stats.by_tier).length > 0) {
|
|
983
|
+
const parts = Object.entries(stats.by_tier).map(([tier, s]) => `T${tier}: ${s.count} (q${s.avg_quality ?? '-'})`).join(' · ');
|
|
984
|
+
console.log(` By tier ${c.dim(parts)}`);
|
|
985
|
+
}
|
|
986
|
+
if (stats.next_expiry) {
|
|
987
|
+
console.log(` Next expiry ${c.dim(new Date(stats.next_expiry).toLocaleDateString())}`);
|
|
988
|
+
}
|
|
989
|
+
console.log('');
|
|
990
|
+
console.log(c.dim(` Commands: veto routing enable · veto routing disable · veto routing reset · veto routing log`));
|
|
991
|
+
console.log('');
|
|
992
|
+
}
|
|
682
993
|
// ─── Hook installer ────────────────────────────────────────────────────────────
|
|
683
994
|
async function hookCommand() {
|
|
684
995
|
const sub = process.argv[3];
|
|
@@ -831,6 +1142,12 @@ switch (command) {
|
|
|
831
1142
|
process.exit(1);
|
|
832
1143
|
});
|
|
833
1144
|
break;
|
|
1145
|
+
case 'routing':
|
|
1146
|
+
routingCommand().catch((err) => {
|
|
1147
|
+
console.error(c.red(`Error: ${err.message}`));
|
|
1148
|
+
process.exit(1);
|
|
1149
|
+
});
|
|
1150
|
+
break;
|
|
834
1151
|
case 'hook':
|
|
835
1152
|
hookCommand().catch((err) => {
|
|
836
1153
|
console.error(c.red(`Error: ${err.message}`));
|