@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.
- package/LAUNCH-KIT.md +37 -22
- package/LICENSE +21 -0
- package/README.md +15 -5
- package/dist/cli/statusline.d.ts +54 -0
- package/dist/cli/statusline.d.ts.map +1 -0
- package/dist/cli/statusline.js +418 -0
- package/dist/cli/statusline.js.map +1 -0
- package/dist/cli.js +69 -5
- package/dist/cli.js.map +1 -1
- package/dist/memory/local.d.ts +7 -0
- package/dist/memory/local.d.ts.map +1 -1
- package/dist/memory/local.js +9 -1
- package/dist/memory/local.js.map +1 -1
- package/dist/memory/schema.d.ts +1 -0
- package/dist/memory/schema.d.ts.map +1 -1
- package/dist/memory/schema.js +16 -0
- package/dist/memory/schema.js.map +1 -1
- package/dist/server/handlers/observability.d.ts.map +1 -1
- package/dist/server/handlers/observability.js +60 -1
- package/dist/server/handlers/observability.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/definitions.d.ts +13 -0
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +14 -0
- package/dist/tools/definitions.js.map +1 -1
- package/package.json +2 -2
- package/server.json +3 -3
|
@@ -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 = '
|
|
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.
|
|
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(` —
|
|
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 (
|
|
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}`));
|