@vibecheckai/cli 3.0.4 → 3.0.5
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/bin/dev/run-v2-torture.js +30 -0
- package/bin/guardrail.js +9 -0
- package/bin/runners/lib/analyzers.js +38 -0
- package/bin/runners/lib/assets/vibecheck-logo.png +0 -0
- package/bin/runners/lib/contracts/auth-contract.js +8 -0
- package/bin/runners/lib/contracts/env-contract.js +3 -0
- package/bin/runners/lib/contracts/external-contract.js +10 -2
- package/bin/runners/lib/contracts/route-contract.js +7 -0
- package/bin/runners/lib/contracts.js +804 -0
- package/bin/runners/lib/detectors-v2.js +703 -0
- package/bin/runners/lib/drift.js +425 -0
- package/bin/runners/lib/entitlements.js +8 -3
- package/bin/runners/lib/env-resolver.js +417 -0
- package/bin/runners/lib/extractors/client-calls.js +990 -0
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -0
- package/bin/runners/lib/extractors/fastify-routes.js +426 -0
- package/bin/runners/lib/extractors/index.js +363 -0
- package/bin/runners/lib/extractors/next-routes.js +524 -0
- package/bin/runners/lib/extractors/proof-graph.js +431 -0
- package/bin/runners/lib/extractors/route-matcher.js +451 -0
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -0
- package/bin/runners/lib/extractors/ui-bindings.js +547 -0
- package/bin/runners/lib/findings-schema.js +281 -0
- package/bin/runners/lib/html-report.js +650 -0
- package/bin/runners/lib/missions/templates.js +45 -0
- package/bin/runners/lib/policy.js +295 -0
- package/bin/runners/lib/reality/correlation-detectors.js +359 -0
- package/bin/runners/lib/reality/index.js +318 -0
- package/bin/runners/lib/reality/request-hashing.js +416 -0
- package/bin/runners/lib/reality/request-mapper.js +453 -0
- package/bin/runners/lib/reality/safety-rails.js +463 -0
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -0
- package/bin/runners/lib/reality/toast-detector.js +393 -0
- package/bin/runners/lib/route-truth.js +10 -10
- package/bin/runners/lib/schema-validator.js +350 -0
- package/bin/runners/lib/schemas/contracts.schema.json +160 -0
- package/bin/runners/lib/schemas/finding.schema.json +100 -0
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -0
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -0
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -0
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -0
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -0
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -0
- package/bin/runners/lib/schemas/validator.js +438 -0
- package/bin/runners/lib/verdict-engine.js +628 -0
- package/bin/runners/runAIAgent.js +228 -1
- package/bin/runners/runBadge.js +181 -1
- package/bin/runners/runCtxDiff.js +301 -0
- package/bin/runners/runInitGha.js +78 -15
- package/bin/runners/runLaunch.js +180 -1
- package/bin/runners/runProve.js +23 -0
- package/bin/runners/runReplay.js +114 -84
- package/bin/runners/runScan.js +111 -32
- package/bin/runners/runShip.js +23 -2
- package/bin/runners/runTruthpack.js +9 -7
- package/bin/runners/runValidate.js +161 -1
- package/bin/vibecheck.js +6 -1
- package/package.json +9 -8
package/bin/runners/runScan.js
CHANGED
|
@@ -478,8 +478,65 @@ async function runScan(args) {
|
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
try {
|
|
481
|
-
// Import systems
|
|
482
|
-
|
|
481
|
+
// Import systems - try TypeScript compiled first, fallback to JS runtime
|
|
482
|
+
let scanRouteIntegrity;
|
|
483
|
+
let useFallbackScanner = false;
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
scanRouteIntegrity = require('../../dist/lib/route-integrity').scanRouteIntegrity;
|
|
487
|
+
} catch (e) {
|
|
488
|
+
// Fallback to JS-based scanner using truth.js and analyzers.js
|
|
489
|
+
useFallbackScanner = true;
|
|
490
|
+
const { buildTruthpack } = require('./lib/truth');
|
|
491
|
+
const { findMissingRoutes, findEnvGaps, findFakeSuccess, findGhostAuth } = require('./lib/analyzers');
|
|
492
|
+
|
|
493
|
+
scanRouteIntegrity = async function({ projectPath, layers, baseUrl, verbose }) {
|
|
494
|
+
// Build truthpack for route analysis
|
|
495
|
+
const truthpack = await buildTruthpack({ repoRoot: projectPath });
|
|
496
|
+
|
|
497
|
+
// Run analyzers
|
|
498
|
+
const findings = [];
|
|
499
|
+
findings.push(...findMissingRoutes(truthpack));
|
|
500
|
+
findings.push(...findEnvGaps(truthpack));
|
|
501
|
+
findings.push(...findFakeSuccess(projectPath));
|
|
502
|
+
findings.push(...findGhostAuth(truthpack, projectPath));
|
|
503
|
+
|
|
504
|
+
// Convert to scan format matching TypeScript scanner output
|
|
505
|
+
const shipBlockers = findings.map((f, i) => ({
|
|
506
|
+
id: f.id || `finding-${i}`,
|
|
507
|
+
ruleId: f.category,
|
|
508
|
+
category: f.category,
|
|
509
|
+
severity: f.severity === 'BLOCK' ? 'critical' : f.severity === 'WARN' ? 'warning' : 'info',
|
|
510
|
+
title: f.title,
|
|
511
|
+
message: f.title,
|
|
512
|
+
description: f.why,
|
|
513
|
+
file: f.evidence?.[0]?.file || '',
|
|
514
|
+
line: parseInt(f.evidence?.[0]?.lines?.split('-')[0]) || 1,
|
|
515
|
+
evidence: f.evidence || [],
|
|
516
|
+
fixHints: f.fixHints || [],
|
|
517
|
+
autofixAvailable: false,
|
|
518
|
+
verdict: f.severity === 'BLOCK' ? 'FAIL' : 'WARN',
|
|
519
|
+
}));
|
|
520
|
+
|
|
521
|
+
// Return structure matching TypeScript scanner
|
|
522
|
+
return {
|
|
523
|
+
report: {
|
|
524
|
+
shipBlockers,
|
|
525
|
+
realitySniffFindings: [],
|
|
526
|
+
routeMap: truthpack.routes,
|
|
527
|
+
summary: {
|
|
528
|
+
total: shipBlockers.length,
|
|
529
|
+
critical: shipBlockers.filter(f => f.severity === 'critical').length,
|
|
530
|
+
warning: shipBlockers.filter(f => f.severity === 'warning').length,
|
|
531
|
+
},
|
|
532
|
+
verdict: shipBlockers.some(f => f.severity === 'critical') ? 'BLOCK' :
|
|
533
|
+
shipBlockers.some(f => f.severity === 'warning') ? 'WARN' : 'SHIP'
|
|
534
|
+
},
|
|
535
|
+
outputPaths: {},
|
|
536
|
+
truthpack
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
}
|
|
483
540
|
|
|
484
541
|
// Try to import new unified output system (may not be compiled yet)
|
|
485
542
|
let buildVerdictOutput, normalizeFinding, formatStandardOutput, formatScanOutput, getExitCode, CacheManager;
|
|
@@ -648,35 +705,6 @@ async function runScan(args) {
|
|
|
648
705
|
|
|
649
706
|
const { report, outputPaths } = result;
|
|
650
707
|
|
|
651
|
-
// Normalize findings with stable IDs
|
|
652
|
-
const existingIDs = new Set();
|
|
653
|
-
const normalizedFindings = [];
|
|
654
|
-
|
|
655
|
-
// Normalize route integrity findings
|
|
656
|
-
if (report.shipBlockers) {
|
|
657
|
-
for (let i = 0; i < report.shipBlockers.length; i++) {
|
|
658
|
-
const blocker = report.shipBlockers[i];
|
|
659
|
-
const category = blocker.category || 'ROUTE';
|
|
660
|
-
const normalized = normalizeFinding(blocker, category, i, existingIDs);
|
|
661
|
-
normalizedFindings.push(normalized);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// Normalize Reality Sniff findings if present
|
|
666
|
-
if (report.realitySniffFindings) {
|
|
667
|
-
for (let i = 0; i < report.realitySniffFindings.length; i++) {
|
|
668
|
-
const finding = report.realitySniffFindings[i];
|
|
669
|
-
const category = finding.ruleId?.startsWith('auth') ? 'AUTH' : 'REALITY';
|
|
670
|
-
const normalized = normalizeFinding(finding, category, normalizedFindings.length, existingIDs);
|
|
671
|
-
normalizedFindings.push(normalized);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// Add detection engine findings (Dead UI, Billing, Fake Success)
|
|
676
|
-
for (const finding of detectionFindings) {
|
|
677
|
-
normalizedFindings.push(finding);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
708
|
// Use new unified output if available, otherwise fallback to old format
|
|
681
709
|
if (useUnifiedOutput && buildVerdictOutput && normalizeFinding) {
|
|
682
710
|
// Normalize findings with stable IDs
|
|
@@ -778,7 +806,58 @@ async function runScan(args) {
|
|
|
778
806
|
});
|
|
779
807
|
|
|
780
808
|
return getExitCode(verdict);
|
|
781
|
-
}
|
|
809
|
+
} else {
|
|
810
|
+
// Legacy fallback output when unified output system isn't available
|
|
811
|
+
const findings = [...(report.shipBlockers || []), ...detectionFindings];
|
|
812
|
+
const criticalCount = findings.filter(f => f.severity === 'critical' || f.severity === 'BLOCK').length;
|
|
813
|
+
const warningCount = findings.filter(f => f.severity === 'warning' || f.severity === 'WARN').length;
|
|
814
|
+
|
|
815
|
+
const verdict = criticalCount > 0 ? 'BLOCK' : warningCount > 0 ? 'WARN' : 'SHIP';
|
|
816
|
+
|
|
817
|
+
// Print simple output
|
|
818
|
+
console.log();
|
|
819
|
+
console.log(` ${c.bold}═══════════════════════════════════════════════════════════════════${c.reset}`);
|
|
820
|
+
|
|
821
|
+
if (verdict === 'SHIP') {
|
|
822
|
+
console.log(` ${c.bgGreen}${c.white}${c.bold} ✓ SHIP ${c.reset} ${c.green}Ready to ship!${c.reset}`);
|
|
823
|
+
} else if (verdict === 'WARN') {
|
|
824
|
+
console.log(` ${c.bgYellow}${c.black}${c.bold} ⚠ WARN ${c.reset} ${c.yellow}Review recommended before shipping${c.reset}`);
|
|
825
|
+
} else {
|
|
826
|
+
console.log(` ${c.bgRed}${c.white}${c.bold} ✗ BLOCK ${c.reset} ${c.red}Issues must be fixed before shipping${c.reset}`);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
console.log(` ${c.bold}═══════════════════════════════════════════════════════════════════${c.reset}`);
|
|
830
|
+
console.log();
|
|
831
|
+
|
|
832
|
+
if (findings.length > 0) {
|
|
833
|
+
console.log(` ${c.bold}Findings (${findings.length})${c.reset}`);
|
|
834
|
+
console.log();
|
|
835
|
+
|
|
836
|
+
for (const finding of findings.slice(0, 10)) {
|
|
837
|
+
const severityIcon = finding.severity === 'critical' || finding.severity === 'BLOCK'
|
|
838
|
+
? `${c.red}✗${c.reset}`
|
|
839
|
+
: `${c.yellow}⚠${c.reset}`;
|
|
840
|
+
console.log(` ${severityIcon} ${finding.title || finding.message}`);
|
|
841
|
+
if (finding.file) {
|
|
842
|
+
console.log(` ${c.dim}${finding.file}${finding.line ? `:${finding.line}` : ''}${c.reset}`);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (findings.length > 10) {
|
|
847
|
+
console.log(` ${c.dim}... and ${findings.length - 10} more findings${c.reset}`);
|
|
848
|
+
}
|
|
849
|
+
console.log();
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Emit audit event
|
|
853
|
+
emitScanComplete(projectPath, verdict === 'SHIP' ? 'success' : 'failure', {
|
|
854
|
+
score: verdict === 'SHIP' ? 100 : verdict === 'WARN' ? 70 : 40,
|
|
855
|
+
issueCount: criticalCount + warningCount,
|
|
856
|
+
durationMs: timings.total,
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
return verdict === 'SHIP' ? 0 : verdict === 'WARN' ? 1 : 2;
|
|
860
|
+
}
|
|
782
861
|
|
|
783
862
|
} catch (error) {
|
|
784
863
|
stopSpinner(`Scan failed: ${error.message}`, false);
|
package/bin/runners/runShip.js
CHANGED
|
@@ -22,6 +22,8 @@ const {
|
|
|
22
22
|
findOwnerModeBypass
|
|
23
23
|
} = require("./lib/analyzers");
|
|
24
24
|
const { findingsFromReality } = require("./lib/reality-findings");
|
|
25
|
+
// Contract Drift Detection - per spec: "routes/env/auth drift → usually BLOCK"
|
|
26
|
+
const { findContractDrift, loadContracts, hasContracts, getDriftSummary } = require("./lib/drift");
|
|
25
27
|
|
|
26
28
|
// Build proof graph from findings for evidence-backed verdicts
|
|
27
29
|
function buildProofGraph(findings, truthpack, root) {
|
|
@@ -103,7 +105,8 @@ function getClaimType(category) {
|
|
|
103
105
|
'StripeWebhook': 'billing_enforced',
|
|
104
106
|
'PaidSurface': 'billing_enforced',
|
|
105
107
|
'OwnerModeBypass': 'billing_enforced',
|
|
106
|
-
'DeadUI': 'ui_wired'
|
|
108
|
+
'DeadUI': 'ui_wired',
|
|
109
|
+
'ContractDrift': 'contract_satisfied'
|
|
107
110
|
};
|
|
108
111
|
return map[category] || 'ui_wired';
|
|
109
112
|
}
|
|
@@ -117,7 +120,8 @@ function getGapType(category) {
|
|
|
117
120
|
'StripeWebhook': 'missing_verification',
|
|
118
121
|
'PaidSurface': 'missing_gate',
|
|
119
122
|
'OwnerModeBypass': 'missing_gate',
|
|
120
|
-
'DeadUI': 'missing_handler'
|
|
123
|
+
'DeadUI': 'missing_handler',
|
|
124
|
+
'ContractDrift': 'contract_drift'
|
|
121
125
|
};
|
|
122
126
|
return map[category] || 'untested_path';
|
|
123
127
|
}
|
|
@@ -490,6 +494,23 @@ ${c.bold}EXAMPLES${c.reset}
|
|
|
490
494
|
...findingsFromReality(projectPath)
|
|
491
495
|
];
|
|
492
496
|
|
|
497
|
+
// Contract Drift Detection - per spec section 8.1:
|
|
498
|
+
// "drift can be WARN or BLOCK depending on category:
|
|
499
|
+
// routes/env/auth drift → usually BLOCK (because AI will lie here)"
|
|
500
|
+
if (hasContracts(projectPath)) {
|
|
501
|
+
const contracts = loadContracts(projectPath);
|
|
502
|
+
const driftFindings = findContractDrift(contracts, truthpack);
|
|
503
|
+
allFindings.push(...driftFindings);
|
|
504
|
+
|
|
505
|
+
const driftSummary = getDriftSummary(driftFindings);
|
|
506
|
+
if (driftSummary.hasDrift) {
|
|
507
|
+
console.log(` ${driftSummary.blocks > 0 ? c.red + '🛑' : c.yellow + '⚠️'} Contract drift detected: ${driftSummary.blocks} blocks, ${driftSummary.warns} warnings${c.reset}`);
|
|
508
|
+
if (driftSummary.blocks > 0) {
|
|
509
|
+
console.log(` ${c.dim}Run 'vibecheck ctx sync' to update contracts${c.reset}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
493
514
|
results.routeTruth = {
|
|
494
515
|
serverRoutes: truthpack.routes.server.length,
|
|
495
516
|
clientRefs: truthpack.routes.clientRefs.length,
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
* vibecheck ctx --md - Also generate truthpack.md
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
"use strict";
|
|
15
|
+
|
|
16
|
+
const fs = require('fs/promises');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const crypto = require('crypto');
|
|
19
|
+
const { execSync } = require('child_process');
|
|
20
|
+
const { RouteIndex, resolveNextRoutes, resolveFastifyRoutes } = require('./lib/route-truth.js');
|
|
19
21
|
|
|
20
22
|
const VERSION = '1.0.0';
|
|
21
23
|
|
|
@@ -25,7 +27,7 @@ let evidenceCounter = 0;
|
|
|
25
27
|
/**
|
|
26
28
|
* Main entry point
|
|
27
29
|
*/
|
|
28
|
-
|
|
30
|
+
async function runTruthpack(projectPath = process.cwd(), options = {}) {
|
|
29
31
|
const startTime = Date.now();
|
|
30
32
|
console.log('📦 Generating Truth Pack...\n');
|
|
31
33
|
|
|
@@ -631,4 +633,4 @@ function generateMarkdown(truthpack) {
|
|
|
631
633
|
return lines.join('\n');
|
|
632
634
|
}
|
|
633
635
|
|
|
634
|
-
|
|
636
|
+
module.exports = { runTruthpack };
|
|
@@ -1,2 +1,162 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* vibecheck validate - Validate AI-generated code for hallucinations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const { buildTruthpack } = require("./lib/truth");
|
|
8
|
+
const { routeMatches } = require("./lib/claims");
|
|
9
|
+
|
|
10
|
+
const c = {
|
|
11
|
+
reset: "\x1b[0m",
|
|
12
|
+
bold: "\x1b[1m",
|
|
13
|
+
dim: "\x1b[2m",
|
|
14
|
+
green: "\x1b[32m",
|
|
15
|
+
yellow: "\x1b[33m",
|
|
16
|
+
red: "\x1b[31m",
|
|
17
|
+
cyan: "\x1b[36m",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function parseArgs(args) {
|
|
21
|
+
const opts = {
|
|
22
|
+
help: false,
|
|
23
|
+
file: null,
|
|
24
|
+
json: false,
|
|
25
|
+
verbose: false,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
const arg = args[i];
|
|
30
|
+
switch (arg) {
|
|
31
|
+
case "--help":
|
|
32
|
+
case "-h":
|
|
33
|
+
opts.help = true;
|
|
34
|
+
break;
|
|
35
|
+
case "--json":
|
|
36
|
+
opts.json = true;
|
|
37
|
+
break;
|
|
38
|
+
case "--verbose":
|
|
39
|
+
case "-v":
|
|
40
|
+
opts.verbose = true;
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
if (!arg.startsWith("-")) {
|
|
44
|
+
opts.file = arg;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return opts;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function printHelp() {
|
|
53
|
+
console.log(`
|
|
54
|
+
${c.bold}vibecheck validate${c.reset} - Validate AI-generated code for hallucinations
|
|
55
|
+
|
|
56
|
+
${c.bold}USAGE${c.reset}
|
|
57
|
+
vibecheck validate [file] [options]
|
|
58
|
+
|
|
59
|
+
${c.bold}OPTIONS${c.reset}
|
|
60
|
+
--help, -h Show this help
|
|
61
|
+
--json Output as JSON
|
|
62
|
+
--verbose, -v Show detailed output
|
|
63
|
+
|
|
64
|
+
${c.bold}WHAT IT CHECKS${c.reset}
|
|
65
|
+
- API routes referenced but not defined
|
|
66
|
+
- Env vars used but not declared
|
|
67
|
+
- Imports that don't exist
|
|
68
|
+
- Function calls to undefined functions
|
|
69
|
+
|
|
70
|
+
${c.bold}EXAMPLES${c.reset}
|
|
71
|
+
vibecheck validate # Validate all files
|
|
72
|
+
vibecheck validate src/api/route.ts # Validate specific file
|
|
73
|
+
vibecheck validate --json # JSON output
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function runValidate(args) {
|
|
78
|
+
const opts = parseArgs(args);
|
|
79
|
+
|
|
80
|
+
if (opts.help) {
|
|
81
|
+
printHelp();
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const projectPath = process.cwd();
|
|
86
|
+
|
|
87
|
+
console.log(`\n${c.bold}🔍 Validating code for hallucinations...${c.reset}\n`);
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Build truthpack for validation
|
|
91
|
+
const truthpack = await buildTruthpack({ repoRoot: projectPath });
|
|
92
|
+
|
|
93
|
+
const issues = [];
|
|
94
|
+
|
|
95
|
+
// Check for missing routes
|
|
96
|
+
const clientRefs = truthpack.routes?.clientRefs || [];
|
|
97
|
+
const serverRoutes = truthpack.routes?.server || [];
|
|
98
|
+
|
|
99
|
+
for (const ref of clientRefs) {
|
|
100
|
+
const method = ref.method || "*";
|
|
101
|
+
const p = ref.path;
|
|
102
|
+
const exists = serverRoutes.some(r => routeMatches(r, method, p) || routeMatches(r, "*", p));
|
|
103
|
+
|
|
104
|
+
if (!exists) {
|
|
105
|
+
issues.push({
|
|
106
|
+
type: "missing_route",
|
|
107
|
+
severity: "error",
|
|
108
|
+
message: `Route ${method} ${p} is referenced but not defined`,
|
|
109
|
+
file: ref.evidence?.[0]?.file || "unknown",
|
|
110
|
+
line: ref.evidence?.[0]?.lines?.split("-")[0] || 1,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Check for undeclared env vars (excluding system vars)
|
|
116
|
+
const envVars = truthpack.env?.vars || [];
|
|
117
|
+
const declared = new Set(truthpack.env?.declared || []);
|
|
118
|
+
const systemVars = new Set([
|
|
119
|
+
'HOME', 'USER', 'PATH', 'NODE_ENV', 'CI', 'DEBUG', 'PORT',
|
|
120
|
+
'APPDATA', 'USERPROFILE', 'COMPUTERNAME', 'HOSTNAME',
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
for (const v of envVars) {
|
|
124
|
+
if (!declared.has(v.name) && !systemVars.has(v.name) && v.name.startsWith("VIBECHECK_")) {
|
|
125
|
+
issues.push({
|
|
126
|
+
type: "undeclared_env",
|
|
127
|
+
severity: "warning",
|
|
128
|
+
message: `Env var ${v.name} is used but not declared in .env.example`,
|
|
129
|
+
file: v.references?.[0]?.file || "unknown",
|
|
130
|
+
line: v.references?.[0]?.lines?.split("-")[0] || 1,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Output results
|
|
136
|
+
if (opts.json) {
|
|
137
|
+
console.log(JSON.stringify({ issues, valid: issues.length === 0 }, null, 2));
|
|
138
|
+
} else {
|
|
139
|
+
if (issues.length === 0) {
|
|
140
|
+
console.log(`${c.green}✓${c.reset} No hallucinations detected!\n`);
|
|
141
|
+
console.log(` ${c.dim}All routes and env vars are properly defined.${c.reset}\n`);
|
|
142
|
+
} else {
|
|
143
|
+
console.log(`${c.yellow}⚠${c.reset} Found ${issues.length} potential issues:\n`);
|
|
144
|
+
|
|
145
|
+
for (const issue of issues) {
|
|
146
|
+
const icon = issue.severity === "error" ? `${c.red}✗${c.reset}` : `${c.yellow}⚠${c.reset}`;
|
|
147
|
+
console.log(` ${icon} ${issue.message}`);
|
|
148
|
+
console.log(` ${c.dim}${issue.file}:${issue.line}${c.reset}`);
|
|
149
|
+
}
|
|
150
|
+
console.log();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return issues.some(i => i.severity === "error") ? 1 : 0;
|
|
155
|
+
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error(`${c.red}✗${c.reset} Validation failed: ${error.message}`);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
2
162
|
module.exports = { runValidate };
|
package/bin/vibecheck.js
CHANGED
|
@@ -298,6 +298,11 @@ ${c.dim}Run ${c.cyan}vibecheck login${c.dim} anytime to upgrade.${c.reset}
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
async function checkCommandAccess(cmd, entitlements, args = []) {
|
|
301
|
+
// Development mode - bypass all tier checks
|
|
302
|
+
if (process.env.VIBECHECK_SKIP_AUTH) {
|
|
303
|
+
return { allowed: true, tier: "dev" };
|
|
304
|
+
}
|
|
305
|
+
|
|
301
306
|
// Free commands always work (no API key needed)
|
|
302
307
|
if (FREE_COMMANDS.includes(cmd)) {
|
|
303
308
|
return { allowed: true, tier: "free" };
|
|
@@ -730,7 +735,7 @@ ${c.dim}Run 'vibecheck <command> --help' for details.${c.reset}
|
|
|
730
735
|
exitCode = await runValidate(args);
|
|
731
736
|
break;
|
|
732
737
|
case "doctor":
|
|
733
|
-
exitCode = runDoctor(args);
|
|
738
|
+
exitCode = await runDoctor(args);
|
|
734
739
|
break;
|
|
735
740
|
case "init":
|
|
736
741
|
// Enterprise init handles all flags including --gha, --gitlab, --compliance, etc.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibecheckai/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "Vibecheck CLI - Ship with confidence. One verdict: SHIP | WARN | BLOCK.",
|
|
5
5
|
"main": "bin/vibecheck.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
"README.md",
|
|
13
13
|
"LICENSE"
|
|
14
14
|
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "node scripts/copy-runners.js",
|
|
17
|
+
"build:legacy": "node scripts/build.js",
|
|
18
|
+
"dev": "node ../../bin/vibecheck.js",
|
|
19
|
+
"start": "node bin/vibecheck.js",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
15
22
|
"dependencies": {
|
|
16
23
|
"@babel/parser": "^7.23.0",
|
|
17
24
|
"@babel/traverse": "^7.23.0",
|
|
@@ -67,11 +74,5 @@
|
|
|
67
74
|
},
|
|
68
75
|
"publishConfig": {
|
|
69
76
|
"access": "public"
|
|
70
|
-
},
|
|
71
|
-
"scripts": {
|
|
72
|
-
"build": "node scripts/copy-runners.js",
|
|
73
|
-
"build:legacy": "node scripts/build.js",
|
|
74
|
-
"dev": "node ../../bin/vibecheck.js",
|
|
75
|
-
"start": "node bin/vibecheck.js"
|
|
76
77
|
}
|
|
77
|
-
}
|
|
78
|
+
}
|