@jigyasudham/veto 1.4.4 → 2.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.
Files changed (91) hide show
  1. package/AGENTS.md +134 -0
  2. package/README.md +26 -144
  3. package/dist/adapters/index.d.ts +3 -2
  4. package/dist/adapters/index.d.ts.map +1 -1
  5. package/dist/adapters/index.js +105 -1
  6. package/dist/adapters/index.js.map +1 -1
  7. package/dist/agents/executor.d.ts +2 -0
  8. package/dist/agents/executor.d.ts.map +1 -1
  9. package/dist/agents/executor.js +50 -3
  10. package/dist/agents/executor.js.map +1 -1
  11. package/dist/agents/llm-runner.d.ts +11 -0
  12. package/dist/agents/llm-runner.d.ts.map +1 -0
  13. package/dist/agents/llm-runner.js +252 -0
  14. package/dist/agents/llm-runner.js.map +1 -0
  15. package/dist/agents/local-llm.d.ts +14 -0
  16. package/dist/agents/local-llm.d.ts.map +1 -0
  17. package/dist/agents/local-llm.js +51 -0
  18. package/dist/agents/local-llm.js.map +1 -0
  19. package/dist/agents/manifest.d.ts +13 -0
  20. package/dist/agents/manifest.d.ts.map +1 -0
  21. package/dist/agents/manifest.js +55 -0
  22. package/dist/agents/manifest.js.map +1 -0
  23. package/dist/agents/quality/clone-detector.d.ts +16 -0
  24. package/dist/agents/quality/clone-detector.d.ts.map +1 -0
  25. package/dist/agents/quality/clone-detector.js +72 -0
  26. package/dist/agents/quality/clone-detector.js.map +1 -0
  27. package/dist/agents/types.d.ts +15 -0
  28. package/dist/agents/types.d.ts.map +1 -1
  29. package/dist/agents/validate.d.ts +11 -0
  30. package/dist/agents/validate.d.ts.map +1 -0
  31. package/dist/agents/validate.js +54 -0
  32. package/dist/agents/validate.js.map +1 -0
  33. package/dist/cli.js +331 -21
  34. package/dist/cli.js.map +1 -1
  35. package/dist/council/llm-council.d.ts.map +1 -1
  36. package/dist/council/llm-council.js +10 -9
  37. package/dist/council/llm-council.js.map +1 -1
  38. package/dist/council/types.d.ts +2 -0
  39. package/dist/council/types.d.ts.map +1 -1
  40. package/dist/memory/local.d.ts +12 -1
  41. package/dist/memory/local.d.ts.map +1 -1
  42. package/dist/memory/local.js +56 -2
  43. package/dist/memory/local.js.map +1 -1
  44. package/dist/memory/schema.d.ts +28 -43
  45. package/dist/memory/schema.d.ts.map +1 -1
  46. package/dist/memory/schema.js +31 -0
  47. package/dist/memory/schema.js.map +1 -1
  48. package/dist/memory/sync.d.ts +13 -0
  49. package/dist/memory/sync.d.ts.map +1 -1
  50. package/dist/memory/sync.js +113 -0
  51. package/dist/memory/sync.js.map +1 -1
  52. package/dist/repo-map/ignore.d.ts +8 -0
  53. package/dist/repo-map/ignore.d.ts.map +1 -0
  54. package/dist/repo-map/ignore.js +65 -0
  55. package/dist/repo-map/ignore.js.map +1 -0
  56. package/dist/repo-map/index.d.ts +29 -0
  57. package/dist/repo-map/index.d.ts.map +1 -0
  58. package/dist/repo-map/index.js +240 -0
  59. package/dist/repo-map/index.js.map +1 -0
  60. package/dist/router/context-compressor.d.ts +1 -1
  61. package/dist/router/context-compressor.d.ts.map +1 -1
  62. package/dist/router/context-compressor.js +9 -3
  63. package/dist/router/context-compressor.js.map +1 -1
  64. package/dist/router/index.d.ts +8 -3
  65. package/dist/router/index.d.ts.map +1 -1
  66. package/dist/router/index.js +20 -4
  67. package/dist/router/index.js.map +1 -1
  68. package/dist/router/learning-updater.d.ts +41 -0
  69. package/dist/router/learning-updater.d.ts.map +1 -1
  70. package/dist/router/learning-updater.js +62 -0
  71. package/dist/router/learning-updater.js.map +1 -1
  72. package/dist/router/model-selector.d.ts +4 -1
  73. package/dist/router/model-selector.d.ts.map +1 -1
  74. package/dist/router/model-selector.js +24 -28
  75. package/dist/router/model-selector.js.map +1 -1
  76. package/dist/server.js +3121 -1655
  77. package/dist/server.js.map +1 -1
  78. package/dist/tools/definitions.d.ts +1205 -171
  79. package/dist/tools/definitions.d.ts.map +1 -1
  80. package/dist/tools/definitions.js +678 -4
  81. package/dist/tools/definitions.js.map +1 -1
  82. package/dist/watcher/index.d.ts +1 -0
  83. package/dist/watcher/index.d.ts.map +1 -1
  84. package/dist/watcher/index.js +7 -6
  85. package/dist/watcher/index.js.map +1 -1
  86. package/dist/workflow/pipeline.d.ts +12 -2
  87. package/dist/workflow/pipeline.d.ts.map +1 -1
  88. package/dist/workflow/pipeline.js +395 -16
  89. package/dist/workflow/pipeline.js.map +1 -1
  90. package/p7.ts +6 -0
  91. package/package.json +8 -4
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AgentPlan, AgentAnalysis, WorkerAgentType } from './types.js';
2
+ /**
3
+ * Validates and sanitizes an AgentPlan. Returns null if the value is not
4
+ * recoverable. Otherwise returns a clean plan using Zod.
5
+ */
6
+ export declare function validateAgentPlan(raw: unknown, agentType: WorkerAgentType): AgentPlan | null;
7
+ /**
8
+ * Validates and sanitizes an AgentAnalysis. Returns null if not recoverable.
9
+ */
10
+ export declare function validateAgentAnalysis(raw: unknown, agentType: WorkerAgentType): AgentAnalysis | null;
11
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/agents/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAiC,eAAe,EAAE,MAAM,YAAY,CAAC;AAmC3G;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAI5F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,GAAG,aAAa,GAAG,IAAI,CAOpG"}
@@ -0,0 +1,54 @@
1
+ import { z } from 'zod';
2
+ const findingSchema = z.object({
3
+ severity: z.enum(['critical', 'high', 'medium', 'low', 'info']).default('info').catch('info'),
4
+ category: z.string().default('general').catch('general'),
5
+ description: z.string().default('No description').catch('No description'),
6
+ fix: z.string().default('No fix provided').catch('No fix provided'),
7
+ location: z.string().optional().catch(undefined),
8
+ cwe: z.string().optional().catch(undefined),
9
+ owasp: z.string().optional().catch(undefined)
10
+ });
11
+ const planSchema = z.object({
12
+ agent: z.string().catch(''),
13
+ task: z.string().catch(''),
14
+ tier: z.union([z.literal(1), z.literal(2), z.literal(3)]).default(2).catch(2),
15
+ approach: z.string().default('').catch(''),
16
+ steps: z.array(z.string()).default([]).catch([]),
17
+ checklist: z.array(z.string()).default([]).catch([]),
18
+ pitfalls: z.array(z.string()).default([]).catch([]),
19
+ patterns: z.array(z.string()).default([]).catch([]),
20
+ duration_estimate: z.string().default('unknown').catch('unknown')
21
+ });
22
+ const analysisSchema = z.object({
23
+ agent: z.string().catch(''),
24
+ subject: z.string().default('').catch(''),
25
+ findings: z.array(findingSchema).default([]).catch([]),
26
+ score: z.number().min(0).max(100).default(70).catch(70),
27
+ verdict: z.enum(['approved', 'approved_with_warnings', 'needs_revision', 'rejected']).default('approved_with_warnings').catch('approved_with_warnings'),
28
+ summary: z.string().default('').catch(''),
29
+ critical_count: z.number().optional().catch(undefined),
30
+ high_count: z.number().optional().catch(undefined)
31
+ });
32
+ /**
33
+ * Validates and sanitizes an AgentPlan. Returns null if the value is not
34
+ * recoverable. Otherwise returns a clean plan using Zod.
35
+ */
36
+ export function validateAgentPlan(raw, agentType) {
37
+ const parsed = planSchema.safeParse(raw);
38
+ if (!parsed.success)
39
+ return null;
40
+ return { ...parsed.data, agent: agentType };
41
+ }
42
+ /**
43
+ * Validates and sanitizes an AgentAnalysis. Returns null if not recoverable.
44
+ */
45
+ export function validateAgentAnalysis(raw, agentType) {
46
+ const parsed = analysisSchema.safeParse(raw);
47
+ if (!parsed.success)
48
+ return null;
49
+ const data = parsed.data;
50
+ const critical_count = data.critical_count ?? data.findings.filter(f => f.severity === 'critical').length;
51
+ const high_count = data.high_count ?? data.findings.filter(f => f.severity === 'high').length;
52
+ return { ...data, agent: agentType, critical_count, high_count };
53
+ }
54
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/agents/validate.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -162,8 +162,21 @@ async function initCommand() {
162
162
  console.error(c.red(` Error initializing database: ${msg}`));
163
163
  process.exit(1);
164
164
  }
