@vibecheckai/cli 3.1.2 → 3.1.4

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.
Files changed (47) hide show
  1. package/README.md +60 -33
  2. package/bin/registry.js +319 -34
  3. package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
  4. package/bin/runners/REPORT_AUDIT.md +64 -0
  5. package/bin/runners/lib/entitlements-v2.js +97 -28
  6. package/bin/runners/lib/entitlements.js +3 -6
  7. package/bin/runners/lib/init-wizard.js +1 -1
  8. package/bin/runners/lib/report-engine.js +459 -280
  9. package/bin/runners/lib/report-html.js +1154 -1423
  10. package/bin/runners/lib/report-output.js +187 -0
  11. package/bin/runners/lib/report-templates.js +848 -850
  12. package/bin/runners/lib/scan-output.js +545 -0
  13. package/bin/runners/lib/server-usage.js +0 -12
  14. package/bin/runners/lib/ship-output.js +641 -0
  15. package/bin/runners/lib/status-output.js +253 -0
  16. package/bin/runners/lib/terminal-ui.js +853 -0
  17. package/bin/runners/runCheckpoint.js +502 -0
  18. package/bin/runners/runContracts.js +105 -0
  19. package/bin/runners/runExport.js +93 -0
  20. package/bin/runners/runFix.js +31 -24
  21. package/bin/runners/runInit.js +377 -112
  22. package/bin/runners/runInstall.js +1 -5
  23. package/bin/runners/runLabs.js +3 -3
  24. package/bin/runners/runPolish.js +2452 -0
  25. package/bin/runners/runProve.js +2 -2
  26. package/bin/runners/runReport.js +251 -200
  27. package/bin/runners/runRuntime.js +110 -0
  28. package/bin/runners/runScan.js +477 -379
  29. package/bin/runners/runSecurity.js +92 -0
  30. package/bin/runners/runShip.js +137 -207
  31. package/bin/runners/runStatus.js +16 -68
  32. package/bin/runners/utils.js +5 -5
  33. package/bin/vibecheck.js +25 -11
  34. package/mcp-server/index.js +150 -18
  35. package/mcp-server/package.json +2 -2
  36. package/mcp-server/premium-tools.js +13 -13
  37. package/mcp-server/tier-auth.js +292 -27
  38. package/mcp-server/vibecheck-tools.js +9 -9
  39. package/package.json +1 -1
  40. package/bin/runners/runClaimVerifier.js +0 -483
  41. package/bin/runners/runContextCompiler.js +0 -385
  42. package/bin/runners/runGate.js +0 -17
  43. package/bin/runners/runInitGha.js +0 -164
  44. package/bin/runners/runInteractive.js +0 -388
  45. package/bin/runners/runMdc.js +0 -204
  46. package/bin/runners/runMissionGenerator.js +0 -282
  47. package/bin/runners/runTruthpack.js +0 -636
