@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
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck ctx diff - Contract Diff
|
|
3
|
-
*
|
|
4
|
-
* Shows detailed changes between current code and contracts.
|
|
5
|
-
* Useful for reviewing what would change before running ctx sync.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
"use strict";
|
|
9
|
-
|
|
10
|
-
const path = require("path");
|
|
11
|
-
const fs = require("fs");
|
|
12
|
-
const { buildTruthpack, loadTruthpack } = require("./lib/truth");
|
|
13
|
-
const {
|
|
14
|
-
buildAllContracts,
|
|
15
|
-
loadContracts,
|
|
16
|
-
diffAllContracts,
|
|
17
|
-
hasContractChanges
|
|
18
|
-
} = require("./lib/contracts");
|
|
19
|
-
|
|
20
|
-
const c = {
|
|
21
|
-
reset: '\x1b[0m',
|
|
22
|
-
bold: '\x1b[1m',
|
|
23
|
-
dim: '\x1b[2m',
|
|
24
|
-
green: '\x1b[32m',
|
|
25
|
-
yellow: '\x1b[33m',
|
|
26
|
-
cyan: '\x1b[36m',
|
|
27
|
-
red: '\x1b[31m',
|
|
28
|
-
blue: '\x1b[34m',
|
|
29
|
-
magenta: '\x1b[35m',
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
async function runCtxDiff(opts = {}) {
|
|
33
|
-
const root = path.resolve(opts.repoRoot || process.cwd());
|
|
34
|
-
|
|
35
|
-
console.log(`\n${c.cyan}${c.bold}📊 vibecheck ctx diff${c.reset}`);
|
|
36
|
-
console.log(`${c.dim}Comparing code against contracts...${c.reset}\n`);
|
|
37
|
-
|
|
38
|
-
// Load existing contracts
|
|
39
|
-
const existingContracts = loadContracts(root);
|
|
40
|
-
|
|
41
|
-
if (Object.keys(existingContracts).length === 0) {
|
|
42
|
-
console.log(`${c.yellow}⚠️ No contracts found${c.reset}`);
|
|
43
|
-
console.log(`${c.dim}Run 'vibecheck ctx sync' first to generate contracts${c.reset}\n`);
|
|
44
|
-
return 0;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Build truthpack
|
|
48
|
-
let truthpack = loadTruthpack(root);
|
|
49
|
-
if (!truthpack) {
|
|
50
|
-
console.log(`${c.dim}Building truthpack...${c.reset}`);
|
|
51
|
-
truthpack = await buildTruthpack({ repoRoot: root, fastifyEntry: opts.fastifyEntry });
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Build new contracts from current code
|
|
55
|
-
const newContracts = buildAllContracts(truthpack);
|
|
56
|
-
|
|
57
|
-
// Calculate diff
|
|
58
|
-
const diff = diffAllContracts(existingContracts, newContracts);
|
|
59
|
-
|
|
60
|
-
// Check if there are changes
|
|
61
|
-
if (!hasContractChanges(diff)) {
|
|
62
|
-
console.log(`${c.green}✓${c.reset} No drift detected - contracts match current code\n`);
|
|
63
|
-
return 0;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Print route diff
|
|
67
|
-
if (diff.routes) {
|
|
68
|
-
printRouteDiff(diff.routes, opts.verbose);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Print env diff
|
|
72
|
-
if (diff.env) {
|
|
73
|
-
printEnvDiff(diff.env, opts.verbose);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Print auth diff
|
|
77
|
-
if (diff.auth) {
|
|
78
|
-
printAuthDiff(diff.auth, opts.verbose);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Print external diff
|
|
82
|
-
if (diff.external) {
|
|
83
|
-
printExternalDiff(diff.external, opts.verbose);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Summary
|
|
87
|
-
const totalAdded = (diff.routes?.added?.length || 0) +
|
|
88
|
-
(diff.env?.added?.length || 0) +
|
|
89
|
-
(diff.auth?.protectedAdded?.length || 0) +
|
|
90
|
-
(diff.external?.added?.length || 0);
|
|
91
|
-
const totalRemoved = (diff.routes?.removed?.length || 0) +
|
|
92
|
-
(diff.env?.removed?.length || 0) +
|
|
93
|
-
(diff.auth?.protectedRemoved?.length || 0) +
|
|
94
|
-
(diff.external?.removed?.length || 0);
|
|
95
|
-
const totalChanged = (diff.routes?.changed?.length || 0) +
|
|
96
|
-
(diff.env?.changed?.length || 0);
|
|
97
|
-
|
|
98
|
-
console.log(`\n${c.bold}Summary${c.reset}`);
|
|
99
|
-
console.log(` ${c.green}+${totalAdded} added${c.reset} ${c.red}-${totalRemoved} removed${c.reset} ${c.yellow}~${totalChanged} changed${c.reset}`);
|
|
100
|
-
|
|
101
|
-
if (totalAdded > 0 || totalRemoved > 0 || totalChanged > 0) {
|
|
102
|
-
console.log(`\n${c.dim}Run 'vibecheck ctx sync' to update contracts${c.reset}`);
|
|
103
|
-
console.log(`${c.dim}Run 'vibecheck ship' to see if drift causes BLOCK${c.reset}\n`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// JSON output
|
|
107
|
-
if (opts.json) {
|
|
108
|
-
const jsonPath = path.join(root, ".vibecheck", "diff-result.json");
|
|
109
|
-
fs.mkdirSync(path.dirname(jsonPath), { recursive: true });
|
|
110
|
-
fs.writeFileSync(jsonPath, JSON.stringify({
|
|
111
|
-
hasDrift: true,
|
|
112
|
-
diff,
|
|
113
|
-
summary: { added: totalAdded, removed: totalRemoved, changed: totalChanged }
|
|
114
|
-
}, null, 2), "utf8");
|
|
115
|
-
console.log(`${c.dim}JSON output: .vibecheck/diff-result.json${c.reset}\n`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return totalRemoved > 0 || totalChanged > 0 ? 1 : 0;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function printRouteDiff(diff, verbose) {
|
|
122
|
-
const hasChanges = diff.added?.length || diff.removed?.length || diff.changed?.length;
|
|
123
|
-
if (!hasChanges) return;
|
|
124
|
-
|
|
125
|
-
console.log(`${c.bold}Routes${c.reset}`);
|
|
126
|
-
|
|
127
|
-
if (diff.added?.length) {
|
|
128
|
-
console.log(` ${c.green}+ ${diff.added.length} new routes${c.reset}`);
|
|
129
|
-
if (verbose) {
|
|
130
|
-
for (const r of diff.added.slice(0, 10)) {
|
|
131
|
-
console.log(` ${c.green}+${c.reset} ${r.method} ${r.path}`);
|
|
132
|
-
}
|
|
133
|
-
if (diff.added.length > 10) {
|
|
134
|
-
console.log(` ${c.dim}...and ${diff.added.length - 10} more${c.reset}`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (diff.removed?.length) {
|
|
140
|
-
console.log(` ${c.red}- ${diff.removed.length} removed routes${c.reset}`);
|
|
141
|
-
if (verbose) {
|
|
142
|
-
for (const r of diff.removed.slice(0, 10)) {
|
|
143
|
-
console.log(` ${c.red}-${c.reset} ${r.method} ${r.path}`);
|
|
144
|
-
}
|
|
145
|
-
if (diff.removed.length > 10) {
|
|
146
|
-
console.log(` ${c.dim}...and ${diff.removed.length - 10} more${c.reset}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (diff.changed?.length) {
|
|
152
|
-
console.log(` ${c.yellow}~ ${diff.changed.length} changed routes${c.reset}`);
|
|
153
|
-
if (verbose) {
|
|
154
|
-
for (const { before, after } of diff.changed.slice(0, 5)) {
|
|
155
|
-
console.log(` ${c.yellow}~${c.reset} ${before.path}: auth ${before.auth} → ${after.auth}`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function printEnvDiff(diff, verbose) {
|
|
162
|
-
const hasChanges = diff.added?.length || diff.removed?.length || diff.changed?.length;
|
|
163
|
-
if (!hasChanges) return;
|
|
164
|
-
|
|
165
|
-
console.log(`\n${c.bold}Environment Variables${c.reset}`);
|
|
166
|
-
|
|
167
|
-
if (diff.added?.length) {
|
|
168
|
-
console.log(` ${c.green}+ ${diff.added.length} new vars${c.reset}`);
|
|
169
|
-
if (verbose) {
|
|
170
|
-
for (const v of diff.added.slice(0, 10)) {
|
|
171
|
-
console.log(` ${c.green}+${c.reset} ${v.name}${v.required ? ' (required)' : ''}`);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (diff.removed?.length) {
|
|
177
|
-
console.log(` ${c.red}- ${diff.removed.length} removed vars${c.reset}`);
|
|
178
|
-
if (verbose) {
|
|
179
|
-
for (const v of diff.removed.slice(0, 10)) {
|
|
180
|
-
console.log(` ${c.red}-${c.reset} ${v.name}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (diff.changed?.length) {
|
|
186
|
-
console.log(` ${c.yellow}~ ${diff.changed.length} changed vars${c.reset}`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function printAuthDiff(diff, verbose) {
|
|
191
|
-
const hasChanges = diff.protectedAdded?.length || diff.protectedRemoved?.length;
|
|
192
|
-
if (!hasChanges) return;
|
|
193
|
-
|
|
194
|
-
console.log(`\n${c.bold}Auth Patterns${c.reset}`);
|
|
195
|
-
|
|
196
|
-
if (diff.protectedAdded?.length) {
|
|
197
|
-
console.log(` ${c.green}+ ${diff.protectedAdded.length} new protected patterns${c.reset}`);
|
|
198
|
-
if (verbose) {
|
|
199
|
-
for (const p of diff.protectedAdded.slice(0, 5)) {
|
|
200
|
-
console.log(` ${c.green}+${c.reset} ${p}`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (diff.protectedRemoved?.length) {
|
|
206
|
-
console.log(` ${c.red}- ${diff.protectedRemoved.length} removed patterns (security!)${c.reset}`);
|
|
207
|
-
if (verbose) {
|
|
208
|
-
for (const p of diff.protectedRemoved.slice(0, 5)) {
|
|
209
|
-
console.log(` ${c.red}-${c.reset} ${p}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function printExternalDiff(diff, verbose) {
|
|
216
|
-
const hasChanges = diff.added?.length || diff.removed?.length;
|
|
217
|
-
if (!hasChanges) return;
|
|
218
|
-
|
|
219
|
-
console.log(`\n${c.bold}External Services${c.reset}`);
|
|
220
|
-
|
|
221
|
-
if (diff.added?.length) {
|
|
222
|
-
console.log(` ${c.green}+ ${diff.added.length} new services${c.reset}`);
|
|
223
|
-
if (verbose) {
|
|
224
|
-
for (const s of diff.added) {
|
|
225
|
-
console.log(` ${c.green}+${c.reset} ${s.name}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (diff.removed?.length) {
|
|
231
|
-
console.log(` ${c.red}- ${diff.removed.length} removed services${c.reset}`);
|
|
232
|
-
if (verbose) {
|
|
233
|
-
for (const s of diff.removed) {
|
|
234
|
-
console.log(` ${c.red}-${c.reset} ${s.name}`);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function parseArgs(args) {
|
|
241
|
-
const opts = {
|
|
242
|
-
repoRoot: process.cwd(),
|
|
243
|
-
fastifyEntry: null,
|
|
244
|
-
json: false,
|
|
245
|
-
verbose: false,
|
|
246
|
-
help: false
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
for (let i = 0; i < args.length; i++) {
|
|
250
|
-
const arg = args[i];
|
|
251
|
-
if (arg === "--json") opts.json = true;
|
|
252
|
-
else if (arg === "--verbose" || arg === "-v") opts.verbose = true;
|
|
253
|
-
else if (arg === "--fastify-entry") opts.fastifyEntry = args[++i];
|
|
254
|
-
else if (arg === "--path" || arg === "-p") opts.repoRoot = args[++i];
|
|
255
|
-
else if (arg === "--help" || arg === "-h") opts.help = true;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return opts;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function printHelp() {
|
|
262
|
-
console.log(`
|
|
263
|
-
${c.cyan}${c.bold}📊 vibecheck ctx diff${c.reset} - Contract Diff
|
|
264
|
-
|
|
265
|
-
Shows what would change if you run 'vibecheck ctx sync'.
|
|
266
|
-
Useful for reviewing drift before committing.
|
|
267
|
-
|
|
268
|
-
${c.bold}USAGE${c.reset}
|
|
269
|
-
vibecheck ctx diff ${c.dim}# Show drift summary${c.reset}
|
|
270
|
-
vibecheck ctx diff --verbose ${c.dim}# Show detailed changes${c.reset}
|
|
271
|
-
vibecheck ctx diff --json ${c.dim}# Output JSON${c.reset}
|
|
272
|
-
|
|
273
|
-
${c.bold}OPTIONS${c.reset}
|
|
274
|
-
--verbose, -v Show detailed changes
|
|
275
|
-
--json Output JSON to .vibecheck/diff-result.json
|
|
276
|
-
--fastify-entry Fastify entry file
|
|
277
|
-
--path, -p Project path (default: current directory)
|
|
278
|
-
--help, -h Show this help
|
|
279
|
-
|
|
280
|
-
${c.bold}EXIT CODES${c.reset}
|
|
281
|
-
0 = No drift (or only additions)
|
|
282
|
-
1 = Drift detected (removals or changes)
|
|
283
|
-
|
|
284
|
-
${c.bold}EXAMPLES${c.reset}
|
|
285
|
-
vibecheck ctx diff ${c.dim}# Quick check${c.reset}
|
|
286
|
-
vibecheck ctx diff -v ${c.dim}# Detailed view${c.reset}
|
|
287
|
-
`);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
async function main(args) {
|
|
291
|
-
const opts = parseArgs(args);
|
|
292
|
-
|
|
293
|
-
if (opts.help) {
|
|
294
|
-
printHelp();
|
|
295
|
-
return 0;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return runCtxDiff(opts);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
module.exports = { runCtxDiff, main };
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck ctx guard - Context Contracts Guard
|
|
3
|
-
*
|
|
4
|
-
* CI gate that validates code against contracts.
|
|
5
|
-
* Blocks if:
|
|
6
|
-
* - New route usage not declared
|
|
7
|
-
* - Env var used not declared
|
|
8
|
-
* - Protected matcher changes without proof
|
|
9
|
-
* - Webhook without verification
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
"use strict";
|
|
13
|
-
|
|
14
|
-
const path = require("path");
|
|
15
|
-
const fs = require("fs");
|
|
16
|
-
const { buildTruthpack, loadTruthpack } = require("./lib/truth");
|
|
17
|
-
const {
|
|
18
|
-
loadContracts,
|
|
19
|
-
guardContracts,
|
|
20
|
-
getGuardSummary,
|
|
21
|
-
formatGuardResult
|
|
22
|
-
} = require("./lib/contracts");
|
|
23
|
-
|
|
24
|
-
const c = {
|
|
25
|
-
reset: '\x1b[0m',
|
|
26
|
-
bold: '\x1b[1m',
|
|
27
|
-
dim: '\x1b[2m',
|
|
28
|
-
green: '\x1b[32m',
|
|
29
|
-
yellow: '\x1b[33m',
|
|
30
|
-
cyan: '\x1b[36m',
|
|
31
|
-
red: '\x1b[31m',
|
|
32
|
-
blue: '\x1b[34m',
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
async function runCtxGuard(opts = {}) {
|
|
36
|
-
const root = path.resolve(opts.repoRoot || process.cwd());
|
|
37
|
-
|
|
38
|
-
console.log(`\n${c.cyan}${c.bold}🛡️ vibecheck ctx guard${c.reset}`);
|
|
39
|
-
console.log(`${c.dim}Validating code against contracts...${c.reset}\n`);
|
|
40
|
-
|
|
41
|
-
// Load contracts
|
|
42
|
-
const contracts = loadContracts(root);
|
|
43
|
-
|
|
44
|
-
if (Object.keys(contracts).length === 0) {
|
|
45
|
-
console.log(`${c.yellow}⚠️ No contracts found${c.reset}`);
|
|
46
|
-
console.log(`${c.dim}Run 'vibecheck ctx sync' first to generate contracts${c.reset}\n`);
|
|
47
|
-
return opts.failOnMissing ? 2 : 0;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Load or build truthpack
|
|
51
|
-
let truthpack = loadTruthpack(root);
|
|
52
|
-
if (!truthpack) {
|
|
53
|
-
console.log(`${c.dim}Building truthpack...${c.reset}`);
|
|
54
|
-
truthpack = await buildTruthpack({ repoRoot: root, fastifyEntry: opts.fastifyEntry });
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Run guard validation
|
|
58
|
-
const guardResult = guardContracts(contracts, truthpack, {
|
|
59
|
-
realityResults: opts.realityResults
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const summary = getGuardSummary(guardResult);
|
|
63
|
-
|
|
64
|
-
// Print results
|
|
65
|
-
console.log(`${c.bold}Contracts Loaded:${c.reset}`);
|
|
66
|
-
if (contracts.routes) console.log(` ✓ routes.json (${contracts.routes.routes?.length || 0} routes)`);
|
|
67
|
-
if (contracts.env) console.log(` ✓ env.json (${contracts.env.vars?.length || 0} vars)`);
|
|
68
|
-
if (contracts.auth) console.log(` ✓ auth.json (${contracts.auth.protectedPatterns?.length || 0} patterns)`);
|
|
69
|
-
if (contracts.external) console.log(` ✓ external.json (${contracts.external.services?.length || 0} services)`);
|
|
70
|
-
|
|
71
|
-
console.log("");
|
|
72
|
-
console.log(formatGuardResult(guardResult));
|
|
73
|
-
|
|
74
|
-
// Print verdict
|
|
75
|
-
console.log("");
|
|
76
|
-
if (summary.verdict === "PASS") {
|
|
77
|
-
console.log(`${c.green}✅ PASS${c.reset} - All contracts satisfied`);
|
|
78
|
-
} else if (summary.verdict === "WARN") {
|
|
79
|
-
console.log(`${c.yellow}⚠️ WARN${c.reset} - ${summary.summary.warns} warnings`);
|
|
80
|
-
} else {
|
|
81
|
-
console.log(`${c.red}🛑 BLOCK${c.reset} - ${summary.summary.blocks} violations`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// JSON output for CI
|
|
85
|
-
if (opts.json) {
|
|
86
|
-
const jsonPath = path.join(root, ".vibecheck", "guard-result.json");
|
|
87
|
-
fs.mkdirSync(path.dirname(jsonPath), { recursive: true });
|
|
88
|
-
fs.writeFileSync(jsonPath, JSON.stringify(summary, null, 2), "utf8");
|
|
89
|
-
console.log(`\n${c.dim}JSON output: .vibecheck/guard-result.json${c.reset}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log("");
|
|
93
|
-
|
|
94
|
-
// Return appropriate exit code
|
|
95
|
-
if (opts.failOnWarn && summary.verdict === "WARN") {
|
|
96
|
-
return 1;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return summary.exitCode;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function parseArgs(args) {
|
|
103
|
-
const opts = {
|
|
104
|
-
repoRoot: process.cwd(),
|
|
105
|
-
fastifyEntry: null,
|
|
106
|
-
json: false,
|
|
107
|
-
failOnWarn: false,
|
|
108
|
-
failOnMissing: false,
|
|
109
|
-
help: false
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
for (let i = 0; i < args.length; i++) {
|
|
113
|
-
const arg = args[i];
|
|
114
|
-
if (arg === "--json") opts.json = true;
|
|
115
|
-
else if (arg === "--fail-on-warn") opts.failOnWarn = true;
|
|
116
|
-
else if (arg === "--fail-on-missing") opts.failOnMissing = true;
|
|
117
|
-
else if (arg === "--fastify-entry") opts.fastifyEntry = args[++i];
|
|
118
|
-
else if (arg === "--path" || arg === "-p") opts.repoRoot = args[++i];
|
|
119
|
-
else if (arg === "--help" || arg === "-h") opts.help = true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return opts;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function printHelp() {
|
|
126
|
-
console.log(`
|
|
127
|
-
${c.cyan}${c.bold}🛡️ vibecheck ctx guard${c.reset} - Contract Guard (CI Gate)
|
|
128
|
-
|
|
129
|
-
Validates current code against contracts. Use in CI to block drift.
|
|
130
|
-
|
|
131
|
-
${c.bold}USAGE${c.reset}
|
|
132
|
-
vibecheck ctx guard ${c.dim}# Validate against contracts${c.reset}
|
|
133
|
-
vibecheck ctx guard --json ${c.dim}# Output JSON for CI${c.reset}
|
|
134
|
-
vibecheck ctx guard --fail-on-warn ${c.dim}# Exit 1 on warnings${c.reset}
|
|
135
|
-
|
|
136
|
-
${c.bold}OPTIONS${c.reset}
|
|
137
|
-
--json Output JSON result to .vibecheck/guard-result.json
|
|
138
|
-
--fail-on-warn Exit 1 on warnings (default: only blocks)
|
|
139
|
-
--fail-on-missing Exit 2 if no contracts exist
|
|
140
|
-
--fastify-entry Fastify entry file (e.g. src/server.ts)
|
|
141
|
-
--path, -p Project path (default: current directory)
|
|
142
|
-
--help, -h Show this help
|
|
143
|
-
|
|
144
|
-
${c.bold}VIOLATIONS (BLOCK)${c.reset}
|
|
145
|
-
• Route used in code but not in routes.json
|
|
146
|
-
• Webhook without signature verification
|
|
147
|
-
• Protected route accessible anonymously
|
|
148
|
-
|
|
149
|
-
${c.bold}WARNINGS${c.reset}
|
|
150
|
-
• Env var used but not in env.json
|
|
151
|
-
• Required env var not used
|
|
152
|
-
• Undeclared external service
|
|
153
|
-
|
|
154
|
-
${c.bold}EXIT CODES${c.reset}
|
|
155
|
-
0 = PASS (or WARN without --fail-on-warn)
|
|
156
|
-
1 = WARN (with --fail-on-warn)
|
|
157
|
-
2 = BLOCK
|
|
158
|
-
|
|
159
|
-
${c.bold}EXAMPLES${c.reset}
|
|
160
|
-
vibecheck ctx guard ${c.dim}# Local validation${c.reset}
|
|
161
|
-
vibecheck ctx guard --json --fail-on-warn ${c.dim}# CI mode${c.reset}
|
|
162
|
-
`);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async function main(args) {
|
|
166
|
-
const opts = parseArgs(args);
|
|
167
|
-
|
|
168
|
-
if (opts.help) {
|
|
169
|
-
printHelp();
|
|
170
|
-
return 0;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return runCtxGuard(opts);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
module.exports = { runCtxGuard, main };
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck ctx sync - Context Contracts Sync
|
|
3
|
-
*
|
|
4
|
-
* Generates/updates contracts from truthpack:
|
|
5
|
-
* - routes.json
|
|
6
|
-
* - env.json
|
|
7
|
-
* - auth.json
|
|
8
|
-
* - external.json
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
"use strict";
|
|
12
|
-
|
|
13
|
-
const path = require("path");
|
|
14
|
-
const fs = require("fs");
|
|
15
|
-
const { buildTruthpack, loadTruthpack } = require("./lib/truth");
|
|
16
|
-
const {
|
|
17
|
-
buildAllContracts,
|
|
18
|
-
loadContracts,
|
|
19
|
-
saveContracts,
|
|
20
|
-
diffAllContracts,
|
|
21
|
-
hasContractChanges
|
|
22
|
-
} = require("./lib/contracts");
|
|
23
|
-
|
|
24
|
-
const c = {
|
|
25
|
-
reset: '\x1b[0m',
|
|
26
|
-
bold: '\x1b[1m',
|
|
27
|
-
dim: '\x1b[2m',
|
|
28
|
-
green: '\x1b[32m',
|
|
29
|
-
yellow: '\x1b[33m',
|
|
30
|
-
cyan: '\x1b[36m',
|
|
31
|
-
red: '\x1b[31m',
|
|
32
|
-
blue: '\x1b[34m',
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
async function runCtxSync(opts = {}) {
|
|
36
|
-
const root = path.resolve(opts.repoRoot || process.cwd());
|
|
37
|
-
const contractDir = path.join(root, ".vibecheck", "contracts");
|
|
38
|
-
|
|
39
|
-
console.log(`\n${c.cyan}${c.bold}📜 vibecheck ctx sync${c.reset}`);
|
|
40
|
-
console.log(`${c.dim}Syncing contracts from truthpack...${c.reset}\n`);
|
|
41
|
-
|
|
42
|
-
// Load or build truthpack
|
|
43
|
-
let truthpack = loadTruthpack(root);
|
|
44
|
-
if (!truthpack) {
|
|
45
|
-
console.log(`${c.dim}Building truthpack...${c.reset}`);
|
|
46
|
-
truthpack = await buildTruthpack({ repoRoot: root, fastifyEntry: opts.fastifyEntry });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Load existing contracts for diff
|
|
50
|
-
const existingContracts = loadContracts(root);
|
|
51
|
-
const hasExisting = Object.keys(existingContracts).length > 0;
|
|
52
|
-
|
|
53
|
-
// Build new contracts
|
|
54
|
-
const newContracts = buildAllContracts(truthpack);
|
|
55
|
-
|
|
56
|
-
// Calculate diff
|
|
57
|
-
let diff = null;
|
|
58
|
-
if (hasExisting) {
|
|
59
|
-
diff = diffAllContracts(existingContracts, newContracts);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Save contracts
|
|
63
|
-
saveContracts(root, newContracts);
|
|
64
|
-
|
|
65
|
-
// Print summary
|
|
66
|
-
console.log(`${c.bold}Contracts saved to:${c.reset} .vibecheck/contracts/\n`);
|
|
67
|
-
|
|
68
|
-
console.log(`${c.bold}Routes Contract${c.reset}`);
|
|
69
|
-
console.log(` Routes: ${newContracts.routes.routes.length}`);
|
|
70
|
-
if (diff?.routes) {
|
|
71
|
-
if (diff.routes.added?.length) console.log(` ${c.green}+${diff.routes.added.length} added${c.reset}`);
|
|
72
|
-
if (diff.routes.removed?.length) console.log(` ${c.red}-${diff.routes.removed.length} removed${c.reset}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.log(`\n${c.bold}Env Contract${c.reset}`);
|
|
76
|
-
console.log(` Variables: ${newContracts.env.vars.length}`);
|
|
77
|
-
const required = newContracts.env.vars.filter(v => v.required).length;
|
|
78
|
-
console.log(` Required: ${required}`);
|
|
79
|
-
if (diff?.env) {
|
|
80
|
-
if (diff.env.added?.length) console.log(` ${c.green}+${diff.env.added.length} added${c.reset}`);
|
|
81
|
-
if (diff.env.removed?.length) console.log(` ${c.red}-${diff.env.removed.length} removed${c.reset}`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
console.log(`\n${c.bold}Auth Contract${c.reset}`);
|
|
85
|
-
console.log(` Protected patterns: ${newContracts.auth.protectedPatterns.length}`);
|
|
86
|
-
console.log(` Roles: ${newContracts.auth.roles.length}`);
|
|
87
|
-
if (diff?.auth) {
|
|
88
|
-
if (diff.auth.protectedAdded?.length) console.log(` ${c.green}+${diff.auth.protectedAdded.length} patterns added${c.reset}`);
|
|
89
|
-
if (diff.auth.protectedRemoved?.length) console.log(` ${c.red}-${diff.auth.protectedRemoved.length} patterns removed${c.reset}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log(`\n${c.bold}External Contract${c.reset}`);
|
|
93
|
-
console.log(` Services: ${newContracts.external.services.length}`);
|
|
94
|
-
for (const svc of newContracts.external.services) {
|
|
95
|
-
console.log(` - ${svc.name} (${svc.envVars.length} env vars)`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Print files created
|
|
99
|
-
console.log(`\n${c.bold}Files:${c.reset}`);
|
|
100
|
-
console.log(` ${c.dim}routes.json${c.reset} Route definitions + auth requirements`);
|
|
101
|
-
console.log(` ${c.dim}env.json${c.reset} Environment variable contract`);
|
|
102
|
-
console.log(` ${c.dim}auth.json${c.reset} Authentication patterns + roles`);
|
|
103
|
-
console.log(` ${c.dim}external.json${c.reset} External service integrations`);
|
|
104
|
-
|
|
105
|
-
if (hasExisting && hasContractChanges(diff)) {
|
|
106
|
-
console.log(`\n${c.yellow}⚠️ Contracts changed since last sync${c.reset}`);
|
|
107
|
-
console.log(`${c.dim}Run 'vibecheck ctx diff' to see detailed changes${c.reset}`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
console.log(`\n${c.green}✓${c.reset} Contracts synced successfully`);
|
|
111
|
-
console.log(`${c.dim}Run 'vibecheck ctx guard' to validate code against contracts${c.reset}\n`);
|
|
112
|
-
|
|
113
|
-
return 0;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
module.exports = { runCtxSync };
|
package/bin/runners/runExport.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vibecheck export - Lightweight Collaboration Outputs
|
|
3
|
-
*
|
|
4
|
-
* Subcommands:
|
|
5
|
-
* export pr = current pr
|
|
6
|
-
* export badge = current badge
|
|
7
|
-
* export bundle = current share
|
|
8
|
-
*
|
|
9
|
-
* Replaces: pr, badge, share
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
"use strict";
|
|
13
|
-
|
|
14
|
-
const c = {
|
|
15
|
-
reset: '\x1b[0m',
|
|
16
|
-
bold: '\x1b[1m',
|
|
17
|
-
dim: '\x1b[2m',
|
|
18
|
-
cyan: '\x1b[36m',
|
|
19
|
-
yellow: '\x1b[33m',
|
|
20
|
-
red: '\x1b[31m',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
function printHelp() {
|
|
24
|
-
console.log(`
|
|
25
|
-
${c.cyan}${c.bold}📤 vibecheck export${c.reset} - Generate Collaboration Outputs
|
|
26
|
-
|
|
27
|
-
Lightweight outputs from latest results for sharing and collaboration.
|
|
28
|
-
|
|
29
|
-
${c.bold}SUBCOMMANDS${c.reset}
|
|
30
|
-
${c.cyan}pr${c.reset} ${c.dim}Generate GitHub PR comment (replaces 'pr')${c.reset}
|
|
31
|
-
${c.cyan}badge${c.reset} ${c.dim}Generate ship badge for README (replaces 'badge')${c.reset}
|
|
32
|
-
${c.cyan}bundle${c.reset} ${c.dim}Generate share pack for PR/docs (replaces 'share')${c.reset}
|
|
33
|
-
|
|
34
|
-
${c.bold}EXAMPLES${c.reset}
|
|
35
|
-
vibecheck export pr
|
|
36
|
-
vibecheck export badge --style gradient
|
|
37
|
-
vibecheck export bundle
|
|
38
|
-
|
|
39
|
-
${c.dim}Note: Old commands still work as aliases:
|
|
40
|
-
vibecheck pr → vibecheck export pr
|
|
41
|
-
vibecheck badge → vibecheck export badge
|
|
42
|
-
vibecheck share → vibecheck export bundle${c.reset}
|
|
43
|
-
`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function runExport(args) {
|
|
47
|
-
if (!args || args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
48
|
-
printHelp();
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const subcommand = args[0];
|
|
53
|
-
const subArgs = args.slice(1);
|
|
54
|
-
|
|
55
|
-
switch (subcommand) {
|
|
56
|
-
case "pr":
|
|
57
|
-
// Delegate to runPR
|
|
58
|
-
try {
|
|
59
|
-
const { runPR } = require("./runPR");
|
|
60
|
-
return await runPR(subArgs);
|
|
61
|
-
} catch (e) {
|
|
62
|
-
console.error(`${c.red}Error:${c.reset} Export PR unavailable: ${e.message}`);
|
|
63
|
-
return 1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
case "badge":
|
|
67
|
-
// Delegate to runBadge
|
|
68
|
-
try {
|
|
69
|
-
const { runBadge } = require("./runBadge");
|
|
70
|
-
return await runBadge(subArgs);
|
|
71
|
-
} catch (e) {
|
|
72
|
-
console.error(`${c.red}Error:${c.reset} Export badge unavailable: ${e.message}`);
|
|
73
|
-
return 1;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
case "bundle":
|
|
77
|
-
// Delegate to runShare
|
|
78
|
-
try {
|
|
79
|
-
const { runShare } = require("./runShare");
|
|
80
|
-
return await runShare(subArgs);
|
|
81
|
-
} catch (e) {
|
|
82
|
-
console.error(`${c.red}Error:${c.reset} Export bundle unavailable: ${e.message}`);
|
|
83
|
-
return 1;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
default:
|
|
87
|
-
console.error(`${c.red}Unknown subcommand:${c.reset} ${subcommand}`);
|
|
88
|
-
console.log(`\n${c.dim}Run 'vibecheck export --help' for available subcommands.${c.reset}\n`);
|
|
89
|
-
return 1;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
module.exports = { runExport };
|