@jigyasudham/veto 2.5.0 → 2.7.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.
@@ -0,0 +1,418 @@
1
+ // veto statusline — a compact, always-on Veto line beneath the AI CLI prompt.
2
+ //
3
+ // Lives in the CLI (not the VS Code extension) so EVERY Veto user gets it in any
4
+ // terminal. Claude Code natively supports a custom `statusLine` command in
5
+ // settings.json; `veto statusline install` wires this command in.
6
+ //
7
+ // The `print` subcommand is a HOT PATH: it runs on every prompt render, so it
8
+ // must be read-only, fast (<50ms), and crash-proof. It opens a dedicated
9
+ // read-only DB connection (no migrations, no table creation, no writes) and on
10
+ // ANY problem — missing DB, locked DB (WAL / SQLITE_BUSY), bad row — it prints a
11
+ // neutral `⬡ veto` and exits 0. It never throws and never blocks the prompt.
12
+ import { createRequire } from 'node:module';
13
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, appendFileSync } from 'node:fs';
14
+ import { join, dirname } from 'node:path';
15
+ import { homedir } from 'node:os';
16
+ import { getDbPath, getDb } from '../memory/local.js';
17
+ // node:sqlite is a Node 22.5+ built-in — use createRequire so bundlers skip it.
18
+ const _require = createRequire(import.meta.url);
19
+ const DbSync = _require('node:sqlite').DatabaseSync;
20
+ const EMPTY = {
21
+ verdict: null, routerPct: null, contextPct: null, rate5hPct: null, rate7dPct: null, memCount: null,
22
+ };
23
+ // Open the veto DB read-only. Returns null if it can't (missing/locked/corrupt).
24
+ function openReadOnly(path) {
25
+ try {
26
+ const db = new DbSync(path, { readOnly: true });
27
+ // query_only is belt-and-suspenders; busy_timeout keeps us from blocking the
28
+ // prompt if a writer holds the WAL lock — fail fast to the neutral fallback.
29
+ db.exec('PRAGMA query_only = ON');
30
+ db.exec('PRAGMA busy_timeout = 50');
31
+ return db;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ // Crash-proof read of everything the statusline shows. Never throws.
38
+ export function readStatuslineData() {
39
+ let db = null;
40
+ let closeAfter = false;
41
+ try {
42
+ const path = getDbPath();
43
+ if (path === ':memory:') {
44
+ // In-memory (tests / special cases): a fresh read-only handle would be a
45
+ // different empty DB, so reuse the shared reader.
46
+ db = getDb();
47
+ }
48
+ else {
49
+ if (!existsSync(path))
50
+ return EMPTY;
51
+ db = openReadOnly(path);
52
+ closeAfter = true;
53
+ if (!db)
54
+ return EMPTY;
55
+ }
56
+ return queryStatusline(db);
57
+ }
58
+ catch {
59
+ return EMPTY;
60
+ }
61
+ finally {
62
+ if (closeAfter && db) {
63
+ try {
64
+ db.close();
65
+ }
66
+ catch { /* ignore */ }
67
+ }
68
+ }
69
+ }
70
+ function queryStatusline(db) {
71
+ const data = { ...EMPTY };
72
+ // Each block is independently guarded: a missing/older table degrades that one
73
+ // segment to null rather than blanking the whole line.
74
+ try {
75
+ const row = db.prepare('SELECT verdict FROM council_outcomes ORDER BY debated_at DESC LIMIT 1').get();
76
+ const v = (row?.verdict ?? '').toUpperCase();
77
+ if (v === 'GREEN' || v === 'YELLOW' || v === 'RED')
78
+ data.verdict = v;
79
+ }
80
+ catch { /* segment off */ }
81
+ try {
82
+ // Top confidence among learned patterns. Exclude router.* threshold rows and
83
+ // composed_agent:* definitions — those carry config/JSON, not a learning score.
84
+ const row = db.prepare(`SELECT confidence FROM patterns
85
+ WHERE pattern_key NOT LIKE 'router.%' AND pattern_key NOT LIKE 'composed_agent:%'
86
+ ORDER BY confidence DESC, seen_count DESC LIMIT 1`).get();
87
+ if (typeof row?.confidence === 'number') {
88
+ data.routerPct = Math.max(0, Math.min(100, Math.round(row.confidence * 100)));
89
+ }
90
+ }
91
+ catch { /* segment off */ }
92
+ // NOTE: live context-window usage (data.contextPct) is intentionally NOT read
93
+ // here — it comes from the JSON Claude Code pipes to `statusline print` on stdin,
94
+ // not from the DB. The old "platform N%" segment read rate_usage.token_count,
95
+ // which only Veto's own tools increment, so it sat frozen during normal use. That
96
+ // segment was removed; printStatusline() overlays the real per-render number.
97
+ try {
98
+ const row = db.prepare('SELECT COUNT(*) AS n FROM knowledge_base').get();
99
+ if (typeof row?.n === 'number')
100
+ data.memCount = row.n;
101
+ }
102
+ catch { /* segment off */ }
103
+ return data;
104
+ }
105
+ const ANSI = {
106
+ reset: '\x1b[0m',
107
+ dim: '\x1b[2m',
108
+ green: '\x1b[32m',
109
+ yellow: '\x1b[33m',
110
+ red: '\x1b[31m',
111
+ };
112
+ export function composeStatusline(data, opts = {}) {
113
+ const color = opts.color ?? !process.env.NO_COLOR;
114
+ const ascii = opts.ascii ?? Boolean(process.env.VETO_STATUSLINE_ASCII);
115
+ const paint = (s, code) => (color ? `${code}${s}${ANSI.reset}` : s);
116
+ const head = `${ascii ? '#' : '⬡'} veto`;
117
+ const segments = [];
118
+ if (data.verdict) {
119
+ const code = data.verdict === 'GREEN' ? ANSI.green
120
+ : data.verdict === 'YELLOW' ? ANSI.yellow
121
+ : ANSI.red;
122
+ segments.push(paint(data.verdict, code));
123
+ }
124
+ if (data.routerPct !== null) {
125
+ segments.push(`router ${data.routerPct}%`);
126
+ }
127
+ // Live "headroom" gauges from Claude Code's stdin payload. All three warn as they
128
+ // fill up — yellow ≥70, red ≥90 — since each is a budget you're consuming.
129
+ const gauge = (prefix, pct) => {
130
+ const label = `${prefix} ${pct}%`;
131
+ const code = pct >= 90 ? ANSI.red : pct >= 70 ? ANSI.yellow : '';
132
+ return code ? paint(label, code) : label;
133
+ };
134
+ if (data.contextPct !== null)
135
+ segments.push(gauge('ctx', data.contextPct)); // context-window used
136
+ if (data.rate5hPct !== null)
137
+ segments.push(gauge('5h', data.rate5hPct)); // 5-hour rate limit used
138
+ if (data.rate7dPct !== null)
139
+ segments.push(gauge('7d', data.rate7dPct)); // weekly rate limit used
140
+ if (data.memCount !== null) {
141
+ segments.push(`mem ${data.memCount}`);
142
+ }
143
+ if (segments.length === 0)
144
+ return head; // neutral fallback
145
+ return `${head} ${segments.join(' · ')}`;
146
+ }
147
+ // Coerce a payload percentage to a clean 0..100 integer, or null for anything
148
+ // unexpected (missing, null early in the session / right after /compact, NaN).
149
+ function pctOrNull(v) {
150
+ return typeof v === 'number' && Number.isFinite(v) ? Math.max(0, Math.min(100, Math.round(v))) : null;
151
+ }
152
+ // Parse all live gauges from the stdin payload in one pass. Never throws — bad/empty
153
+ // JSON yields all-null so every segment simply drops rather than showing a wrong value.
154
+ export function parseClaudeInput(raw) {
155
+ try {
156
+ const j = JSON.parse(raw);
157
+ return {
158
+ contextPct: pctOrNull(j?.context_window?.used_percentage),
159
+ rate5hPct: pctOrNull(j?.rate_limits?.five_hour?.used_percentage),
160
+ rate7dPct: pctOrNull(j?.rate_limits?.seven_day?.used_percentage),
161
+ };
162
+ }
163
+ catch {
164
+ return { contextPct: null, rate5hPct: null, rate7dPct: null };
165
+ }
166
+ }
167
+ // Focused helper kept for callers that only need context usage.
168
+ export function parseClaudeContextPct(raw) {
169
+ return parseClaudeInput(raw).contextPct;
170
+ }
171
+ // Read the stdin payload Claude Code sends. Crash-proof and never blocks the prompt:
172
+ // returns null immediately when run from a TTY (manual invocation) and bails after a
173
+ // short timeout if no data arrives. Claude Code closes stdin after writing, so the
174
+ // 'end' path is the normal case.
175
+ function readStdinPayload(timeoutMs = 200) {
176
+ return new Promise((resolve) => {
177
+ const stdin = process.stdin;
178
+ if (stdin.isTTY) {
179
+ resolve(null);
180
+ return;
181
+ }
182
+ let data = '';
183
+ let settled = false;
184
+ const done = (v) => { if (!settled) {
185
+ settled = true;
186
+ resolve(v);
187
+ } };
188
+ const timer = setTimeout(() => done(null), timeoutMs);
189
+ timer.unref?.();
190
+ try {
191
+ stdin.setEncoding('utf8');
192
+ stdin.on('data', (c) => { data += c; });
193
+ stdin.on('end', () => { clearTimeout(timer); done(data || null); });
194
+ stdin.on('error', () => { clearTimeout(timer); done(null); });
195
+ }
196
+ catch {
197
+ clearTimeout(timer);
198
+ done(null);
199
+ }
200
+ });
201
+ }
202
+ // The hot path: read DB + live stdin, render, print. Never throws, always exits 0.
203
+ // `capturePath` (the `--capture <file>` flag) is a verification aid: it appends the
204
+ // raw payload Claude Code sent and the line we rendered, so you can diff the ACTUAL
205
+ // context_window.used_percentage against the displayed `ctx N%`. Never on by default.
206
+ export async function printStatusline(opts = {}, capturePath) {
207
+ let data;
208
+ try {
209
+ data = readStatuslineData();
210
+ }
211
+ catch {
212
+ data = { ...EMPTY };
213
+ }
214
+ let raw = null;
215
+ try {
216
+ raw = await readStdinPayload();
217
+ if (raw)
218
+ data = { ...data, ...parseClaudeInput(raw) };
219
+ }
220
+ catch { /* live segments stay null */ }
221
+ let line;
222
+ try {
223
+ line = composeStatusline(data, opts);
224
+ }
225
+ catch {
226
+ line = composeStatusline(EMPTY, opts);
227
+ }
228
+ if (capturePath) {
229
+ // Best-effort, never blocks or crashes the render.
230
+ try {
231
+ const actual = raw ? (() => { try {
232
+ return JSON.parse(raw).context_window?.used_percentage ?? null;
233
+ }
234
+ catch {
235
+ return null;
236
+ } })() : null;
237
+ appendFileSync(capturePath, `${new Date().toISOString()}\tactual_used_percentage=${actual}\trendered=${JSON.stringify(line)}\tpayload=${raw ?? '<none>'}\n`, 'utf8');
238
+ }
239
+ catch { /* capture is diagnostic only */ }
240
+ }
241
+ // Flush before returning so the caller can exit immediately without truncating
242
+ // output. A statusLine command runs on every prompt render; the process must not
243
+ // linger holding an open stdin handle if the parent keeps the pipe open (the line
244
+ // still prints on time regardless — see the 200ms timeout in readStdinPayload).
245
+ await new Promise((resolve) => {
246
+ try {
247
+ process.stdout.write(line + '\n', () => resolve());
248
+ }
249
+ catch {
250
+ resolve();
251
+ }
252
+ });
253
+ }
254
+ // Resolve the settings.json for a client. Only Claude Code exposes a documented
255
+ // `statusLine` command hook today; others are gated behind --client as a stretch.
256
+ function resolveClient(client) {
257
+ const HOME = homedir();
258
+ switch (client) {
259
+ case 'claude':
260
+ // VETO_STATUSLINE_SETTINGS overrides the path (used by tests).
261
+ return {
262
+ name: 'Claude Code',
263
+ settingsPath: process.env.VETO_STATUSLINE_SETTINGS ?? join(HOME, '.claude', 'settings.json'),
264
+ };
265
+ default:
266
+ return null;
267
+ }
268
+ }
269
+ const STATUSLINE_VALUE = { type: 'command', command: 'veto statusline print' };
270
+ const BACKUP_SUFFIX = '.veto-statusline-backup';
271
+ const NO_ORIGINAL = '__VETO_NO_ORIGINAL_FILE__';
272
+ function isOurStatusLine(v) {
273
+ return Boolean(v) && typeof v === 'object'
274
+ && v.command === STATUSLINE_VALUE.command;
275
+ }
276
+ export function installStatusline(client = 'claude', opts = {}) {
277
+ const target = resolveClient(client);
278
+ if (!target) {
279
+ return { ok: false, message: `Unknown client "${client}". Supported: claude.` };
280
+ }
281
+ const { settingsPath } = target;
282
+ const existed = existsSync(settingsPath);
283
+ let settings = {};
284
+ let rawOriginal = '';
285
+ if (existed) {
286
+ try {
287
+ rawOriginal = readFileSync(settingsPath, 'utf8');
288
+ settings = JSON.parse(rawOriginal);
289
+ }
290
+ catch {
291
+ return { ok: false, message: `Refusing to touch ${settingsPath}: it is not valid JSON.` };
292
+ }
293
+ }
294
+ const current = settings.statusLine;
295
+ if (isOurStatusLine(current)) {
296
+ return { ok: true, changed: false, message: `Already installed for ${target.name} (${settingsPath}).` };
297
+ }
298
+ if (current !== undefined && !opts.force) {
299
+ return {
300
+ ok: false,
301
+ message: `${target.name} already has a custom statusLine. Re-run with --force to replace it `
302
+ + `(your original is backed up and restored on uninstall).`,
303
+ };
304
+ }
305
+ if (opts.dryRun) {
306
+ return {
307
+ ok: true,
308
+ changed: false,
309
+ message: `[dry-run] Would set statusLine → ${JSON.stringify(STATUSLINE_VALUE)} in ${settingsPath}`
310
+ + (current !== undefined ? ` (replacing existing statusLine).` : `.`),
311
+ };
312
+ }
313
+ // Back up byte-for-byte so uninstall can restore exactly. Only create the
314
+ // backup once (a re-install must not overwrite the true original).
315
+ const backupPath = settingsPath + BACKUP_SUFFIX;
316
+ if (!existsSync(backupPath)) {
317
+ writeFileSync(backupPath, existed ? rawOriginal : NO_ORIGINAL, 'utf8');
318
+ }
319
+ settings.statusLine = { ...STATUSLINE_VALUE };
320
+ if (!existed)
321
+ mkdirSync(dirname(settingsPath), { recursive: true });
322
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
323
+ return {
324
+ ok: true,
325
+ changed: true,
326
+ backupPath,
327
+ message: `Installed Veto statusline for ${target.name}.\n ${settingsPath}\n backup: ${backupPath}`
328
+ + (current !== undefined ? `\n (replaced your previous statusLine — restored on uninstall)` : ``),
329
+ };
330
+ }
331
+ export function uninstallStatusline(client = 'claude') {
332
+ const target = resolveClient(client);
333
+ if (!target) {
334
+ return { ok: false, message: `Unknown client "${client}". Supported: claude.` };
335
+ }
336
+ const { settingsPath } = target;
337
+ const backupPath = settingsPath + BACKUP_SUFFIX;
338
+ if (existsSync(backupPath)) {
339
+ const backup = readFileSync(backupPath, 'utf8');
340
+ if (backup === NO_ORIGINAL) {
341
+ // There was no settings file before us — remove our key; delete the file if
342
+ // it now holds nothing else.
343
+ if (existsSync(settingsPath)) {
344
+ try {
345
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
346
+ delete settings.statusLine;
347
+ if (Object.keys(settings).length === 0) {
348
+ unlinkSync(settingsPath);
349
+ }
350
+ else {
351
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
352
+ }
353
+ }
354
+ catch { /* leave as-is if unreadable */ }
355
+ }
356
+ }
357
+ else {
358
+ // Restore the original file byte-for-byte.
359
+ writeFileSync(settingsPath, backup, 'utf8');
360
+ }
361
+ unlinkSync(backupPath);
362
+ return { ok: true, changed: true, message: `Uninstalled Veto statusline for ${target.name} (restored ${settingsPath}).` };
363
+ }
364
+ // No backup — best-effort removal of our key only.
365
+ if (existsSync(settingsPath)) {
366
+ try {
367
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
368
+ if (isOurStatusLine(settings.statusLine)) {
369
+ delete settings.statusLine;
370
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
371
+ return { ok: true, changed: true, message: `Removed Veto statusline from ${settingsPath}.` };
372
+ }
373
+ }
374
+ catch { /* fall through */ }
375
+ }
376
+ return { ok: true, changed: false, message: `Veto statusline was not installed for ${target.name}.` };
377
+ }
378
+ // Cheap, DB-free "is our statusLine wired into settings.json?" check. Safe to call
379
+ // at server startup — never throws, never opens the DB.
380
+ export function isStatuslineInstalled(client = 'claude') {
381
+ const target = resolveClient(client);
382
+ if (!target || !existsSync(target.settingsPath))
383
+ return false;
384
+ try {
385
+ const settings = JSON.parse(readFileSync(target.settingsPath, 'utf8'));
386
+ return isOurStatusLine(settings.statusLine);
387
+ }
388
+ catch {
389
+ return false;
390
+ }
391
+ }
392
+ export function statuslineStatusInfo(client = 'claude') {
393
+ const target = resolveClient(client);
394
+ const sample = composeStatusline(readStatuslineData());
395
+ if (!target)
396
+ return { installed: false, settingsPath: null, sample };
397
+ return { installed: isStatuslineInstalled(client), settingsPath: target.settingsPath, sample };
398
+ }
399
+ // First-run setup nudge surfaced to the agent through the MCP server `instructions`
400
+ // field. An MCP server speaks JSON-RPC over stdio — it can't print a `[y/N]` prompt
401
+ // or read a keystroke — so the protocol-correct way to "ask on first connect" is to
402
+ // hand the offer to the agent, which asks the user and runs the install on consent.
403
+ // Returns undefined once the statusline is installed, so the nudge self-resolves and
404
+ // stops appearing. We never edit settings.json without the user agreeing.
405
+ export function statuslineSetupInstruction(client = 'claude') {
406
+ if (isStatuslineInstalled(client))
407
+ return undefined;
408
+ return [
409
+ 'SETUP TIP — Veto status line (mention once per session; drop it if the user declines).',
410
+ 'Veto ships an always-on status line for Claude Code that renders beneath the prompt',
411
+ '(latest council verdict · top router-pattern confidence · daily token-budget % · memory',
412
+ 'entry count). It is NOT yet enabled in this install. If the user would like it, offer to',
413
+ 'run `veto statusline install` for them — it backs up settings.json and is reversible with',
414
+ '`veto statusline uninstall`, and the line appears after the next CLI restart. Do not',
415
+ 'install it unless the user agrees.',
416
+ ].join(' ');
417
+ }
418
+ //# sourceMappingURL=statusline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusline.js","sourceRoot":"","sources":["../../src/cli/statusline.ts"],"names":[],"mappings":"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"}
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 = '92 agentic tools. 49 specialists. Every major AI CLI. Self-learning. Zero extra cost on subscriptions.';
12
+ const TAGLINE = '93 agentic tools. 49 specialists. Every major AI CLI. Self-learning. Zero extra cost on subscriptions.';
13
13
  const VETO_DIR = join(homedir(), '.veto');
14
14
  const HOME = homedir();
15
15
  const c = {
@@ -307,7 +307,7 @@ async function initCommand() {
307
307
  console.log('');
308
308
  const VETO_GUIDE = `# Veto MCP Server
309
309
 
310
- Veto is active. 92 tools across 6 categories:
310
+ Veto is active. 93 tools across 6 categories:
311
311
 
312
312
  **Session & Context** — veto_status · veto_session_save · veto_continue · veto_handoff
313
313
  Save work at 60–70% context capacity. veto_status triggers auto-save above 70%.
@@ -863,9 +863,65 @@ async function patternsCommand() {
863
863
  }
864
864
  console.log('');
865
865
  }
866
+ async function statuslineCommand() {
867
+ const sub = process.argv[3] ?? 'status';
868
+ const args = process.argv.slice(4);
869
+ const clientArg = args.find(a => a.startsWith('--client='))?.split('=')[1] ?? 'claude';
870
+ const force = args.includes('--force') || args.includes('--yes') || args.includes('-y');
871
+ const dryRun = args.includes('--dry-run');
872
+ const sl = await import('./cli/statusline.js');
873
+ // Hot path: one line to stdout, nothing else. No banner, no colors-config noise.
874
+ if (sub === 'print') {
875
+ // --capture <file>: verification aid — log the raw Claude Code payload next to
876
+ // the rendered line so you can compare the actual context % against `ctx N%`.
877
+ const capIdx = args.indexOf('--capture');
878
+ const capturePath = capIdx !== -1 ? args[capIdx + 1] : undefined;
879
+ await sl.printStatusline({}, capturePath);
880
+ // Exit promptly: the line is already flushed, and we must not linger holding an
881
+ // open stdin handle if the parent kept the pipe open on this per-render hot path.
882
+ process.exit(0);
883
+ }
884
+ if (sub === 'install') {
885
+ const r = sl.installStatusline(clientArg, { force, dryRun });
886
+ console.log('');
887
+ console.log((r.ok ? c.green(' ✓ ') : c.red(' ✗ ')) + r.message.replace(/\n/g, '\n '));
888
+ if (r.ok && r.changed)
889
+ console.log(c.dim('\n Restart your AI CLI to see the Veto line. Remove with: veto statusline uninstall'));
890
+ console.log('');
891
+ if (!r.ok)
892
+ process.exit(1);
893
+ return;
894
+ }
895
+ if (sub === 'uninstall') {
896
+ const r = sl.uninstallStatusline(clientArg);
897
+ console.log('');
898
+ console.log((r.ok ? c.green(' ✓ ') : c.red(' ✗ ')) + r.message);
899
+ console.log('');
900
+ if (!r.ok)
901
+ process.exit(1);
902
+ return;
903
+ }
904
+ if (sub === 'status') {
905
+ const info = sl.statuslineStatusInfo(clientArg);
906
+ console.log('');
907
+ console.log(c.bold(' Veto Statusline'));
908
+ console.log(c.dim(' ─────────────────────────────────────────────────────'));
909
+ console.log(` Installed: ${info.installed ? c.green('yes') : c.dim('no')}`);
910
+ if (info.settingsPath)
911
+ console.log(` Settings: ${c.dim(info.settingsPath)}`);
912
+ console.log(` Sample: ${info.sample}`);
913
+ console.log('');
914
+ console.log(c.dim(' Install: veto statusline install [--client=claude] [--force] [--dry-run]'));
915
+ console.log('');
916
+ return;
917
+ }
918
+ console.error(c.red(` Unknown statusline subcommand: ${sub}`));
919
+ console.error(c.dim(' Usage: veto statusline <install|uninstall|print|status>'));
920
+ process.exit(1);
921
+ }
866
922
  function shortHelpCommand() {
867
923
  console.log('');
868
- console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(` — 92 agentic tools. 49 specialists. Every major AI CLI. Zero extra cost on subscriptions.`));
924
+ console.log(c.bold(c.cyan(' veto')) + c.dim(` v${VERSION}`) + c.dim(` — 93 agentic tools. 49 specialists. Every major AI CLI. Zero extra cost on subscriptions.`));
869
925
  console.log('');
870
926
  console.log(c.bold(' CLI Commands'));
871
927
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
@@ -879,6 +935,8 @@ function shortHelpCommand() {
879
935
  console.log(` ${c.cyan('veto patterns')} ${c.dim('[prefix]')} List learned agent/routing patterns`);
880
936
  console.log(` ${c.cyan('veto routing')} ${c.dim('[status|enable|disable|reset|log]')}`);
881
937
  console.log(` Routing feedback loop (opt-in signal storage)`);
938
+ console.log(` ${c.cyan('veto statusline')} ${c.dim('[install|uninstall|print|status]')}`);
939
+ console.log(` Compact Veto line under your AI CLI prompt`);
882
940
  console.log(` ${c.cyan('veto version')} Show version (alias for status)`);
883
941
  console.log(` ${c.cyan('veto hook install')} Install pre-commit secrets scan hook`);
884
942
  console.log(` ${c.cyan('veto hook remove')} Remove the veto pre-commit hook`);
@@ -886,9 +944,9 @@ function shortHelpCommand() {
886
944
  console.log(` ${c.cyan('veto help')} Show this help`);
887
945
  console.log(` ${c.cyan('veto help --troubleshoot')} Show troubleshooting guide`);
888
946
  console.log('');
889
- console.log(c.bold(' MCP Tools (92 Agentic Tools)'));
947
+ console.log(c.bold(' MCP Tools (93 Agentic Tools)'));
890
948
  console.log(c.dim(' ─────────────────────────────────────────────────────'));
891
- console.log(` ${c.dim('Session')} veto_status · veto_session_save · veto_session_restore · veto_sessions_list · veto_session_replay · veto_autosave_status`);
949
+ console.log(` ${c.dim('Session')} veto_status · veto_session_save · veto_session_restore · veto_sessions_list · veto_session_replay · veto_autosave_status · veto_snapshot`);
892
950
  console.log(` ${c.dim('Council')} veto_council_debate · veto_benchmark · veto_adr`);
893
951
  console.log(` ${c.dim('Intelligence')} veto_agent_plan · veto_execute_parallel · veto_explain · veto_delegate · veto_compose_agents`);
894
952
  console.log(` ${c.dim('Scanning')} veto_code_review · veto_security_scan · veto_secrets_scan · veto_diff_review · veto_full_review · veto_pr_review`);
@@ -1331,6 +1389,12 @@ switch (command) {
1331
1389
  process.exit(1);
1332
1390
  });
1333
1391
  break;
1392
+ case 'statusline':
1393
+ statuslineCommand().catch((err) => {
1394
+ console.error(c.red(`Error: ${err.message}`));
1395
+ process.exit(1);
1396
+ });
1397
+ break;
1334
1398
  case 'hook':
1335
1399
  hookCommand().catch((err) => {
1336
1400
  console.error(c.red(`Error: ${err.message}`));