165
- // 3. Auto-scan current project and store project map
165
+ // 3. Auto-import VETO_MEMORY.md if present in cwd
166
166
  const cwd = resolve(process.cwd());
167
+ const vetoMemoryPath = join(cwd, 'VETO_MEMORY.md');
168
+ if (existsSync(vetoMemoryPath)) {
169
+ process.stdout.write(' · Importing VETO_MEMORY.md...');
170
+ try {
171
+ const { importMemoryMarkdown } = await import('./memory/sync.js');
172
+ const importResult = importMemoryMarkdown(vetoMemoryPath);
173
+ console.log(c.green(' ✓') + ` ${importResult.imported} knowledge entries imported`);
174
+ }
175
+ catch {
176
+ console.log(c.dim(' skipped'));
177
+ }
178
+ }
179
+ // 4. Auto-scan current project and store project map
167
180
  const { updateProjectMap } = await import('./memory/local.js');
168
181
  const { discoverProject } = await import('./discover.js');
169
182
  try {
@@ -282,6 +295,171 @@ async function initCommand() {
282
295
  }
283
296
  }
284
297
  console.log('');
298
+ // 5. Write platform-specific context guidance files
299
+ // These are read at session start by each AI client — zero tool calls needed.
300
+ console.log(' Writing context guidance files...');
301
+ console.log('');
302
+ const VETO_GUIDE = `# Veto MCP Server
303
+
304
+ Veto is active. 49 tools across 5 categories:
305
+
306
+ **Session & Context** — veto_status · veto_session_save · veto_continue · veto_handoff
307
+ Save work at 60–70% context capacity. veto_status triggers auto-save above 70%.
308
+
309
+ **Code Intelligence** — veto_diff_review · veto_code_review · veto_security_scan · veto_secrets_scan · veto_ci_gate
310
+ Run veto_diff_review before any merge — it runs all three scans in parallel.
311
+
312
+ **Council & Routing** — veto_council_debate · veto_route_task · veto_execute_parallel
313
+ Council = 7 specialist agents (Lead Dev, PM, Architect, UX, Devil's Advocate, Legal, Security).
314
+ Verdicts: GREEN (proceed) · YELLOW (warnings) · RED (blocked) · DEADLOCK (human decision needed).
315
+ Two-phase LLM-backed flow: call with { task } → get debate_prompt → reason as all 7 agents → call again with { task, agent_responses }.
316
+
317
+ **Memory & Discovery** — veto_discover · veto_summarize · veto_memory_store · veto_memory_search
318
+ Run veto_discover on any unfamiliar repo before touching files.
319
+
320
+ **Observability** — veto_usage_status · veto_health · veto_audit_log · veto_learning_stats
321
+
322
+ Recommended start sequence:
323
+ 1. veto_status — confirm running
324
+ 2. veto_discover — map the project
325
+ 3. veto_route_task — pick the right agent
326
+ 4. veto_diff_review — validate before shipping
327
+ 5. veto_session_save — checkpoint before context fills
328
+ `;
329
+ let ctxWritten = 0;
330
+ // Gemini CLI: ~/.gemini/GEMINI.md
331
+ const geminiDir = join(HOME, '.gemini');
332
+ if (existsSync(geminiDir)) {
333
+ try {
334
+ writeFileSync(join(geminiDir, 'GEMINI.md'), VETO_GUIDE, 'utf8');
335
+ console.log(c.green(' ✓ ') + 'Gemini CLI — wrote ~/.gemini/GEMINI.md');
336
+ ctxWritten++;
337
+ }
338
+ catch {
339
+ console.log(c.yellow(' ⚠ ') + 'Gemini CLI — could not write GEMINI.md (permission denied?)');
340
+ }
341
+ }
342
+ // Codex CLI: project AGENTS.md + global ~/.codex/AGENTS.override.md
343
+ const codexDir2 = join(HOME, '.codex');
344
+ if (existsSync(codexDir2)) {
345
+ // Project-level: only write if not already present (user may have customized it)
346
+ const projectAgents = join(cwd, 'AGENTS.md');
347
+ if (!existsSync(projectAgents)) {
348
+ try {
349
+ writeFileSync(projectAgents, VETO_GUIDE, 'utf8');
350
+ console.log(c.green(' ✓ ') + `Codex CLI — wrote AGENTS.md in ${cwd}`);
351
+ ctxWritten++;
352
+ }
353
+ catch {
354
+ console.log(c.yellow(' ⚠ ') + 'Codex CLI — could not write AGENTS.md');
355
+ }
356
+ }
357
+ else {
358
+ console.log(c.dim(' · ') + c.dim('Codex CLI — AGENTS.md already exists, skipping'));
359
+ }
360
+ // Global override
361
+ try {
362
+ writeFileSync(join(codexDir2, 'AGENTS.override.md'), VETO_GUIDE, 'utf8');
363
+ console.log(c.green(' ✓ ') + 'Codex CLI — wrote ~/.codex/AGENTS.override.md');
364
+ ctxWritten++;
365
+ }
366
+ catch {
367
+ console.log(c.yellow(' ⚠ ') + 'Codex CLI — could not write AGENTS.override.md');
368
+ }
369
+ }
370
+ // Windsurf: ~/.codeium/windsurf/rules/veto.md
371
+ const windsurfRulesDir = join(HOME, '.codeium', 'windsurf', 'rules');
372
+ if (existsSync(join(HOME, '.codeium', 'windsurf'))) {
373
+ try {
374
+ mkdirSync(windsurfRulesDir, { recursive: true });
375
+ writeFileSync(join(windsurfRulesDir, 'veto.md'), VETO_GUIDE, 'utf8');
376
+ console.log(c.green(' ✓ ') + 'Windsurf — wrote ~/.codeium/windsurf/rules/veto.md');
377
+ ctxWritten++;
378
+ }
379
+ catch {
380
+ console.log(c.yellow(' ⚠ ') + 'Windsurf — could not write rules/veto.md');
381
+ }
382
+ }
383
+ if (ctxWritten > 0)
384
+ console.log('');
385
+ // 6. Write Claude Code hook templates to .claude/hooks/ in current project
386
+ // Hooks enforce secrets scanning on every file write and auto-save before compaction.
387
+ if (existsSync(claudeDir)) {
388
+ const hooksDir = join(cwd, '.claude', 'hooks');
389
+ const settingsPath = join(cwd, '.claude', 'settings.json');
390
+ try {
391
+ mkdirSync(hooksDir, { recursive: true });
392
+ // Secrets scan — bash (Mac/Linux)
393
+ const shLines = [
394
+ '#!/usr/bin/env bash',
395
+ '# Veto hook: scan written files for exposed secrets (no API key needed).',
396
+ '# Triggered by Claude Code PostToolUse after Write/Edit tool calls.',
397
+ 'FILE="$1"',
398
+ '[ -z "$FILE" ] && exit 0',
399
+ '[ ! -f "$FILE" ] && exit 0',
400
+ "PATTERNS='(api[_-]?key|secret[_-]?key|password|passwd|token|access[_-]?key|private[_-]?key)\\s*[=:]\\s*[A-Za-z0-9+/]{20,}'",
401
+ 'if grep -qiE "$PATTERNS" "$FILE" 2>/dev/null; then',
402
+ ' echo "Veto: possible secret detected in $FILE — run veto_secrets_scan to confirm"',
403
+ ' exit 1',
404
+ 'fi',
405
+ 'exit 0',
406
+ '',
407
+ ];
408
+ writeFileSync(join(hooksDir, 'veto-secrets-scan.sh'), shLines.join('\n'), 'utf8');
409
+ // Secrets scan — PowerShell (Windows)
410
+ const ps1Lines = [
411
+ '# Veto hook: scan written files for exposed secrets (no API key needed).',
412
+ 'param([string]$File)',
413
+ 'if (-not $File -or -not (Test-Path $File)) { exit 0 }',
414
+ "$pattern = '(api[_-]?key|secret[_-]?key|password|passwd|token|access[_-]?key|private[_-]?key)\\s*[=:]\\s*[A-Za-z0-9+/]{20,}'",
415
+ 'if (Select-String -Path $File -Pattern $pattern -Quiet -CaseSensitive:$false) {',
416
+ ' Write-Host "Veto: possible secret detected in $File — run veto_secrets_scan to confirm"',
417
+ ' exit 1',
418
+ '}',
419
+ 'exit 0',
420
+ '',
421
+ ];
422
+ writeFileSync(join(hooksDir, 'veto-secrets-scan.ps1'), ps1Lines.join('\n'), 'utf8');
423
+ // Phase 1.4: Write standard hook files that Claude Code looks for
424
+ const postFileWrite = process.platform === 'win32'
425
+ ? `@powershell -NoProfile -ExecutionPolicy Bypass -File ".claude\\hooks\\veto-secrets-scan.ps1" "%1"`
426
+ : `#!/bin/sh\n./.claude/hooks/veto-secrets-scan.sh "$1"`;
427
+ const preCompact = process.platform === 'win32'
428
+ ? `@npx -y @jigyasudham/veto veto_session_save --auto_summarize=true`
429
+ : `#!/bin/sh\nnpx -y @jigyasudham/veto veto_session_save --auto_summarize=true`;
430
+ writeFileSync(join(hooksDir, 'post-file-write'), postFileWrite, { mode: 0o755 });
431
+ writeFileSync(join(hooksDir, 'pre-compact'), preCompact, { mode: 0o755 });
432
+ // Wire hooks into .claude/settings.json if it exists or create it
433
+ let projectSettings = {};
434
+ if (existsSync(settingsPath)) {
435
+ try {
436
+ projectSettings = JSON.parse(readFileSync(settingsPath, 'utf8'));
437
+ }
438
+ catch { /* leave empty */ }
439
+ }
440
+ else {
441
+ mkdirSync(dirname(settingsPath), { recursive: true });
442
+ }
443
+ const hooks = projectSettings.hooks ?? {};
444
+ // Only add if not already configured
445
+ if (!hooks['PostToolUse']) {
446
+ const scanCmd = process.platform === 'win32'
447
+ ? 'powershell -ExecutionPolicy Bypass -File .claude/hooks/veto-secrets-scan.ps1 "$CLAUDE_TOOL_INPUT_FILE_PATH"'
448
+ : 'bash .claude/hooks/veto-secrets-scan.sh "$CLAUDE_TOOL_INPUT_FILE_PATH"';
449
+ hooks['PostToolUse'] = [{ matcher: 'Write|Edit', hooks: [{ type: 'command', command: scanCmd }] }];
450
+ projectSettings.hooks = hooks;
451
+ writeFileSync(settingsPath, JSON.stringify(projectSettings, null, 2) + '\n', 'utf8');
452
+ console.log(c.green(' ✓ ') + 'Claude Code — wrote .claude/hooks/veto-secrets-scan + PostToolUse hook entry');
453
+ }
454
+ else {
455
+ console.log(c.dim(' · ') + c.dim('Claude Code — PostToolUse hook already configured, skipping'));
456
+ }
457
+ }
458
+ catch {
459
+ console.log(c.yellow(' ⚠ ') + 'Claude Code — could not write hook templates (permission denied?)');
460
+ }
461
+ console.log('');
462
+ }
285
463
  if (configured === 0 && skipped === 0) {
286
464
  console.log(c.yellow(' ⚠ No AI tools detected.'));
287
465
  console.log(' Install Claude Code, Gemini CLI, or Codex CLI and run veto init again.');
@@ -513,6 +691,57 @@ async function sessionsCommand() {
513
691
  }
514
692
  async function memoryCommand() {
515
693
  const args = process.argv.slice(3);
694
+ const subcommand = args[0];
695
+ // veto memory export [--format=markdown] [--output=path]
696
+ if (subcommand === 'export') {
697
+ const formatArg = args.find(a => a.startsWith('--format='));
698
+ const outputArg = args.find(a => a.startsWith('--output='));
699
+ const format = formatArg?.split('=')[1] ?? 'json';
700
+ const outputPath = outputArg?.split('=')[1];
701
+ const { exportMemory, exportMemoryMarkdown } = await import('./memory/sync.js');
702
+ if (format === 'markdown') {
703
+ const cwd = resolve(process.cwd());
704
+ const result = exportMemoryMarkdown(cwd, outputPath);
705
+ if (result.success) {
706
+ console.log(c.green(' ✓') + ` VETO_MEMORY.md written to ${result.output_path}`);
707
+ console.log(c.dim(` Sections: ${JSON.stringify(result.sections)}`));
708
+ }
709
+ else {
710
+ console.error(c.red(` ✗ Export failed: ${result.error}`));
711
+ }
712
+ }
713
+ else {
714
+ const result = exportMemory(outputPath);
715
+ if (result.success) {
716
+ console.log(c.green(' ✓') + ` Exported to ${result.export_path}`);
717
+ }
718
+ else {
719
+ console.error(c.red(` ✗ Export failed: ${result.error}`));
720
+ }
721
+ }
722
+ return;
723
+ }
724
+ // veto memory import [--format=markdown] <path>
725
+ if (subcommand === 'import') {
726
+ const formatArg = args.find(a => a.startsWith('--format='));
727
+ const format = formatArg?.split('=')[1] ?? 'json';
728
+ const inputPath = args.find(a => !a.startsWith('--')) ?? '';
729
+ const { importMemory, importMemoryMarkdown } = await import('./memory/sync.js');
730
+ if (format === 'markdown') {
731
+ if (!inputPath) {
732
+ console.error(c.red(' ✗ Provide a file path: veto memory import --format=markdown <path>'));
733
+ return;
734
+ }
735
+ const result = importMemoryMarkdown(inputPath);
736
+ console.log(result.success ? c.green(' ✓') + ` ${result.message}` : c.red(` ✗ ${result.message}`));
737
+ }
738
+ else {
739
+ const result = importMemory(inputPath || undefined);
740
+ console.log(result.success ? c.green(' ✓') + ` Import complete` : c.red(` ✗ Import failed: ${result.error}`));
741
+ }
742
+ return;
743
+ }
744
+ // veto memory [query]
516
745
  const query = args.join(' ') || undefined;
517
746
  const { searchKnowledge } = await import('./memory/local.js');
518
747
  const results = searchKnowledge({ query, limit: 20 });
@@ -554,7 +783,7 @@ async function patternsCommand() {
554
783
  }
555
784
  function shortHelpCommand() {
556
785
  console.log('');
557
- console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(` — ${TAGLINE}`));
786
+ console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(` — 62 agentic tools. 50+ specialists. Zero cost.`));
558
787
  console.log('');
559
788
  console.log(c.bold(' CLI Commands'));
560
789
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
@@ -564,6 +793,8 @@ function shortHelpCommand() {
564
793
  console.log(` ${c.cyan('veto sessions')} List last 20 saved sessions`);
565
794
  console.log(` ${c.cyan('veto memory')} ${c.dim('[query]')} Search knowledge base`);
566
795
  console.log(` ${c.cyan('veto patterns')} ${c.dim('[prefix]')} List learned agent/routing patterns`);
796
+ console.log(` ${c.cyan('veto routing')} ${c.dim('[status|enable|disable|reset|log]')}`);
797
+ console.log(` Routing feedback loop (opt-in signal storage)`);
567
798
  console.log(` ${c.cyan('veto version')} Show version (alias for status)`);
568
799
  console.log(` ${c.cyan('veto hook install')} Install pre-commit secrets scan hook`);
569
800
  console.log(` ${c.cyan('veto hook remove')} Remove the veto pre-commit hook`);
@@ -571,26 +802,20 @@ function shortHelpCommand() {
571
802
  console.log(` ${c.cyan('veto help')} Show this help`);
572
803
  console.log(` ${c.cyan('veto help --troubleshoot')} Show troubleshooting guide`);
573
804
  console.log('');
574
- console.log(c.bold(' MCP Tools (49)'));
805
+ console.log(c.bold(' MCP Tools (62 Agentic Tools)'));
575
806
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
576
- console.log(` ${c.dim('Session')} veto_status · veto_autosave_status · veto_session_save · veto_session_restore · veto_sessions_list`);
577
- console.log(` ${c.dim('Router')} veto_route_task · veto_rate_status`);
578
- console.log(` ${c.dim('Council')} veto_council_debate · veto_benchmark`);
579
- console.log(` ${c.dim('Agents')} veto_agent_plan · veto_execute_parallel · veto_explain`);
580
- console.log(` ${c.dim('Review')} veto_code_review · veto_security_scan · veto_secrets_scan · veto_diff_review`);
581
- console.log(` ${c.dim('Pipeline')} veto_workflow`);
582
- console.log(` ${c.dim('Watch')} veto_watch · veto_watch_poll · veto_watch_stop`);
583
- console.log(` ${c.dim('Memory')} veto_memory_store · veto_memory_search · veto_memory_delete`);
584
- console.log(` veto_project_map_update · veto_project_map_get`);
585
- console.log(` veto_pattern_store · veto_patterns_list`);
586
- console.log(` veto_memory_export · veto_memory_import`);
587
- console.log(` ${c.dim('Learning')} veto_record_outcome · veto_learning_stats · veto_learning_apply`);
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`);
807
+ console.log(` ${c.dim('Session')} veto_status · veto_session_save · veto_session_restore · veto_sessions_list · veto_session_replay · veto_autosave_status`);
808
+ console.log(` ${c.dim('Council')} veto_council_debate · veto_benchmark · veto_adr`);
809
+ console.log(` ${c.dim('Intelligence')} veto_agent_plan · veto_execute_parallel · veto_explain · veto_delegate · veto_compose_agents`);
810
+ console.log(` ${c.dim('Scanning')} veto_code_review · veto_security_scan · veto_secrets_scan · veto_diff_review · veto_full_review · veto_pr_review`);
811
+ console.log(` ${c.dim('Pipelines')} veto_workflow · veto_task_parse · veto_new_feature · veto_pre_commit · veto_ci_gate`);
812
+ console.log(` ${c.dim('Watching')} veto_watch · veto_watch_poll · veto_watch_stop`);
813
+ console.log(` ${c.dim('Advanced')} veto_local_llm · veto_semantic_search · veto_sdd_agent · veto_playwright · veto_notify_ide · veto_translate · veto_a11y_advisor`);
814
+ console.log(` ${c.dim('Quality')} veto_type_coverage · veto_test_gaps · veto_clone_detector · veto_lint_rules · veto_api_contract`);
815
+ console.log(` ${c.dim('Discovery')} veto_discover · veto_summarize · veto_git_blame · veto_changelog · veto_onboard · veto_debt_register`);
816
+ console.log(` ${c.dim('DevTools')} veto_docs_fetch · veto_context_status · veto_openapi_gen · veto_flag_auditor · veto_env_setup · veto_diagram · veto_rca`);
817
+ console.log(` veto_commit_message · veto_pr_description · veto_pr_post · veto_prompt_optimizer · veto_sre_advisor · veto_merge_conflict`);
818
+ 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
819
  console.log('');
595
820
  console.log(c.bold(' MCP Resources'));
596
821
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
@@ -602,6 +827,7 @@ function shortHelpCommand() {
602
827
  console.log(c.bold(' MCP Prompts'));
603
828
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
604
829
  console.log(` ${c.cyan('code-review')} · ${c.cyan('security-audit')} · ${c.cyan('deploy-checklist')} · ${c.cyan('explain-file')}`);
830
+ console.log(` ${c.cyan('full-review')} · ${c.cyan('new-feature')} · ${c.cyan('debug-incident')} · ${c.cyan('onboard')}`);
605
831
  console.log('');
606
832
  console.log(c.bold(' Docs & Support'));
607
833
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
@@ -679,6 +905,84 @@ function troubleshootCommand() {
679
905
  console.log(` ${c.dim('→')} Then restart the AI client on that machine`);
680
906
  console.log('');
681
907
  }
908
+ // ─── Routing Command ────────────────────────────────────────────────────────────
909
+ async function routingCommand() {
910
+ const { getRoutingFeedbackStats, resetRoutingFeedback, listRoutingFeedback, isFeedbackEnabled, setFeedbackEnabled } = await import('./router/learning-updater.js');
911
+ const sub = process.argv[3];
912
+ if (sub === 'enable') {
913
+ setFeedbackEnabled(true);
914
+ console.log('');
915
+ console.log(c.green(' ✓ Routing feedback enabled.'));
916
+ console.log(c.dim(' Every veto_route_task call now records a routing signal (30-day TTL).'));
917
+ console.log(c.dim(' Disable with: veto routing disable | Clear with: veto routing reset'));
918
+ console.log('');
919
+ return;
920
+ }
921
+ if (sub === 'disable') {
922
+ setFeedbackEnabled(false);
923
+ console.log('');
924
+ console.log(c.yellow(' ✓ Routing feedback disabled.'));
925
+ console.log(c.dim(' No new signals will be recorded. Existing data is retained.'));
926
+ console.log(c.dim(' Re-enable with: veto routing enable'));
927
+ console.log('');
928
+ return;
929
+ }
930
+ if (sub === 'reset') {
931
+ const result = resetRoutingFeedback();
932
+ console.log('');
933
+ console.log(c.green(' ✓ Routing feedback reset.'));
934
+ console.log(` ${c.dim('Deleted:')} ${c.cyan(String(result.deleted_feedback))} feedback signal${result.deleted_feedback !== 1 ? 's' : ''}`);
935
+ if (result.reset_thresholds) {
936
+ console.log(` ${c.dim('Thresholds:')} reset to defaults (30/70)`);
937
+ }
938
+ console.log('');
939
+ return;
940
+ }
941
+ if (sub === 'log') {
942
+ const limit = parseInt(process.argv[4] ?? '20', 10);
943
+ const entries = listRoutingFeedback(isNaN(limit) ? 20 : limit);
944
+ console.log('');
945
+ console.log(c.bold(' Routing Feedback Log') + c.dim(` (${entries.length})`));
946
+ console.log(c.dim(' ─────────────────────────────────────────────────────────────'));
947
+ if (entries.length === 0) {
948
+ console.log(c.dim(' No feedback signals yet. Enable feedback: veto routing enable'));
949
+ }
950
+ else {
951
+ for (const e of entries) {
952
+ const outcomeColor = e.outcome === 'accepted' ? c.green : e.outcome === 'overridden' ? c.yellow : c.dim;
953
+ const exp = new Date(e.expires_at).toLocaleDateString();
954
+ 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)}`);
955
+ console.log(` ${c.dim(` expires: ${exp} agent: ${e.agent ?? 'dynamic'}`)}`);
956
+ console.log('');
957
+ }
958
+ }
959
+ return;
960
+ }
961
+ // Default: status
962
+ const stats = getRoutingFeedbackStats();
963
+ const enabled = isFeedbackEnabled();
964
+ const statusStr = enabled ? c.green('enabled') : c.dim('disabled');
965
+ console.log('');
966
+ console.log(c.bold(' Routing Feedback') + c.dim(' — loop status'));
967
+ console.log(c.dim(' ─────────────────────────────────────────────────────'));
968
+ console.log(` Status ${statusStr}`);
969
+ console.log(` TTL ${c.cyan(String(stats.ttl_days))} days`);
970
+ console.log(` Signals ${c.cyan(String(stats.active))} active · ${c.dim(String(stats.expired))} expired · ${String(stats.total)} total`);
971
+ if (Object.keys(stats.by_outcome).length > 0) {
972
+ const parts = Object.entries(stats.by_outcome).map(([k, v]) => `${k}: ${v}`).join(' · ');
973
+ console.log(` Outcomes ${c.dim(parts)}`);
974
+ }
975
+ if (Object.keys(stats.by_tier).length > 0) {
976
+ const parts = Object.entries(stats.by_tier).map(([tier, s]) => `T${tier}: ${s.count} (q${s.avg_quality ?? '-'})`).join(' · ');
977
+ console.log(` By tier ${c.dim(parts)}`);
978
+ }
979
+ if (stats.next_expiry) {
980
+ console.log(` Next expiry ${c.dim(new Date(stats.next_expiry).toLocaleDateString())}`);
981
+ }
982
+ console.log('');
983
+ console.log(c.dim(` Commands: veto routing enable · veto routing disable · veto routing reset · veto routing log`));
984
+ console.log('');
985
+ }
682
986
  // ─── Hook installer ────────────────────────────────────────────────────────────
683
987
  async function hookCommand() {
684
988
  const sub = process.argv[3];
@@ -831,6 +1135,12 @@ switch (command) {
831
1135
  process.exit(1);
832
1136
  });
833
1137
  break;
1138
+ case 'routing':
1139
+ routingCommand().catch((err) => {
1140
+ console.error(c.red(`Error: ${err.message}`));
1141
+ process.exit(1);
1142
+ });
1143
+ break;
834
1144
  case 'hook':
835
1145
  hookCommand().catch((err) => {
836
1146
  console.error(c.red(`Error: ${err.message}`));