@vibecheckai/cli 3.1.6 → 3.2.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/README.md +27 -32
- package/bin/registry.js +208 -343
- package/bin/runners/context/generators/mcp.js +18 -0
- package/bin/runners/context/index.js +72 -4
- package/bin/runners/context/proof-context.js +293 -1
- package/bin/runners/context/security-scanner.js +311 -73
- package/bin/runners/lib/analyzers.js +607 -20
- package/bin/runners/lib/detectors-v2.js +172 -15
- package/bin/runners/lib/entitlements-v2.js +48 -1
- package/bin/runners/lib/evidence-pack.js +678 -0
- package/bin/runners/lib/html-proof-report.js +913 -0
- package/bin/runners/lib/missions/plan.js +231 -41
- package/bin/runners/lib/missions/templates.js +125 -0
- package/bin/runners/lib/scan-output.js +492 -253
- package/bin/runners/lib/ship-output.js +901 -641
- package/bin/runners/runCheckpoint.js +44 -3
- package/bin/runners/runContext.d.ts +4 -0
- package/bin/runners/runContext.js +2 -3
- package/bin/runners/runDoctor.js +11 -4
- package/bin/runners/runFix.js +51 -341
- package/bin/runners/runInit.js +37 -20
- package/bin/runners/runPolish.d.ts +4 -0
- package/bin/runners/runPolish.js +608 -29
- package/bin/runners/runProve.js +210 -25
- package/bin/runners/runReality.js +861 -107
- package/bin/runners/runScan.js +238 -4
- package/bin/runners/runShip.js +19 -3
- package/bin/runners/runWatch.js +25 -5
- package/bin/vibecheck.js +35 -47
- package/mcp-server/consolidated-tools.js +408 -42
- package/mcp-server/index.js +152 -15
- package/mcp-server/package.json +1 -1
- package/mcp-server/proof-tools.js +571 -0
- package/mcp-server/tier-auth.js +22 -19
- package/mcp-server/tools-v3.js +744 -0
- package/mcp-server/truth-firewall-tools.js +190 -4
- package/package.json +3 -1
- package/bin/runners/runBadge.js +0 -916
- package/bin/runners/runContracts.js +0 -105
- package/bin/runners/runCtx.js +0 -680
- package/bin/runners/runCtxDiff.js +0 -301
- package/bin/runners/runCtxGuard.js +0 -176
- package/bin/runners/runCtxSync.js +0 -116
- package/bin/runners/runExport.js +0 -93
- package/bin/runners/runGraph.js +0 -454
- package/bin/runners/runInstall.js +0 -273
- package/bin/runners/runLabs.js +0 -341
- package/bin/runners/runLaunch.js +0 -181
- package/bin/runners/runPR.js +0 -255
- package/bin/runners/runPermissions.js +0 -310
- package/bin/runners/runPreflight.js +0 -580
- package/bin/runners/runReplay.js +0 -499
- package/bin/runners/runSecurity.js +0 -92
- package/bin/runners/runShare.js +0 -212
- package/bin/runners/runStatus.js +0 -102
- package/bin/runners/runVerify.js +0 -272
package/bin/runners/runShare.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck share - Generate Shareable Proof Bundles
|
|
3
|
-
*
|
|
4
|
-
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
-
* ENTERPRISE EDITION - World-Class Terminal Experience
|
|
6
|
-
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require("fs");
|
|
10
|
-
const path = require("path");
|
|
11
|
-
const { buildSharePack, findLatestMissionDir } = require("./lib/share-pack");
|
|
12
|
-
|
|
13
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
14
|
-
// ADVANCED TERMINAL - ANSI CODES & UTILITIES
|
|
15
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
16
|
-
|
|
17
|
-
const c = {
|
|
18
|
-
reset: '\x1b[0m',
|
|
19
|
-
bold: '\x1b[1m',
|
|
20
|
-
dim: '\x1b[2m',
|
|
21
|
-
italic: '\x1b[3m',
|
|
22
|
-
red: '\x1b[31m',
|
|
23
|
-
green: '\x1b[32m',
|
|
24
|
-
yellow: '\x1b[33m',
|
|
25
|
-
blue: '\x1b[34m',
|
|
26
|
-
magenta: '\x1b[35m',
|
|
27
|
-
cyan: '\x1b[36m',
|
|
28
|
-
white: '\x1b[37m',
|
|
29
|
-
gray: '\x1b[90m',
|
|
30
|
-
clearLine: '\x1b[2K',
|
|
31
|
-
hideCursor: '\x1b[?25l',
|
|
32
|
-
showCursor: '\x1b[?25h',
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
|
|
36
|
-
|
|
37
|
-
const colors = {
|
|
38
|
-
gradient1: rgb(100, 255, 200),
|
|
39
|
-
gradient2: rgb(80, 235, 180),
|
|
40
|
-
gradient3: rgb(60, 215, 160),
|
|
41
|
-
shipGreen: rgb(0, 255, 150),
|
|
42
|
-
warnAmber: rgb(255, 200, 0),
|
|
43
|
-
blockRed: rgb(255, 80, 80),
|
|
44
|
-
accent: rgb(100, 255, 200),
|
|
45
|
-
muted: rgb(120, 120, 140),
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
49
|
-
// PREMIUM BANNER
|
|
50
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
51
|
-
|
|
52
|
-
const SHARE_BANNER = `
|
|
53
|
-
${rgb(100, 255, 200)} ███████╗██╗ ██╗ █████╗ ██████╗ ███████╗${c.reset}
|
|
54
|
-
${rgb(80, 235, 180)} ██╔════╝██║ ██║██╔══██╗██╔══██╗██╔════╝${c.reset}
|
|
55
|
-
${rgb(60, 215, 160)} ███████╗███████║███████║██████╔╝█████╗ ${c.reset}
|
|
56
|
-
${rgb(40, 195, 140)} ╚════██║██╔══██║██╔══██║██╔══██╗██╔══╝ ${c.reset}
|
|
57
|
-
${rgb(20, 175, 120)} ███████║██║ ██║██║ ██║██║ ██║███████╗${c.reset}
|
|
58
|
-
${rgb(0, 155, 100)} ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝${c.reset}
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
|
-
const BANNER_FULL = `
|
|
62
|
-
${rgb(100, 255, 200)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${c.reset}
|
|
63
|
-
${rgb(90, 245, 190)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${c.reset}
|
|
64
|
-
${rgb(80, 235, 180)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${c.reset}
|
|
65
|
-
${rgb(60, 215, 160)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${c.reset}
|
|
66
|
-
${rgb(40, 195, 140)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${c.reset}
|
|
67
|
-
${rgb(20, 175, 120)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${c.reset}
|
|
68
|
-
|
|
69
|
-
${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
|
|
70
|
-
${c.dim} │${c.reset} ${rgb(100, 255, 200)}📤${c.reset} ${c.bold}SHARE${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}Proof Bundles${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}PR Comments${c.reset} ${c.dim}•${c.reset} ${rgb(100, 100, 100)}Collaboration${c.reset} ${c.dim}│${c.reset}
|
|
71
|
-
${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
|
|
72
|
-
`;
|
|
73
|
-
|
|
74
|
-
const ICONS = {
|
|
75
|
-
share: '📤',
|
|
76
|
-
package: '📦',
|
|
77
|
-
file: '📄',
|
|
78
|
-
check: '✓',
|
|
79
|
-
cross: '✗',
|
|
80
|
-
warning: '⚠',
|
|
81
|
-
arrow: '→',
|
|
82
|
-
bullet: '•',
|
|
83
|
-
github: '🐙',
|
|
84
|
-
sparkle: '✨',
|
|
85
|
-
folder: '📁',
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
function printDivider(char = '─', width = 69, color = c.dim) {
|
|
89
|
-
console.log(`${color} ${char.repeat(width)}${c.reset}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function printSection(title, icon = '◆') {
|
|
93
|
-
console.log();
|
|
94
|
-
console.log(` ${colors.accent}${icon}${c.reset} ${c.bold}${title}${c.reset}`);
|
|
95
|
-
printDivider();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function printHelp() {
|
|
99
|
-
console.log(BANNER_FULL);
|
|
100
|
-
console.log(`
|
|
101
|
-
${c.bold}Usage:${c.reset} vibecheck share [options]
|
|
102
|
-
|
|
103
|
-
${c.bold}Proof Bundles${c.reset} — Generate shareable mission proof for collaboration.
|
|
104
|
-
|
|
105
|
-
${c.bold}Options:${c.reset}
|
|
106
|
-
${colors.accent}--mission-dir <path>${c.reset} Specific mission directory to share
|
|
107
|
-
${colors.accent}--output-dir <path>${c.reset} Output directory for share pack
|
|
108
|
-
${colors.accent}--pr-comment${c.reset} Print PR comment to stdout
|
|
109
|
-
${colors.accent}--help, -h${c.reset} Show this help
|
|
110
|
-
|
|
111
|
-
${c.bold}What It Does:${c.reset}
|
|
112
|
-
${colors.shipGreen}1.${c.reset} Finds latest mission pack from .vibecheck/missions/
|
|
113
|
-
${colors.shipGreen}2.${c.reset} Generates share bundle with:
|
|
114
|
-
${ICONS.file} ${colors.accent}share.json${c.reset} ${c.dim}Machine readable${c.reset}
|
|
115
|
-
${ICONS.file} ${colors.accent}share.md${c.reset} ${c.dim}Human readable${c.reset}
|
|
116
|
-
${ICONS.github} ${colors.accent}pr_comment.md${c.reset} ${c.dim}GitHub ready${c.reset}
|
|
117
|
-
|
|
118
|
-
${c.bold}Output Files:${c.reset}
|
|
119
|
-
${c.dim}.vibecheck/missions/<timestamp>/share/${c.reset}
|
|
120
|
-
${colors.accent}share.json${c.reset} ${c.dim}Mission data + findings${c.reset}
|
|
121
|
-
${colors.accent}share.md${c.reset} ${c.dim}Markdown summary${c.reset}
|
|
122
|
-
${colors.accent}pr_comment.md${c.reset} ${c.dim}Ready to paste into GitHub${c.reset}
|
|
123
|
-
|
|
124
|
-
${c.bold}Examples:${c.reset}
|
|
125
|
-
${c.dim}# Share latest mission${c.reset}
|
|
126
|
-
vibecheck share
|
|
127
|
-
|
|
128
|
-
${c.dim}# Print PR comment body${c.reset}
|
|
129
|
-
vibecheck share --pr-comment
|
|
130
|
-
|
|
131
|
-
${c.dim}# Fix then auto-share${c.reset}
|
|
132
|
-
vibecheck fix --autopilot --share
|
|
133
|
-
`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async function runShare(argsOrOpts = {}) {
|
|
137
|
-
// Handle array args from CLI
|
|
138
|
-
if (Array.isArray(argsOrOpts)) {
|
|
139
|
-
if (argsOrOpts.includes("--help") || argsOrOpts.includes("-h")) {
|
|
140
|
-
printHelp();
|
|
141
|
-
return 0;
|
|
142
|
-
}
|
|
143
|
-
const getArg = (flags) => {
|
|
144
|
-
for (const f of flags) {
|
|
145
|
-
const idx = argsOrOpts.indexOf(f);
|
|
146
|
-
if (idx !== -1 && idx < argsOrOpts.length - 1) return argsOrOpts[idx + 1];
|
|
147
|
-
}
|
|
148
|
-
return undefined;
|
|
149
|
-
};
|
|
150
|
-
argsOrOpts = {
|
|
151
|
-
missionDir: getArg(["--mission-dir"]),
|
|
152
|
-
outputDir: getArg(["--output-dir"]),
|
|
153
|
-
prComment: argsOrOpts.includes("--pr-comment"),
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const { repoRoot, missionDir, outputDir, prComment } = argsOrOpts;
|
|
158
|
-
const root = repoRoot || process.cwd();
|
|
159
|
-
const projectName = path.basename(root);
|
|
160
|
-
|
|
161
|
-
// Print banner
|
|
162
|
-
console.log(BANNER_FULL);
|
|
163
|
-
console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
|
|
164
|
-
console.log(` ${c.dim}Path:${c.reset} ${root}`);
|
|
165
|
-
console.log();
|
|
166
|
-
|
|
167
|
-
let resolvedMissionDir;
|
|
168
|
-
try {
|
|
169
|
-
resolvedMissionDir = missionDir
|
|
170
|
-
? (path.isAbsolute(missionDir) ? missionDir : path.join(root, missionDir))
|
|
171
|
-
: findLatestMissionDir(root);
|
|
172
|
-
} catch (e) {
|
|
173
|
-
console.log(` ${colors.blockRed}${ICONS.cross}${c.reset} ${c.bold}Error:${c.reset} ${e.message}`);
|
|
174
|
-
console.log();
|
|
175
|
-
console.log(` ${c.dim}Run ${colors.accent}vibecheck fix --autopilot${c.reset}${c.dim} first to generate mission packs.${c.reset}`);
|
|
176
|
-
console.log();
|
|
177
|
-
return 1;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const res = buildSharePack({
|
|
181
|
-
repoRoot: root,
|
|
182
|
-
missionDirAbs: resolvedMissionDir,
|
|
183
|
-
outputDirAbs: outputDir ? (path.isAbsolute(outputDir) ? outputDir : path.join(root, outputDir)) : null
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
printSection('SHARE BUNDLE', ICONS.package);
|
|
187
|
-
console.log();
|
|
188
|
-
console.log(` ${c.dim}Mission pack:${c.reset} ${colors.accent}${path.relative(root, res.missionDir).replace(/\\/g,"/")}${c.reset}`);
|
|
189
|
-
console.log(` ${c.dim}Output:${c.reset} ${colors.accent}${path.relative(root, res.outputDir).replace(/\\/g,"/")}${c.reset}`);
|
|
190
|
-
console.log();
|
|
191
|
-
console.log(` ${colors.shipGreen}${ICONS.check}${c.reset} ${ICONS.file} ${colors.accent}share.json${c.reset}`);
|
|
192
|
-
console.log(` ${colors.shipGreen}${ICONS.check}${c.reset} ${ICONS.file} ${colors.accent}share.md${c.reset}`);
|
|
193
|
-
console.log(` ${colors.shipGreen}${ICONS.check}${c.reset} ${ICONS.github} ${colors.accent}pr_comment.md${c.reset}`);
|
|
194
|
-
console.log();
|
|
195
|
-
|
|
196
|
-
if (prComment) {
|
|
197
|
-
printSection('PR COMMENT', ICONS.github);
|
|
198
|
-
console.log();
|
|
199
|
-
console.log(` ${c.dim}Paste into GitHub:${c.reset}`);
|
|
200
|
-
printDivider('─', 60);
|
|
201
|
-
console.log();
|
|
202
|
-
console.log(fs.readFileSync(res.files.prComment, "utf8"));
|
|
203
|
-
printDivider('─', 60);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
console.log(` ${colors.shipGreen}${ICONS.sparkle}${c.reset} Share bundle generated successfully`);
|
|
207
|
-
console.log();
|
|
208
|
-
|
|
209
|
-
return 0;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
module.exports = { runShare };
|
package/bin/runners/runStatus.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck status - Show current project status at a glance
|
|
3
|
-
*
|
|
4
|
-
* Displays:
|
|
5
|
-
* - Last ship verdict
|
|
6
|
-
* - Last reality run
|
|
7
|
-
* - Pending findings count
|
|
8
|
-
* - Config status
|
|
9
|
-
* - Quick health indicators
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
"use strict";
|
|
13
|
-
|
|
14
|
-
const fs = require("fs");
|
|
15
|
-
const path = require("path");
|
|
16
|
-
const { formatStatusOutput } = require("./lib/status-output");
|
|
17
|
-
const { parseGlobalFlags } = require("./lib/global-flags");
|
|
18
|
-
|
|
19
|
-
function readJsonSafe(p) {
|
|
20
|
-
try {
|
|
21
|
-
if (!fs.existsSync(p)) return null;
|
|
22
|
-
return JSON.parse(fs.readFileSync(p, "utf8"));
|
|
23
|
-
} catch {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function runStatus(args = []) {
|
|
29
|
-
// Parse global flags
|
|
30
|
-
const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
|
|
31
|
-
|
|
32
|
-
// Support both old API ({ repoRoot, json }) and new API (args array)
|
|
33
|
-
let repoRoot, json;
|
|
34
|
-
if (typeof args === 'object' && !Array.isArray(args) && args.repoRoot !== undefined) {
|
|
35
|
-
// Old API compatibility
|
|
36
|
-
repoRoot = args.repoRoot;
|
|
37
|
-
json = args.json || false;
|
|
38
|
-
} else {
|
|
39
|
-
// New API - parse from args
|
|
40
|
-
repoRoot = globalFlags.path || process.cwd();
|
|
41
|
-
json = globalFlags.json || false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const root = repoRoot || process.cwd();
|
|
45
|
-
|
|
46
|
-
// Gather data
|
|
47
|
-
const lastShip = readJsonSafe(path.join(root, ".vibecheck", "last_ship.json"));
|
|
48
|
-
const truthpack = readJsonSafe(path.join(root, ".vibecheck", "truth", "truthpack.json"));
|
|
49
|
-
const lastReality = readJsonSafe(path.join(root, ".vibecheck", "reality", "last_reality.json"));
|
|
50
|
-
const lastProve = readJsonSafe(path.join(root, ".vibecheck", "prove", "last_prove.json"));
|
|
51
|
-
const config = readJsonSafe(path.join(root, ".vibecheck", "config.json"));
|
|
52
|
-
|
|
53
|
-
// Count findings
|
|
54
|
-
const findings = lastShip?.findings || [];
|
|
55
|
-
const blocks = findings.filter(f => f.severity === "BLOCK").length;
|
|
56
|
-
const warns = findings.filter(f => f.severity === "WARN").length;
|
|
57
|
-
|
|
58
|
-
// Reality coverage
|
|
59
|
-
const coverage = lastReality?.coverage?.percent;
|
|
60
|
-
|
|
61
|
-
// Truthpack stats
|
|
62
|
-
const routes = truthpack?.routes?.server?.length || 0;
|
|
63
|
-
const envVars = truthpack?.env?.vars?.length || 0;
|
|
64
|
-
const gaps = truthpack?.routes?.gaps?.length || 0;
|
|
65
|
-
|
|
66
|
-
if (json) {
|
|
67
|
-
const status = {
|
|
68
|
-
verdict: lastShip?.meta?.verdict || null,
|
|
69
|
-
lastShipAt: lastShip?.meta?.generatedAt || null,
|
|
70
|
-
lastRealityAt: lastReality?.meta?.startedAt || null,
|
|
71
|
-
lastProveAt: lastProve?.meta?.startedAt || null,
|
|
72
|
-
findings: { BLOCK: blocks, WARN: warns },
|
|
73
|
-
truthpack: { routes, envVars, gaps },
|
|
74
|
-
coverage: coverage || null,
|
|
75
|
-
config: !!config
|
|
76
|
-
};
|
|
77
|
-
console.log(JSON.stringify(status, null, 2));
|
|
78
|
-
return 0;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const status = {
|
|
82
|
-
verdict: lastShip?.meta?.verdict || null,
|
|
83
|
-
lastShipAt: lastShip?.meta?.generatedAt || null,
|
|
84
|
-
blockers: blocks,
|
|
85
|
-
warnings: warns,
|
|
86
|
-
routes,
|
|
87
|
-
envVars,
|
|
88
|
-
gaps,
|
|
89
|
-
lastRealityAt: lastReality?.meta?.startedAt || null,
|
|
90
|
-
coverage: coverage || null,
|
|
91
|
-
hasTruthpack: !!truthpack,
|
|
92
|
-
hasReality: !!lastReality,
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
console.log(formatStatusOutput(status, { root }));
|
|
96
|
-
|
|
97
|
-
// Exit 0 when showing status successfully (even if no ship yet)
|
|
98
|
-
// Only return non-zero if explicitly checking for BLOCK
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
module.exports = { runStatus };
|
package/bin/runners/runVerify.js
DELETED
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* runVerify.js - CLI Verify Command
|
|
4
|
-
* Verifies AI-generated agent output against vibecheck-v1 protocol
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* vibecheck verify [options]
|
|
8
|
-
* vibecheck verify --input response.json
|
|
9
|
-
* vibecheck verify --stdin
|
|
10
|
-
* vibecheck verify --mode ship --strict
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
"use strict";
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const path = require('path');
|
|
17
|
-
const { parseArgs } = require('util');
|
|
18
|
-
|
|
19
|
-
const HELP = `
|
|
20
|
-
vibecheck verify - Verify AI-generated agent output
|
|
21
|
-
|
|
22
|
-
Usage:
|
|
23
|
-
vibecheck verify [options]
|
|
24
|
-
|
|
25
|
-
Options:
|
|
26
|
-
--input, -i <file> Input file containing agent response JSON
|
|
27
|
-
--stdin Read agent response from stdin
|
|
28
|
-
--root, -r <dir> Project root directory (default: cwd)
|
|
29
|
-
--mode, -m <mode> Verification mode: explore|build|ship (default: build)
|
|
30
|
-
--strict Enable strict mode (fail on warnings)
|
|
31
|
-
--json Output results as JSON
|
|
32
|
-
--help, -h Show this help message
|
|
33
|
-
|
|
34
|
-
Examples:
|
|
35
|
-
vibecheck verify --input agent-response.json
|
|
36
|
-
echo '{"format":"vibecheck-v1",...}' | vibecheck verify --stdin
|
|
37
|
-
vibecheck verify --input response.json --mode ship --strict
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
async function main() {
|
|
41
|
-
const { values, positionals } = parseArgs({
|
|
42
|
-
options: {
|
|
43
|
-
input: { type: 'string', short: 'i' },
|
|
44
|
-
stdin: { type: 'boolean', default: false },
|
|
45
|
-
root: { type: 'string', short: 'r' },
|
|
46
|
-
mode: { type: 'string', short: 'm', default: 'build' },
|
|
47
|
-
strict: { type: 'boolean', default: false },
|
|
48
|
-
json: { type: 'boolean', default: false },
|
|
49
|
-
help: { type: 'boolean', short: 'h' },
|
|
50
|
-
},
|
|
51
|
-
allowPositionals: true,
|
|
52
|
-
strict: false,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
if (values.help) {
|
|
56
|
-
console.log(HELP);
|
|
57
|
-
process.exit(0);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const projectRoot = values.root ? path.resolve(values.root) : process.cwd();
|
|
61
|
-
const mode = values.mode || 'build';
|
|
62
|
-
const strict = values.strict || false;
|
|
63
|
-
const outputJson = values.json || false;
|
|
64
|
-
|
|
65
|
-
// Validate mode
|
|
66
|
-
if (!['explore', 'build', 'ship'].includes(mode)) {
|
|
67
|
-
console.error(`Error: Invalid mode "${mode}". Must be one of: explore, build, ship`);
|
|
68
|
-
process.exit(2);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Get input
|
|
72
|
-
let rawInput = '';
|
|
73
|
-
|
|
74
|
-
if (values.stdin) {
|
|
75
|
-
rawInput = await readStdin();
|
|
76
|
-
} else if (values.input) {
|
|
77
|
-
const inputPath = path.resolve(values.input);
|
|
78
|
-
if (!fs.existsSync(inputPath)) {
|
|
79
|
-
console.error(`Error: Input file not found: ${inputPath}`);
|
|
80
|
-
process.exit(2);
|
|
81
|
-
}
|
|
82
|
-
rawInput = fs.readFileSync(inputPath, 'utf-8');
|
|
83
|
-
} else if (positionals.length > 0) {
|
|
84
|
-
// Allow positional argument as input file
|
|
85
|
-
const inputPath = path.resolve(positionals[0]);
|
|
86
|
-
if (!fs.existsSync(inputPath)) {
|
|
87
|
-
console.error(`Error: Input file not found: ${inputPath}`);
|
|
88
|
-
process.exit(2);
|
|
89
|
-
}
|
|
90
|
-
rawInput = fs.readFileSync(inputPath, 'utf-8');
|
|
91
|
-
} else {
|
|
92
|
-
console.error('Error: No input provided. Use --input <file> or --stdin');
|
|
93
|
-
console.log(HELP);
|
|
94
|
-
process.exit(2);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!rawInput.trim()) {
|
|
98
|
-
console.error('Error: Empty input');
|
|
99
|
-
process.exit(2);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Load the verification module
|
|
103
|
-
let validateFormat, verifyAgentOutput, formatCheckResults, buildJsonReport;
|
|
104
|
-
try {
|
|
105
|
-
// Try loading from the built TypeScript output
|
|
106
|
-
const verification = require('../../dist/lib/verification/index.js');
|
|
107
|
-
validateFormat = verification.validateFormat;
|
|
108
|
-
verifyAgentOutput = verification.verifyAgentOutput;
|
|
109
|
-
formatCheckResults = verification.formatCheckResults;
|
|
110
|
-
buildJsonReport = verification.buildJsonReport;
|
|
111
|
-
} catch (err) {
|
|
112
|
-
// Fallback: try loading directly (for development)
|
|
113
|
-
try {
|
|
114
|
-
const verification = require('../../src/lib/verification/index.ts');
|
|
115
|
-
validateFormat = verification.validateFormat;
|
|
116
|
-
verifyAgentOutput = verification.verifyAgentOutput;
|
|
117
|
-
formatCheckResults = verification.formatCheckResults;
|
|
118
|
-
buildJsonReport = verification.buildJsonReport;
|
|
119
|
-
} catch (err2) {
|
|
120
|
-
console.error('Error loading verification module:', err.message);
|
|
121
|
-
console.error('Make sure the project is built: pnpm build');
|
|
122
|
-
process.exit(2);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Step 1: Validate format
|
|
127
|
-
if (!outputJson) {
|
|
128
|
-
console.log('🔍 Validating agent output format...');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const formatResult = validateFormat(rawInput);
|
|
132
|
-
|
|
133
|
-
if (!formatResult.valid) {
|
|
134
|
-
if (outputJson) {
|
|
135
|
-
console.log(JSON.stringify({
|
|
136
|
-
status: 'fail',
|
|
137
|
-
phase: 'format-validation',
|
|
138
|
-
error: formatResult.error,
|
|
139
|
-
retryPrompt: formatResult.retryPrompt,
|
|
140
|
-
}, null, 2));
|
|
141
|
-
} else {
|
|
142
|
-
console.error('❌ Format validation failed:', formatResult.error);
|
|
143
|
-
console.error('\n📝 Retry prompt:');
|
|
144
|
-
console.error(formatResult.retryPrompt);
|
|
145
|
-
}
|
|
146
|
-
process.exit(2);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Check if it's an error response
|
|
150
|
-
if ('error' in formatResult && formatResult.error) {
|
|
151
|
-
if (outputJson) {
|
|
152
|
-
console.log(JSON.stringify({
|
|
153
|
-
status: 'error',
|
|
154
|
-
phase: 'agent-error',
|
|
155
|
-
error: formatResult.error.error,
|
|
156
|
-
}, null, 2));
|
|
157
|
-
} else {
|
|
158
|
-
console.log('⚠️ Agent returned an error response:');
|
|
159
|
-
console.log(formatResult.error.error);
|
|
160
|
-
}
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const agentOutput = formatResult.output;
|
|
165
|
-
|
|
166
|
-
if (!outputJson) {
|
|
167
|
-
console.log('✅ Format valid');
|
|
168
|
-
console.log(` Files in diff: ${countFilesInDiff(agentOutput.diff)}`);
|
|
169
|
-
console.log(` Commands: ${agentOutput.commands?.length || 0}`);
|
|
170
|
-
console.log(` Tests: ${agentOutput.tests?.length || 0}`);
|
|
171
|
-
console.log('');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Step 2: Run verification pipeline
|
|
175
|
-
if (!outputJson) {
|
|
176
|
-
console.log('🔬 Running verification pipeline...');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const context = {
|
|
180
|
-
projectRoot,
|
|
181
|
-
mode,
|
|
182
|
-
runTests: mode === 'ship',
|
|
183
|
-
strictMode: strict,
|
|
184
|
-
maxFilesChanged: mode === 'ship' ? 10 : mode === 'build' ? 20 : 50,
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
let result;
|
|
188
|
-
try {
|
|
189
|
-
result = await verifyAgentOutput(agentOutput, context);
|
|
190
|
-
} catch (err) {
|
|
191
|
-
if (outputJson) {
|
|
192
|
-
console.log(JSON.stringify({
|
|
193
|
-
status: 'fail',
|
|
194
|
-
phase: 'verification',
|
|
195
|
-
error: err.message,
|
|
196
|
-
}, null, 2));
|
|
197
|
-
} else {
|
|
198
|
-
console.error('❌ Verification error:', err.message);
|
|
199
|
-
}
|
|
200
|
-
process.exit(2);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Output results
|
|
204
|
-
if (outputJson) {
|
|
205
|
-
console.log(JSON.stringify(buildJsonReport(result), null, 2));
|
|
206
|
-
} else {
|
|
207
|
-
console.log('');
|
|
208
|
-
console.log(formatCheckResults(result.checks));
|
|
209
|
-
console.log('');
|
|
210
|
-
|
|
211
|
-
if (result.status === 'pass') {
|
|
212
|
-
console.log('✅ VERIFICATION PASSED');
|
|
213
|
-
} else if (result.status === 'warn') {
|
|
214
|
-
console.log('⚠️ VERIFICATION PASSED WITH WARNINGS');
|
|
215
|
-
} else {
|
|
216
|
-
console.log('❌ VERIFICATION FAILED');
|
|
217
|
-
if (result.failureContext) {
|
|
218
|
-
console.log('\n📝 Failure context for retry:');
|
|
219
|
-
console.log(result.failureContext);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Exit codes: 0 = pass, 1 = warn (if strict), 2 = fail
|
|
225
|
-
if (result.status === 'fail') {
|
|
226
|
-
process.exit(2);
|
|
227
|
-
} else if (result.status === 'warn' && strict) {
|
|
228
|
-
process.exit(1);
|
|
229
|
-
} else {
|
|
230
|
-
process.exit(0);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Read all input from stdin
|
|
236
|
-
*/
|
|
237
|
-
function readStdin() {
|
|
238
|
-
return new Promise((resolve, reject) => {
|
|
239
|
-
let data = '';
|
|
240
|
-
process.stdin.setEncoding('utf-8');
|
|
241
|
-
process.stdin.on('data', chunk => { data += chunk; });
|
|
242
|
-
process.stdin.on('end', () => resolve(data));
|
|
243
|
-
process.stdin.on('error', reject);
|
|
244
|
-
|
|
245
|
-
// Timeout after 5 seconds if no input
|
|
246
|
-
setTimeout(() => {
|
|
247
|
-
if (data === '') {
|
|
248
|
-
reject(new Error('No input received from stdin'));
|
|
249
|
-
}
|
|
250
|
-
}, 5000);
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Count files in a diff string
|
|
256
|
-
*/
|
|
257
|
-
function countFilesInDiff(diff) {
|
|
258
|
-
if (!diff) return 0;
|
|
259
|
-
const matches = diff.match(/^diff --git/gm);
|
|
260
|
-
return matches ? matches.length : 0;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Export for CLI registry
|
|
264
|
-
module.exports = { main };
|
|
265
|
-
|
|
266
|
-
// Run if executed directly
|
|
267
|
-
if (require.main === module) {
|
|
268
|
-
main().catch(err => {
|
|
269
|
-
console.error('Fatal error:', err.message);
|
|
270
|
-
process.exit(2);
|
|
271
|
-
});
|
|
272
|
-
}
|