@@ -1,483 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Claim Verifier v1
4
- *
5
- * Validates claims against the Truth Pack.
6
- * Returns: true | false | unknown
7
- *
8
- * CRITICAL: If 'unknown', the agent MUST NOT proceed with actions that depend on this claim.
9
- *
10
- * Usage:
11
- * validateClaim({ type: 'route_exists', subject: { method: 'POST', path: '/api/login' } })
12
- */
13
-
14
- import fs from 'fs/promises';
15
- import path from 'path';
16
- import crypto from 'crypto';
17
- import { RouteIndex, validateRouteExists as validateRouteFromIndex } from './lib/route-truth.js';
18
-
19
- /**
20
- * Load the truth pack from disk
21
- */
22
- async function loadTruthpack(projectPath) {
23
- const truthpackPath = path.join(projectPath, '.vibecheck', 'truth', 'truthpack.json');
24
- try {
25
- const content = await fs.readFile(truthpackPath, 'utf8');
26
- return JSON.parse(content);
27
- } catch (err) {
28
- return null;
29
- }
30
- }
31
-
32
- /**
33
- * Validate a claim against the truth pack
34
- *
35
- * @param {Object} claim - The claim to validate
36
- * @param {string} claim.type - Type of claim (route_exists, env_var_exists, auth_enforced, etc.)
37
- * @param {Object} claim.subject - What the claim is about
38
- * @param {boolean} claim.expected - Expected result (default: true)
39
- * @param {Object} claim.context - Optional context (task, scopeFiles)
40
- * @param {string} projectPath - Project root path
41
- * @returns {Object} Claim result with evidence
42
- */
43
- export async function validateClaim(claim, projectPath = process.cwd()) {
44
- const claimId = generateClaimId(claim);
45
- const truthpack = await loadTruthpack(projectPath);
46
-
47
- if (!truthpack) {
48
- return {
49
- id: claimId,
50
- result: 'unknown',
51
- confidence: 'low',
52
- evidence: [],
53
- assumptions: [],
54
- gaps: [{ title: 'No truth pack found', severity: 'block', confidence: 'high' }],
55
- nextSteps: ['Run `vibecheck ctx` to generate truth pack'],
56
- };
57
- }
58
-
59
- let result;
60
-
61
- switch (claim.type) {
62
- case 'route_exists':
63
- result = await verifyRouteExists(claim, truthpack, projectPath);
64
- break;
65
-
66
- case 'env_var_exists':
67
- result = verifyEnvVarExists(claim, truthpack);
68
- break;
69
-
70
- case 'env_var_used':
71
- result = verifyEnvVarUsed(claim, truthpack);
72
- break;
73
-
74
- case 'auth_enforced':
75
- case 'auth_enforced_on_surface':
76
- result = verifyAuthEnforced(claim, truthpack);
77
- break;
78
-
79
- case 'route_guarded':
80
- result = verifyRouteGuarded(claim, truthpack);
81
- break;
82
-
83
- case 'file_exists':
84
- result = await verifyFileExists(claim, projectPath);
85
- break;
86
-
87
- case 'integration_exists':
88
- result = verifyIntegrationExists(claim, truthpack);
89
- break;
90
-
91
- default:
92
- result = {
93
- result: 'unknown',
94
- confidence: 'low',
95
- evidence: [],
96
- assumptions: [],
97
- gaps: [],
98
- nextSteps: [`Claim type "${claim.type}" not yet implemented`],
99
- };
100
- }
101
-
102
- // Add warning for unknown results
103
- if (result.result === 'unknown') {
104
- result.warning = '⚠️ UNKNOWN claims BLOCK dependent actions. Verify before proceeding.';
105
- if (!result.nextSteps) result.nextSteps = [];
106
- result.nextSteps.push(
107
- 'Use vibecheck.search_evidence to find related code',
108
- 'Check if the feature is implemented yet'
109
- );
110
- }
111
-
112
- return {
113
- id: claimId,
114
- ...result,
115
- timestamp: new Date().toISOString(),
116
- };
117
- }
118
-
119
- /**
120
- * Verify route_exists claim using Route Truth v1
121
- */
122
- async function verifyRouteExists(claim, truthpack, projectPath) {
123
- const { method, path: routePath } = claim.subject;
124
-
125
- // Use Route Truth for live verification (more accurate than cached truthpack)
126
- if (projectPath) {
127
- try {
128
- const result = await validateRouteFromIndex({ method, path: routePath }, projectPath);
129
- return {
130
- result: result.result,
131
- confidence: result.confidence,
132
- evidence: result.evidence || [],
133
- assumptions: [],
134
- gaps: result.gaps || [],
135
- nextSteps: result.nextSteps || [],
136
- matchedRoute: result.matchedRoute,
137
- closestRoutes: result.closestRoutes,
138
- };
139
- } catch {
140
- // Fall back to truthpack if Route Truth fails
141
- }
142
- }
143
-
144
- // Fallback: use cached truthpack
145
- const routes = truthpack?.routes?.server || [];
146
-
147
- // Find matching route
148
- const match = routes.find(r => {
149
- const methodMatch = !method || r.method === '*' || r.method.toUpperCase() === method.toUpperCase();
150
- const pathMatch = r.path === routePath || pathMatches(r.path, routePath);
151
- return methodMatch && pathMatch;
152
- });
153
-
154
- if (match) {
155
- return {
156
- result: 'true',
157
- confidence: match.confidence,
158
- evidence: match.evidence || [],
159
- assumptions: [],
160
- gaps: [],
161
- nextSteps: [],
162
- };
163
- }
164
-
165
- // Check if it's referenced but not defined (gap)
166
- const clientRef = truthpack?.routes?.clientRefs?.find(r => r.path === routePath);
167
- if (clientRef) {
168
- return {
169
- result: 'false',
170
- confidence: 'high',
171
- evidence: clientRef.evidence || [],
172
- assumptions: [],
173
- gaps: [{
174
- title: `Route ${routePath} referenced in UI but not found on server`,
175
- severity: 'block',
176
- confidence: 'high',
177
- suggestion: 'Create the server route or fix the client reference',
178
- }],
179
- nextSteps: ['Check server route definitions', 'Verify the intended endpoint path'],
180
- };
181
- }
182
-
183
- return {
184
- result: 'false',
185
- confidence: 'high',
186
- evidence: [],
187
- assumptions: [],
188
- gaps: [],
189
- nextSteps: [`Route ${method || 'ANY'} ${routePath} not found in truth pack`],
190
- };
191
- }
192
-
193
- /**
194
- * Verify env_var_exists claim
195
- */
196
- function verifyEnvVarExists(claim, truthpack) {
197
- const { name } = claim.subject;
198
- const vars = truthpack.env?.vars || [];
199
-
200
- const match = vars.find(v => v.name === name);
201
-
202
- if (match) {
203
- return {
204
- result: 'true',
205
- confidence: 'high',
206
- evidence: match.references || [],
207
- assumptions: [],
208
- gaps: [],
209
- nextSteps: [],
210
- };
211
- }
212
-
213
- return {
214
- result: 'unknown',
215
- confidence: 'low',
216
- evidence: [],
217
- assumptions: [],
218
- gaps: [],
219
- nextSteps: [`Check .env.example for ${name}`, `Search for process.env.${name} in code`],
220
- };
221
- }
222
-
223
- /**
224
- * Verify env_var_used claim
225
- */
226
- function verifyEnvVarUsed(claim, truthpack) {
227
- const { name } = claim.subject;
228
- const vars = truthpack.env?.vars || [];
229
-
230
- const match = vars.find(v => v.name === name);
231
-
232
- if (match && match.references && match.references.length > 0) {
233
- return {
234
- result: 'true',
235
- confidence: 'high',
236
- evidence: match.references,
237
- assumptions: [],
238
- gaps: [],
239
- nextSteps: [],
240
- };
241
- }
242
-
243
- if (match) {
244
- return {
245
- result: 'false',
246
- confidence: 'med',
247
- evidence: [],
248
- assumptions: [],
249
- gaps: [{
250
- title: `${name} declared but not used in code`,
251
- severity: 'warn',
252
- confidence: 'med',
253
- }],
254
- nextSteps: [],
255
- };
256
- }
257
-
258
- return {
259
- result: 'false',
260
- confidence: 'high',
261
- evidence: [],
262
- assumptions: [],
263
- gaps: [],
264
- nextSteps: [],
265
- };
266
- }
267
-
268
- /**
269
- * Verify auth_enforced claim
270
- */
271
- function verifyAuthEnforced(claim, truthpack) {
272
- const { path: surfacePath, surface } = claim.subject;
273
- const targetPath = surfacePath || surface;
274
-
275
- const protectedSurfaces = truthpack.auth?.protectedSurfaces || [];
276
- const match = protectedSurfaces.find(s =>
277
- s.surface === targetPath || pathMatches(s.surface, targetPath)
278
- );
279
-
280
- if (match) {
281
- return {
282
- result: 'true',
283
- confidence: 'high',
284
- evidence: match.evidence || [],
285
- assumptions: [],
286
- gaps: [],
287
- nextSteps: [],
288
- };
289
- }
290
-
291
- // Check if route exists but isn't protected
292
- const routes = truthpack.routes?.server || [];
293
- const routeMatch = routes.find(r => r.path === targetPath);
294
-
295
- if (routeMatch) {
296
- if (routeMatch.authRequired === 'yes') {
297
- return {
298
- result: 'true',
299
- confidence: 'med',
300
- evidence: routeMatch.evidence || [],
301
- assumptions: [{ description: 'Auth detected via pattern matching, not explicit middleware check' }],
302
- gaps: [],
303
- nextSteps: ['Verify middleware is correctly applied'],
304
- };
305
- } else if (routeMatch.authRequired === 'no') {
306
- return {
307
- result: 'false',
308
- confidence: 'high',
309
- evidence: routeMatch.evidence || [],
310
- assumptions: [],
311
- gaps: [],
312
- nextSteps: [],
313
- };
314
- }
315
- }
316
-
317
- return {
318
- result: 'unknown',
319
- confidence: 'low',
320
- evidence: [],
321
- assumptions: [],
322
- gaps: [],
323
- nextSteps: ['Check middleware configuration', 'Look for auth guards on this route'],
324
- };
325
- }
326
-
327
- /**
328
- * Verify route_guarded claim
329
- */
330
- function verifyRouteGuarded(claim, truthpack) {
331
- const { path: routePath } = claim.subject;
332
- const routes = truthpack.routes?.server || [];
333
-
334
- const match = routes.find(r => r.path === routePath);
335
-
336
- if (match && match.middlewares && match.middlewares.length > 0) {
337
- return {
338
- result: 'true',
339
- confidence: 'high',
340
- evidence: match.evidence || [],
341
- assumptions: [],
342
- gaps: [],
343
- nextSteps: [],
344
- };
345
- }
346
-
347
- if (match) {
348
- return {
349
- result: 'false',
350
- confidence: 'med',
351
- evidence: match.evidence || [],
352
- assumptions: [],
353
- gaps: [{
354
- title: `Route ${routePath} has no detected middleware`,
355
- severity: 'warn',
356
- confidence: 'med',
357
- }],
358
- nextSteps: [],
359
- };
360
- }
361
-
362
- return {
363
- result: 'unknown',
364
- confidence: 'low',
365
- evidence: [],
366
- assumptions: [],
367
- gaps: [],
368
- nextSteps: [`Route ${routePath} not found in truth pack`],
369
- };
370
- }
371
-
372
- /**
373
- * Verify file_exists claim
374
- */
375
- async function verifyFileExists(claim, projectPath) {
376
- const { path: filePath, name } = claim.subject;
377
- const targetPath = path.join(projectPath, filePath || name);
378
-
379
- try {
380
- await fs.access(targetPath);
381
- return {
382
- result: 'true',
383
- confidence: 'high',
384
- evidence: [{ id: 'file_check', file: filePath || name, lines: '1', snippetHash: '', reason: 'File exists' }],
385
- assumptions: [],
386
- gaps: [],
387
- nextSteps: [],
388
- };
389
- } catch {
390
- return {
391
- result: 'false',
392
- confidence: 'high',
393
- evidence: [],
394
- assumptions: [],
395
- gaps: [],
396
- nextSteps: [],
397
- };
398
- }
399
- }
400
-
401
- /**
402
- * Verify integration_exists claim
403
- */
404
- function verifyIntegrationExists(claim, truthpack) {
405
- const { name } = claim.subject;
406
- const services = truthpack.integrations?.services || [];
407
-
408
- const match = services.find(s => s.name.toLowerCase() === name.toLowerCase());
409
-
410
- if (match) {
411
- return {
412
- result: 'true',
413
- confidence: 'high',
414
- evidence: match.evidence || [],
415
- assumptions: [],
416
- gaps: [],
417
- nextSteps: [],
418
- };
419
- }
420
-
421
- return {
422
- result: 'false',
423
- confidence: 'med',
424
- evidence: [],
425
- assumptions: [],
426
- gaps: [],
427
- nextSteps: [`Search for ${name} imports or SDK usage`],
428
- };
429
- }
430
-
431
- // =============================================================================
432
- // HELPERS
433
- // =============================================================================
434
-
435
- function generateClaimId(claim) {
436
- const payload = JSON.stringify({ type: claim.type, subject: claim.subject });
437
- return `clm_${crypto.createHash('sha256').update(payload).digest('hex').slice(0, 8)}`;
438
- }
439
-
440
- function pathMatches(pattern, path) {
441
- // Handle Express-style path params (:id, :userId, etc.)
442
- const patternParts = pattern.split('/');
443
- const pathParts = path.split('/');
444
-
445
- if (patternParts.length !== pathParts.length) return false;
446
-
447
- return patternParts.every((part, i) => {
448
- if (part.startsWith(':')) return true; // Param placeholder
449
- if (part === '*') return true; // Wildcard
450
- return part === pathParts[i];
451
- });
452
- }
453
-
454
- /**
455
- * Batch validate multiple claims
456
- */
457
- export async function validateClaims(claims, projectPath = process.cwd()) {
458
- const results = [];
459
-
460
- for (const claim of claims) {
461
- const result = await validateClaim(claim, projectPath);
462
- results.push(result);
463
- }
464
-
465
- // Check if any claims are unknown - blocks dependent actions
466
- const hasUnknown = results.some(r => r.result === 'unknown');
467
- const hasFalse = results.some(r => r.result === 'false');
468
-
469
- return {
470
- claims: results,
471
- allVerified: !hasUnknown && !hasFalse,
472
- hasUnknown,
473
- hasFalse,
474
- canProceed: !hasUnknown,
475
- message: hasUnknown
476
- ? '⚠️ Cannot proceed: some claims are unknown. Verify or provide more evidence.'
477
- : hasFalse
478
- ? '❌ Some claims are false. Review and correct before proceeding.'
479
- : '✅ All claims verified.',
480
- };
481
- }
482
-
483
- export default { validateClaim, validateClaims };