@jigyasudham/veto 0.8.2 → 0.8.3
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/dist/cli.js +106 -46
- package/package.json +1 -1
- package/src/cli.ts +204 -135
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Veto CLI — entry point for `npx veto init`
|
|
3
3
|
// Suppress Node experimental warnings (node:sqlite) for clean UX
|
|
4
4
|
process.removeAllListeners('warning');
|
|
5
|
-
import { mkdirSync, existsSync } from 'node:fs';
|
|
6
|
-
import { join } from 'node:path';
|
|
5
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
|
-
const VERSION = '0.8.
|
|
8
|
+
const VERSION = '0.8.2';
|
|
9
9
|
const VETO_DIR = join(homedir(), '.veto');
|
|
10
|
-
|
|
10
|
+
const HOME = homedir();
|
|
11
11
|
const c = {
|
|
12
12
|
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
13
13
|
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
@@ -29,6 +29,70 @@ function printBanner() {
|
|
|
29
29
|
console.log(c.dim(` v${VERSION}`));
|
|
30
30
|
console.log('');
|
|
31
31
|
}
|
|
32
|
+
// Merge veto entry into an existing JSON config file, creating it if needed.
|
|
33
|
+
// Supports both "mcpServers" format (Claude/Gemini/Codex/Cursor/Windsurf)
|
|
34
|
+
// and "servers" format (VS Code).
|
|
35
|
+
function writeVetoConfig(configPath, format) {
|
|
36
|
+
let existing = {};
|
|
37
|
+
if (existsSync(configPath)) {
|
|
38
|
+
try {
|
|
39
|
+
existing = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Unreadable / invalid JSON — skip to avoid corrupting it
|
|
43
|
+
return 'skipped';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
48
|
+
}
|
|
49
|
+
const wasEmpty = Object.keys(existing).length === 0;
|
|
50
|
+
if (format === 'mcpServers') {
|
|
51
|
+
const servers = existing.mcpServers ?? {};
|
|
52
|
+
servers['veto'] = { command: 'veto-server' };
|
|
53
|
+
existing.mcpServers = servers;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const servers = existing.servers ?? {};
|
|
57
|
+
servers['veto'] = { type: 'stdio', command: 'veto-server' };
|
|
58
|
+
existing.servers = servers;
|
|
59
|
+
}
|
|
60
|
+
writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
61
|
+
return wasEmpty ? 'created' : 'updated';
|
|
62
|
+
}
|
|
63
|
+
// All platforms Veto supports, with their config paths and formats.
|
|
64
|
+
const PLATFORMS = [
|
|
65
|
+
{
|
|
66
|
+
name: 'Claude Code',
|
|
67
|
+
path: join(HOME, '.claude', 'mcp_servers.json'),
|
|
68
|
+
format: 'mcpServers',
|
|
69
|
+
detectionDir: join(HOME, '.claude'),
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Gemini CLI',
|
|
73
|
+
path: join(HOME, '.gemini', 'settings.json'),
|
|
74
|
+
format: 'mcpServers',
|
|
75
|
+
detectionDir: join(HOME, '.gemini'),
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'Codex CLI',
|
|
79
|
+
path: join(HOME, '.codex', 'config.json'),
|
|
80
|
+
format: 'mcpServers',
|
|
81
|
+
detectionDir: join(HOME, '.codex'),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'Cursor',
|
|
85
|
+
path: join(HOME, '.cursor', 'mcp.json'),
|
|
86
|
+
format: 'mcpServers',
|
|
87
|
+
detectionDir: join(HOME, '.cursor'),
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'Windsurf',
|
|
91
|
+
path: join(HOME, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
92
|
+
format: 'mcpServers',
|
|
93
|
+
detectionDir: join(HOME, '.codeium', 'windsurf'),
|
|
94
|
+
},
|
|
95
|
+
];
|
|
32
96
|
async function initCommand() {
|
|
33
97
|
printBanner();
|
|
34
98
|
// 1. Create ~/.veto directory
|
|
@@ -39,13 +103,12 @@ async function initCommand() {
|
|
|
39
103
|
else {
|
|
40
104
|
console.log(c.dim(' · ') + `Found existing ${VETO_DIR}`);
|
|
41
105
|
}
|
|
42
|
-
// 2. Initialize SQLite database
|
|
106
|
+
// 2. Initialize SQLite database
|
|
43
107
|
process.stdout.write(' · Initializing SQLite database...');
|
|
44
108
|
const { getDb, getDbPath, saveSession } = await import('./memory/local.js');
|
|
45
109
|
try {
|
|
46
110
|
const db = getDb();
|
|
47
111
|
const dbPath = getDbPath();
|
|
48
|
-
// Smoke test: save + retrieve a test session
|
|
49
112
|
const { session_id } = saveSession({
|
|
50
113
|
platform: 'claude',
|
|
51
114
|
summary: 'Veto initialized',
|
|
@@ -54,7 +117,6 @@ async function initCommand() {
|
|
|
54
117
|
const row = db.prepare('SELECT id FROM sessions WHERE id = ?').get(session_id);
|
|
55
118
|
if (!row)
|
|
56
119
|
throw new Error('DB smoke test failed');
|
|
57
|
-
// Clean up test row
|
|
58
120
|
db.prepare('DELETE FROM sessions WHERE id = ?').run(session_id);
|
|
59
121
|
console.log(c.green(' ✓'));
|
|
60
122
|
console.log(c.green(' ✓') + ` Database ready at ${dbPath}`);
|
|
@@ -65,48 +127,46 @@ async function initCommand() {
|
|
|
65
127
|
console.error(c.red(` Error initializing database: ${msg}`));
|
|
66
128
|
process.exit(1);
|
|
67
129
|
}
|
|
68
|
-
// 3.
|
|
69
|
-
console.log('');
|
|
70
|
-
console.log(c.bold(' ┌─ Add Veto to your AI CLI or IDE ───────────────────────────────┐'));
|
|
71
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
72
|
-
console.log(c.bold(' │') + ' Config file locations: ' + c.bold('│'));
|
|
73
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
74
|
-
console.log(c.bold(' │') + c.dim(' Claude Code → ~/.claude/mcp_servers.json') + ' ' + c.bold('│'));
|
|
75
|
-
console.log(c.bold(' │') + c.dim(' Gemini CLI → ~/.gemini/settings.json') + ' ' + c.bold('│'));
|
|
76
|
-
console.log(c.bold(' │') + c.dim(' Codex CLI → ~/.codex/config.json') + ' ' + c.bold('│'));
|
|
77
|
-
console.log(c.bold(' │') + c.dim(' Cursor → ~/.cursor/mcp.json') + ' ' + c.bold('│'));
|
|
78
|
-
console.log(c.bold(' │') + c.dim(' Windsurf → ~/.codeium/windsurf/mcp_config.json') + ' ' + c.bold('│'));
|
|
79
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
80
|
-
console.log(c.bold(' │') + ' Claude / Gemini / Codex / Cursor / Windsurf: ' + c.bold('│'));
|
|
81
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
82
|
-
console.log(c.bold(' │') + c.cyan(' {') + ' ' + c.bold('│'));
|
|
83
|
-
console.log(c.bold(' │') + c.cyan(' "mcpServers": {') + ' ' + c.bold('│'));
|
|
84
|
-
console.log(c.bold(' │') + c.cyan(' "veto": {') + ' ' + c.bold('│'));
|
|
85
|
-
console.log(c.bold(' │') + c.cyan(' "command": "veto-server"') + ' ' + c.bold('│'));
|
|
86
|
-
console.log(c.bold(' │') + c.cyan(' }') + ' ' + c.bold('│'));
|
|
87
|
-
console.log(c.bold(' │') + c.cyan(' }') + ' ' + c.bold('│'));
|
|
88
|
-
console.log(c.bold(' │') + c.cyan(' }') + ' ' + c.bold('│'));
|
|
89
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
90
|
-
console.log(c.bold(' │') + ' VS Code → .vscode/mcp.json: ' + c.bold('│'));
|
|
91
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
92
|
-
console.log(c.bold(' │') + c.cyan(' {') + ' ' + c.bold('│'));
|
|
93
|
-
console.log(c.bold(' │') + c.cyan(' "servers": {') + ' ' + c.bold('│'));
|
|
94
|
-
console.log(c.bold(' │') + c.cyan(' "veto": {') + ' ' + c.bold('│'));
|
|
95
|
-
console.log(c.bold(' │') + c.cyan(' "type": "stdio",') + ' ' + c.bold('│'));
|
|
96
|
-
console.log(c.bold(' │') + c.cyan(' "command": "veto-server"') + ' ' + c.bold('│'));
|
|
97
|
-
console.log(c.bold(' │') + c.cyan(' }') + ' ' + c.bold('│'));
|
|
98
|
-
console.log(c.bold(' │') + c.cyan(' }') + ' ' + c.bold('│'));
|
|
99
|
-
console.log(c.bold(' │') + c.cyan(' }') + ' ' + c.bold('│'));
|
|
100
|
-
console.log(c.bold(' │') + ' ' + c.bold('│'));
|
|
101
|
-
console.log(c.bold(' └────────────────────────────────────────────────────────────────┘'));
|
|
130
|
+
// 3. Auto-configure every AI CLI / IDE found on this machine
|
|
102
131
|
console.log('');
|
|
103
|
-
console.log(
|
|
132
|
+
console.log(' Configuring all AI tools found on this machine...');
|
|
104
133
|
console.log('');
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
134
|
+
let configured = 0;
|
|
135
|
+
let skipped = 0;
|
|
136
|
+
for (const platform of PLATFORMS) {
|
|
137
|
+
const detected = existsSync(platform.detectionDir);
|
|
138
|
+
if (!detected) {
|
|
139
|
+
console.log(c.dim(' · ') + c.dim(`${platform.name} — not installed, skipping`));
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const result = writeVetoConfig(platform.path, platform.format);
|
|
143
|
+
if (result === 'skipped') {
|
|
144
|
+
console.log(c.yellow(' ⚠ ') + `${platform.name} — config unreadable, skipped`);
|
|
145
|
+
skipped++;
|
|
146
|
+
}
|
|
147
|
+
else if (result === 'created') {
|
|
148
|
+
console.log(c.green(' ✓ ') + `${platform.name} — configured`);
|
|
149
|
+
configured++;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.log(c.green(' ✓ ') + `${platform.name} — updated`);
|
|
153
|
+
configured++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
109
156
|
console.log('');
|
|
157
|
+
if (configured === 0 && skipped === 0) {
|
|
158
|
+
console.log(c.yellow(' ⚠ No AI tools detected.'));
|
|
159
|
+
console.log(' Install Claude Code, Gemini CLI, or Codex CLI and run veto init again.');
|
|
160
|
+
console.log('');
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.log(c.green(` ✓ Veto configured for ${configured} tool${configured !== 1 ? 's' : ''}!`));
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log(' Next steps:');
|
|
166
|
+
console.log(c.dim(' 1.') + ' Restart your AI CLI or IDE');
|
|
167
|
+
console.log(c.dim(' 2.') + ' Run: veto_status — should return { "status": "running", "version": "' + VERSION + '" }');
|
|
168
|
+
console.log('');
|
|
169
|
+
}
|
|
110
170
|
}
|
|
111
171
|
// ─── Router ────────────────────────────────────────────────────────────────────
|
|
112
172
|
const command = process.argv[2] ?? 'init';
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -1,135 +1,204 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Veto CLI — entry point for `npx veto init`
|
|
3
|
-
|
|
4
|
-
// Suppress Node experimental warnings (node:sqlite) for clean UX
|
|
5
|
-
process.removeAllListeners('warning');
|
|
6
|
-
|
|
7
|
-
import { mkdirSync, existsSync } from 'node:fs';
|
|
8
|
-
import { join } from 'node:path';
|
|
9
|
-
import { homedir } from 'node:os';
|
|
10
|
-
|
|
11
|
-
const VERSION = '0.8.
|
|
12
|
-
const VETO_DIR = join(homedir(), '.veto');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const c = {
|
|
16
|
-
bold: (s: string) => `\x1b[1m${s}\x1b[0m`,
|
|
17
|
-
green: (s: string) => `\x1b[32m${s}\x1b[0m`,
|
|
18
|
-
yellow: (s: string) => `\x1b[33m${s}\x1b[0m`,
|
|
19
|
-
cyan: (s: string) => `\x1b[36m${s}\x1b[0m`,
|
|
20
|
-
dim: (s: string) => `\x1b[2m${s}\x1b[0m`,
|
|
21
|
-
red: (s: string) => `\x1b[31m${s}\x1b[0m`,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
function printBanner() {
|
|
25
|
-
console.log('');
|
|
26
|
-
console.log(c.bold(c.cyan(' ██╗ ██╗███████╗████████╗ ██████╗')));
|
|
27
|
-
console.log(c.bold(c.cyan(' ██║ ██║██╔════╝╚══██╔══╝██╔═══██╗')));
|
|
28
|
-
console.log(c.bold(c.cyan(' ██║ ██║█████╗ ██║ ██║ ██║')));
|
|
29
|
-
console.log(c.bold(c.cyan(' ╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║')));
|
|
30
|
-
console.log(c.bold(c.cyan(' ╚████╔╝ ███████╗ ██║ ╚██████╔╝')));
|
|
31
|
-
console.log(c.bold(c.cyan(' ╚═══╝ ╚══════╝ ╚═╝ ╚═════╝')));
|
|
32
|
-
console.log('');
|
|
33
|
-
console.log(c.dim(` 50 agents. 28 skills. 3 AIs. Self-learning. Zero extra cost.`));
|
|
34
|
-
console.log(c.dim(` v${VERSION}`));
|
|
35
|
-
console.log('');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Veto CLI — entry point for `npx veto init`
|
|
3
|
+
|
|
4
|
+
// Suppress Node experimental warnings (node:sqlite) for clean UX
|
|
5
|
+
process.removeAllListeners('warning');
|
|
6
|
+
|
|
7
|
+
import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { join, dirname } from 'node:path';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
|
|
11
|
+
const VERSION = '0.8.2';
|
|
12
|
+
const VETO_DIR = join(homedir(), '.veto');
|
|
13
|
+
const HOME = homedir();
|
|
14
|
+
|
|
15
|
+
const c = {
|
|
16
|
+
bold: (s: string) => `\x1b[1m${s}\x1b[0m`,
|
|
17
|
+
green: (s: string) => `\x1b[32m${s}\x1b[0m`,
|
|
18
|
+
yellow: (s: string) => `\x1b[33m${s}\x1b[0m`,
|
|
19
|
+
cyan: (s: string) => `\x1b[36m${s}\x1b[0m`,
|
|
20
|
+
dim: (s: string) => `\x1b[2m${s}\x1b[0m`,
|
|
21
|
+
red: (s: string) => `\x1b[31m${s}\x1b[0m`,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function printBanner() {
|
|
25
|
+
console.log('');
|
|
26
|
+
console.log(c.bold(c.cyan(' ██╗ ██╗███████╗████████╗ ██████╗')));
|
|
27
|
+
console.log(c.bold(c.cyan(' ██║ ██║██╔════╝╚══██╔══╝██╔═══██╗')));
|
|
28
|
+
console.log(c.bold(c.cyan(' ██║ ██║█████╗ ██║ ██║ ██║')));
|
|
29
|
+
console.log(c.bold(c.cyan(' ╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║')));
|
|
30
|
+
console.log(c.bold(c.cyan(' ╚████╔╝ ███████╗ ██║ ╚██████╔╝')));
|
|
31
|
+
console.log(c.bold(c.cyan(' ╚═══╝ ╚══════╝ ╚═╝ ╚═════╝')));
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(c.dim(` 50 agents. 28 skills. 3 AIs. Self-learning. Zero extra cost.`));
|
|
34
|
+
console.log(c.dim(` v${VERSION}`));
|
|
35
|
+
console.log('');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Merge veto entry into an existing JSON config file, creating it if needed.
|
|
39
|
+
// Supports both "mcpServers" format (Claude/Gemini/Codex/Cursor/Windsurf)
|
|
40
|
+
// and "servers" format (VS Code).
|
|
41
|
+
function writeVetoConfig(
|
|
42
|
+
configPath: string,
|
|
43
|
+
format: 'mcpServers' | 'servers'
|
|
44
|
+
): 'created' | 'updated' | 'skipped' {
|
|
45
|
+
let existing: Record<string, unknown> = {};
|
|
46
|
+
|
|
47
|
+
if (existsSync(configPath)) {
|
|
48
|
+
try {
|
|
49
|
+
existing = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
50
|
+
} catch {
|
|
51
|
+
// Unreadable / invalid JSON — skip to avoid corrupting it
|
|
52
|
+
return 'skipped';
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const wasEmpty = Object.keys(existing).length === 0;
|
|
59
|
+
|
|
60
|
+
if (format === 'mcpServers') {
|
|
61
|
+
const servers = (existing.mcpServers as Record<string, unknown>) ?? {};
|
|
62
|
+
servers['veto'] = { command: 'veto-server' };
|
|
63
|
+
existing.mcpServers = servers;
|
|
64
|
+
} else {
|
|
65
|
+
const servers = (existing.servers as Record<string, unknown>) ?? {};
|
|
66
|
+
servers['veto'] = { type: 'stdio', command: 'veto-server' };
|
|
67
|
+
existing.servers = servers;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
71
|
+
return wasEmpty ? 'created' : 'updated';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// All platforms Veto supports, with their config paths and formats.
|
|
75
|
+
const PLATFORMS = [
|
|
76
|
+
{
|
|
77
|
+
name: 'Claude Code',
|
|
78
|
+
path: join(HOME, '.claude', 'mcp_servers.json'),
|
|
79
|
+
format: 'mcpServers' as const,
|
|
80
|
+
detectionDir: join(HOME, '.claude'),
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'Gemini CLI',
|
|
84
|
+
path: join(HOME, '.gemini', 'settings.json'),
|
|
85
|
+
format: 'mcpServers' as const,
|
|
86
|
+
detectionDir: join(HOME, '.gemini'),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'Codex CLI',
|
|
90
|
+
path: join(HOME, '.codex', 'config.json'),
|
|
91
|
+
format: 'mcpServers' as const,
|
|
92
|
+
detectionDir: join(HOME, '.codex'),
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'Cursor',
|
|
96
|
+
path: join(HOME, '.cursor', 'mcp.json'),
|
|
97
|
+
format: 'mcpServers' as const,
|
|
98
|
+
detectionDir: join(HOME, '.cursor'),
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'Windsurf',
|
|
102
|
+
path: join(HOME, '.codeium', 'windsurf', 'mcp_config.json'),
|
|
103
|
+
format: 'mcpServers' as const,
|
|
104
|
+
detectionDir: join(HOME, '.codeium', 'windsurf'),
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
async function initCommand() {
|
|
109
|
+
printBanner();
|
|
110
|
+
|
|
111
|
+
// 1. Create ~/.veto directory
|
|
112
|
+
if (!existsSync(VETO_DIR)) {
|
|
113
|
+
mkdirSync(VETO_DIR, { recursive: true });
|
|
114
|
+
console.log(c.green(' ✓') + ` Created ${VETO_DIR}`);
|
|
115
|
+
} else {
|
|
116
|
+
console.log(c.dim(' · ') + `Found existing ${VETO_DIR}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 2. Initialize SQLite database
|
|
120
|
+
process.stdout.write(' · Initializing SQLite database...');
|
|
121
|
+
const { getDb, getDbPath, saveSession } = await import('./memory/local.js');
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const db = getDb();
|
|
125
|
+
const dbPath = getDbPath();
|
|
126
|
+
const { session_id } = saveSession({
|
|
127
|
+
platform: 'claude',
|
|
128
|
+
summary: 'Veto initialized',
|
|
129
|
+
context: 'Initial setup via npx veto init',
|
|
130
|
+
});
|
|
131
|
+
const row = db.prepare('SELECT id FROM sessions WHERE id = ?').get(session_id);
|
|
132
|
+
if (!row) throw new Error('DB smoke test failed');
|
|
133
|
+
db.prepare('DELETE FROM sessions WHERE id = ?').run(session_id);
|
|
134
|
+
console.log(c.green(' ✓'));
|
|
135
|
+
console.log(c.green(' ✓') + ` Database ready at ${dbPath}`);
|
|
136
|
+
} catch (err: unknown) {
|
|
137
|
+
console.log(c.red(' ✗'));
|
|
138
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
139
|
+
console.error(c.red(` Error initializing database: ${msg}`));
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 3. Auto-configure every AI CLI / IDE found on this machine
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(' Configuring all AI tools found on this machine...');
|
|
146
|
+
console.log('');
|
|
147
|
+
|
|
148
|
+
let configured = 0;
|
|
149
|
+
let skipped = 0;
|
|
150
|
+
|
|
151
|
+
for (const platform of PLATFORMS) {
|
|
152
|
+
const detected = existsSync(platform.detectionDir);
|
|
153
|
+
if (!detected) {
|
|
154
|
+
console.log(c.dim(' · ') + c.dim(`${platform.name} — not installed, skipping`));
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const result = writeVetoConfig(platform.path, platform.format);
|
|
159
|
+
|
|
160
|
+
if (result === 'skipped') {
|
|
161
|
+
console.log(c.yellow(' ⚠ ') + `${platform.name} — config unreadable, skipped`);
|
|
162
|
+
skipped++;
|
|
163
|
+
} else if (result === 'created') {
|
|
164
|
+
console.log(c.green(' ✓ ') + `${platform.name} — configured`);
|
|
165
|
+
configured++;
|
|
166
|
+
} else {
|
|
167
|
+
console.log(c.green(' ✓ ') + `${platform.name} — updated`);
|
|
168
|
+
configured++;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log('');
|
|
173
|
+
|
|
174
|
+
if (configured === 0 && skipped === 0) {
|
|
175
|
+
console.log(c.yellow(' ⚠ No AI tools detected.'));
|
|
176
|
+
console.log(' Install Claude Code, Gemini CLI, or Codex CLI and run veto init again.');
|
|
177
|
+
console.log('');
|
|
178
|
+
} else {
|
|
179
|
+
console.log(c.green(` ✓ Veto configured for ${configured} tool${configured !== 1 ? 's' : ''}!`));
|
|
180
|
+
console.log('');
|
|
181
|
+
console.log(' Next steps:');
|
|
182
|
+
console.log(c.dim(' 1.') + ' Restart your AI CLI or IDE');
|
|
183
|
+
console.log(c.dim(' 2.') + ' Run: veto_status — should return { "status": "running", "version": "' + VERSION + '" }');
|
|
184
|
+
console.log('');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ─── Router ────────────────────────────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
const command = process.argv[2] ?? 'init';
|
|
191
|
+
|
|
192
|
+
switch (command) {
|
|
193
|
+
case 'init':
|
|
194
|
+
initCommand().catch((err) => {
|
|
195
|
+
console.error(c.red(`Error: ${err.message}`));
|
|
196
|
+
process.exit(1);
|
|
197
|
+
});
|
|
198
|
+
break;
|
|
199
|
+
|
|
200
|
+
default:
|
|
201
|
+
console.error(`Unknown command: ${command}`);
|
|
202
|
+
console.log('Usage: veto init');
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|