@vibecheckai/cli 3.5.0 → 3.5.1
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/registry.js +174 -449
- package/bin/runners/cli-utils.js +33 -2
- package/bin/runners/context/generators/cursor.js +2 -49
- package/bin/runners/context/generators/mcp.js +13 -15
- package/bin/runners/context/proof-context.js +1 -248
- package/bin/runners/lib/analysis-core.js +180 -198
- package/bin/runners/lib/analyzers.js +241 -2212
- package/bin/runners/lib/cli-output.js +210 -242
- package/bin/runners/lib/detectors-v2.js +785 -547
- package/bin/runners/lib/entitlements-v2.js +431 -161
- package/bin/runners/lib/error-handler.js +9 -16
- package/bin/runners/lib/global-flags.js +0 -37
- package/bin/runners/lib/html-proof-report.js +700 -350
- package/bin/runners/lib/missions/plan.js +6 -46
- package/bin/runners/lib/missions/templates.js +0 -232
- package/bin/runners/lib/route-truth.js +322 -1167
- package/bin/runners/lib/scan-output.js +467 -493
- package/bin/runners/lib/ship-output.js +27 -280
- package/bin/runners/lib/terminal-ui.js +700 -310
- package/bin/runners/lib/truth.js +321 -1004
- package/bin/runners/lib/unified-output.js +158 -162
- package/bin/runners/lib/upsell.js +204 -104
- package/bin/runners/runAIAgent.js +10 -5
- package/bin/runners/runAllowlist.js +324 -0
- package/bin/runners/runAuth.js +94 -344
- package/bin/runners/runCheckpoint.js +45 -43
- package/bin/runners/runContext.js +24 -139
- package/bin/runners/runDoctor.js +101 -136
- package/bin/runners/runEvidencePack.js +219 -0
- package/bin/runners/runFix.js +71 -82
- package/bin/runners/runGuard.js +119 -606
- package/bin/runners/runInit.js +60 -22
- package/bin/runners/runInstall.js +281 -0
- package/bin/runners/runLabs.js +341 -0
- package/bin/runners/runMcp.js +62 -139
- package/bin/runners/runPolish.js +83 -282
- package/bin/runners/runPromptFirewall.js +12 -5
- package/bin/runners/runProve.js +58 -33
- package/bin/runners/runReality.js +58 -81
- package/bin/runners/runReport.js +7 -34
- package/bin/runners/runRuntime.js +8 -5
- package/bin/runners/runScan.js +844 -219
- package/bin/runners/runShip.js +59 -721
- package/bin/runners/runValidate.js +11 -24
- package/bin/runners/runWatch.js +76 -131
- package/bin/vibecheck.js +69 -295
- package/mcp-server/ARCHITECTURE.md +339 -0
- package/mcp-server/__tests__/cache.test.ts +313 -0
- package/mcp-server/__tests__/executor.test.ts +239 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.cache/webpack/cache.pack +1 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.next/server/chunk.js +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.turbo/cache.json +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.venv/lib/env.py +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/dist/bundle.js +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/package.json +5 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/src/app.ts +5 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/venv/lib/config.py +4 -0
- package/mcp-server/__tests__/ids.test.ts +345 -0
- package/mcp-server/__tests__/integration/tools.test.ts +410 -0
- package/mcp-server/__tests__/registry.test.ts +365 -0
- package/mcp-server/__tests__/sandbox.test.ts +323 -0
- package/mcp-server/__tests__/schemas.test.ts +372 -0
- package/mcp-server/benchmarks/run-benchmarks.ts +304 -0
- package/mcp-server/examples/doctor.request.json +14 -0
- package/mcp-server/examples/doctor.response.json +53 -0
- package/mcp-server/examples/error.response.json +15 -0
- package/mcp-server/examples/scan.request.json +14 -0
- package/mcp-server/examples/scan.response.json +108 -0
- package/mcp-server/handlers/tool-handler.ts +671 -0
- package/mcp-server/index-v1.js +698 -0
- package/mcp-server/index-v3.ts +293 -0
- package/mcp-server/index.js +1080 -1757
- package/mcp-server/index.old.js +4137 -0
- package/mcp-server/lib/cache.ts +341 -0
- package/mcp-server/lib/errors.ts +346 -0
- package/mcp-server/lib/executor.ts +792 -0
- package/mcp-server/lib/ids.ts +238 -0
- package/mcp-server/lib/logger.ts +368 -0
- package/mcp-server/lib/metrics.ts +365 -0
- package/mcp-server/lib/sandbox.ts +337 -0
- package/mcp-server/lib/validator.ts +229 -0
- package/mcp-server/package-lock.json +165 -0
- package/mcp-server/package.json +32 -7
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/registry/tools.json +476 -0
- package/mcp-server/schemas/error-envelope.schema.json +125 -0
- package/mcp-server/schemas/finding.schema.json +167 -0
- package/mcp-server/schemas/report-artifact.schema.json +88 -0
- package/mcp-server/schemas/run-request.schema.json +75 -0
- package/mcp-server/schemas/verdict.schema.json +168 -0
- package/mcp-server/tier-auth.d.ts +71 -0
- package/mcp-server/tier-auth.js +371 -183
- package/mcp-server/truth-context.js +90 -131
- package/mcp-server/truth-firewall-tools.js +1000 -1611
- package/mcp-server/tsconfig.json +34 -0
- package/mcp-server/vibecheck-tools.js +2 -2
- package/mcp-server/vitest.config.ts +16 -0
- package/package.json +3 -4
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +0 -474
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +0 -488
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +0 -228
- package/bin/runners/lib/agent-firewall/change-packet/store.js +0 -200
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +0 -21
- package/bin/runners/lib/agent-firewall/claims/extractor.js +0 -303
- package/bin/runners/lib/agent-firewall/claims/patterns.js +0 -24
- package/bin/runners/lib/agent-firewall/critic/index.js +0 -151
- package/bin/runners/lib/agent-firewall/critic/judge.js +0 -432
- package/bin/runners/lib/agent-firewall/critic/prompts.js +0 -305
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +0 -88
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +0 -75
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +0 -127
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +0 -102
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +0 -213
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +0 -145
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +0 -19
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +0 -87
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +0 -184
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +0 -163
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +0 -107
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +0 -68
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +0 -66
- package/bin/runners/lib/agent-firewall/interceptor/base.js +0 -304
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +0 -35
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +0 -35
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +0 -34
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +0 -465
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +0 -604
- package/bin/runners/lib/agent-firewall/lawbook/index.js +0 -304
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +0 -514
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +0 -420
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
- package/bin/runners/lib/agent-firewall/logger.js +0 -141
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +0 -90
- package/bin/runners/lib/agent-firewall/policy/engine.js +0 -103
- package/bin/runners/lib/agent-firewall/policy/loader.js +0 -451
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +0 -50
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +0 -50
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +0 -86
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +0 -162
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +0 -189
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +0 -93
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +0 -57
- package/bin/runners/lib/agent-firewall/policy/schema.json +0 -183
- package/bin/runners/lib/agent-firewall/policy/verdict.js +0 -54
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +0 -394
- package/bin/runners/lib/agent-firewall/proposal/index.js +0 -212
- package/bin/runners/lib/agent-firewall/proposal/schema.js +0 -251
- package/bin/runners/lib/agent-firewall/proposal/validator.js +0 -386
- package/bin/runners/lib/agent-firewall/reality/index.js +0 -332
- package/bin/runners/lib/agent-firewall/reality/state.js +0 -625
- package/bin/runners/lib/agent-firewall/reality/watcher.js +0 -322
- package/bin/runners/lib/agent-firewall/risk/index.js +0 -173
- package/bin/runners/lib/agent-firewall/risk/scorer.js +0 -328
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +0 -321
- package/bin/runners/lib/agent-firewall/risk/vectors.js +0 -421
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +0 -472
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +0 -346
- package/bin/runners/lib/agent-firewall/simulator/index.js +0 -181
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +0 -380
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +0 -661
- package/bin/runners/lib/agent-firewall/time-machine/index.js +0 -267
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +0 -436
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +0 -490
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +0 -530
- package/bin/runners/lib/agent-firewall/truthpack/index.js +0 -67
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +0 -137
- package/bin/runners/lib/agent-firewall/unblock/planner.js +0 -337
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +0 -118
- package/bin/runners/lib/api-client.js +0 -269
- package/bin/runners/lib/audit-logger.js +0 -532
- package/bin/runners/lib/authority/authorities/architecture.js +0 -364
- package/bin/runners/lib/authority/authorities/compliance.js +0 -341
- package/bin/runners/lib/authority/authorities/human.js +0 -343
- package/bin/runners/lib/authority/authorities/quality.js +0 -420
- package/bin/runners/lib/authority/authorities/security.js +0 -228
- package/bin/runners/lib/authority/index.js +0 -293
- package/bin/runners/lib/authority-badge.js +0 -425
- package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
- package/bin/runners/lib/cli-charts.js +0 -368
- package/bin/runners/lib/cli-config-display.js +0 -405
- package/bin/runners/lib/cli-demo.js +0 -275
- package/bin/runners/lib/cli-errors.js +0 -438
- package/bin/runners/lib/cli-help-formatter.js +0 -439
- package/bin/runners/lib/cli-interactive-menu.js +0 -509
- package/bin/runners/lib/cli-prompts.js +0 -441
- package/bin/runners/lib/cli-scan-cards.js +0 -362
- package/bin/runners/lib/compliance-reporter.js +0 -710
- package/bin/runners/lib/conductor/index.js +0 -671
- package/bin/runners/lib/easy/README.md +0 -123
- package/bin/runners/lib/easy/index.js +0 -140
- package/bin/runners/lib/easy/interactive-wizard.js +0 -788
- package/bin/runners/lib/easy/one-click-firewall.js +0 -564
- package/bin/runners/lib/easy/zero-config-reality.js +0 -714
- package/bin/runners/lib/engines/accessibility-engine.js +0 -390
- package/bin/runners/lib/engines/api-consistency-engine.js +0 -467
- package/bin/runners/lib/engines/ast-cache.js +0 -99
- package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
- package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
- package/bin/runners/lib/engines/code-quality-engine.js +0 -255
- package/bin/runners/lib/engines/confidence-scoring.js +0 -276
- package/bin/runners/lib/engines/console-logs-engine.js +0 -115
- package/bin/runners/lib/engines/context-detection.js +0 -264
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +0 -533
- package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
- package/bin/runners/lib/engines/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/deprecated-api-engine.js +0 -226
- package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
- package/bin/runners/lib/engines/empty-catch-engine.js +0 -260
- package/bin/runners/lib/engines/env-variables-engine.js +0 -458
- package/bin/runners/lib/engines/error-handling-engine.js +0 -437
- package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
- package/bin/runners/lib/engines/file-filter.js +0 -131
- package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
- package/bin/runners/lib/engines/framework-detection.js +0 -508
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +0 -251
- package/bin/runners/lib/engines/import-order-engine.js +0 -429
- package/bin/runners/lib/engines/mock-data-engine.js +0 -315
- package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
- package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
- package/bin/runners/lib/engines/orchestrator.js +0 -334
- package/bin/runners/lib/engines/parallel-processor.js +0 -71
- package/bin/runners/lib/engines/performance-issues-engine.js +0 -405
- package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +0 -571
- package/bin/runners/lib/engines/todo-fixme-engine.js +0 -115
- package/bin/runners/lib/engines/type-aware-engine.js +0 -376
- package/bin/runners/lib/engines/unsafe-regex-engine.js +0 -225
- package/bin/runners/lib/engines/vibecheck-engines/README.md +0 -53
- package/bin/runners/lib/engines/vibecheck-engines/index.js +0 -124
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +0 -439
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
- package/bin/runners/lib/engines/vibecheck-engines/package.json +0 -13
- package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
- package/bin/runners/lib/enhanced-features/index.js +0 -305
- package/bin/runners/lib/enhanced-output.js +0 -631
- package/bin/runners/lib/enterprise.js +0 -300
- package/bin/runners/lib/exit-codes.js +0 -275
- package/bin/runners/lib/fingerprint.js +0 -377
- package/bin/runners/lib/firewall/command-validator.js +0 -351
- package/bin/runners/lib/firewall/config.js +0 -341
- package/bin/runners/lib/firewall/content-validator.js +0 -519
- package/bin/runners/lib/firewall/index.js +0 -101
- package/bin/runners/lib/firewall/path-validator.js +0 -256
- package/bin/runners/lib/help-formatter.js +0 -413
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
- package/bin/runners/lib/logger.js +0 -38
- package/bin/runners/lib/mcp-utils.js +0 -425
- package/bin/runners/lib/output/index.js +0 -1022
- package/bin/runners/lib/policy-engine.js +0 -652
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
- package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
- package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
- package/bin/runners/lib/polish/autofix/index.js +0 -200
- package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
- package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
- package/bin/runners/lib/polish/backend-checks.js +0 -148
- package/bin/runners/lib/polish/documentation-checks.js +0 -111
- package/bin/runners/lib/polish/frontend-checks.js +0 -168
- package/bin/runners/lib/polish/index.js +0 -71
- package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
- package/bin/runners/lib/polish/library-detection.js +0 -175
- package/bin/runners/lib/polish/performance-checks.js +0 -100
- package/bin/runners/lib/polish/security-checks.js +0 -148
- package/bin/runners/lib/polish/utils.js +0 -203
- package/bin/runners/lib/prompt-builder.js +0 -540
- package/bin/runners/lib/proof-certificate.js +0 -634
- package/bin/runners/lib/reality/accessibility-audit.js +0 -946
- package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
- package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
- package/bin/runners/lib/reality/performance-tracker.js +0 -1077
- package/bin/runners/lib/reality/scenario-generator.js +0 -1404
- package/bin/runners/lib/reality/visual-regression.js +0 -852
- package/bin/runners/lib/reality-profiler.js +0 -717
- package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
- package/bin/runners/lib/review/ai-code-review.js +0 -832
- package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
- package/bin/runners/lib/sbom-generator.js +0 -641
- package/bin/runners/lib/scan-output-enhanced.js +0 -512
- package/bin/runners/lib/security/owasp-scanner.js +0 -939
- package/bin/runners/lib/ship-output-enterprise.js +0 -239
- package/bin/runners/lib/unified-cli-output.js +0 -777
- package/bin/runners/lib/validators/contract-validator.js +0 -283
- package/bin/runners/lib/validators/dead-export-detector.js +0 -279
- package/bin/runners/lib/validators/dep-audit.js +0 -245
- package/bin/runners/lib/validators/env-validator.js +0 -319
- package/bin/runners/lib/validators/index.js +0 -120
- package/bin/runners/lib/validators/license-checker.js +0 -252
- package/bin/runners/lib/validators/route-validator.js +0 -290
- package/bin/runners/runAgent.d.ts +0 -5
- package/bin/runners/runAgent.js +0 -164
- package/bin/runners/runApprove.js +0 -1233
- package/bin/runners/runAuthority.js +0 -528
- package/bin/runners/runClassify.js +0 -862
- package/bin/runners/runConductor.js +0 -772
- package/bin/runners/runContainer.js +0 -366
- package/bin/runners/runContext.d.ts +0 -4
- package/bin/runners/runEasy.js +0 -410
- package/bin/runners/runFirewall.d.ts +0 -5
- package/bin/runners/runFirewall.js +0 -137
- package/bin/runners/runFirewallHook.d.ts +0 -5
- package/bin/runners/runFirewallHook.js +0 -59
- package/bin/runners/runIaC.js +0 -372
- package/bin/runners/runPolish.d.ts +0 -4
- package/bin/runners/runProof.zip +0 -0
- package/bin/runners/runTruth.d.ts +0 -5
- package/bin/runners/runTruth.js +0 -104
- package/bin/runners/runVibe.js +0 -791
- package/mcp-server/HARDENING_SUMMARY.md +0 -299
- package/mcp-server/agent-firewall-interceptor.js +0 -500
- package/mcp-server/authority-tools.js +0 -569
- package/mcp-server/conductor/conflict-resolver.js +0 -588
- package/mcp-server/conductor/execution-planner.js +0 -544
- package/mcp-server/conductor/index.js +0 -377
- package/mcp-server/conductor/lock-manager.js +0 -615
- package/mcp-server/conductor/request-queue.js +0 -550
- package/mcp-server/conductor/session-manager.js +0 -500
- package/mcp-server/conductor/tools.js +0 -510
- package/mcp-server/lib/api-client.cjs +0 -13
- package/mcp-server/lib/logger.cjs +0 -30
- package/mcp-server/logger.js +0 -173
- package/mcp-server/tools-v3.js +0 -1039
- package/mcp-server/tools.js +0 -495
- package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
package/bin/runners/runShip.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vibecheck ship -
|
|
3
|
-
*
|
|
4
|
-
* The comprehensive analysis command running:
|
|
5
|
-
* - ALL 17+ scan engines (vs 5 in quick scan)
|
|
6
|
-
* - Ship-only validators (route integrity, contracts, deps, licenses, env, dead exports)
|
|
7
|
-
* - Production Readiness Score calculation
|
|
8
|
-
* - SHIP/WARN/BLOCK verdict with proof certificate
|
|
2
|
+
* vibecheck ship - The Vibe Coder's Best Friend
|
|
3
|
+
* Zero config. Plain English. One command to ship with confidence.
|
|
9
4
|
*
|
|
10
5
|
* ═══════════════════════════════════════════════════════════════════════════════
|
|
11
6
|
* ENTERPRISE EDITION - World-Class Terminal Experience
|
|
@@ -16,73 +11,20 @@ const path = require("path");
|
|
|
16
11
|
const fs = require("fs");
|
|
17
12
|
const { withErrorHandling } = require("./lib/error-handler");
|
|
18
13
|
const { ensureOutputDir, detectProjectFeatures } = require("./utils");
|
|
19
|
-
const { enforceLimit, enforceFeature, trackUsage, getCurrentTier } = require("./lib/entitlements
|
|
14
|
+
const { enforceLimit, enforceFeature, trackUsage, getCurrentTier } = require("./lib/entitlements");
|
|
20
15
|
const { emitShipCheck } = require("./lib/audit-bridge");
|
|
21
16
|
const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
|
|
22
17
|
const {
|
|
23
18
|
generateRunId,
|
|
24
19
|
createJsonOutput,
|
|
25
20
|
writeJsonOutput,
|
|
21
|
+
exitCodeToVerdict,
|
|
22
|
+
verdictToExitCode,
|
|
26
23
|
saveArtifact
|
|
27
24
|
} = require("./lib/cli-output");
|
|
28
|
-
const { EXIT, verdictToExitCode, exitCodeToVerdict } = require("./lib/exit-codes");
|
|
29
|
-
|
|
30
|
-
// NEW: Import orchestrator and validators
|
|
31
|
-
const { runShipEngines, ALL_ENGINES } = require("./lib/engines/orchestrator");
|
|
32
|
-
const { runShipValidators } = require("./lib/validators");
|
|
33
25
|
|
|
34
26
|
// Route Truth v1 - Fake endpoint detection
|
|
35
27
|
const { buildTruthpack, writeTruthpack, detectFastifyEntry } = require("./lib/truth");
|
|
36
|
-
|
|
37
|
-
// Helper to normalize severity for ship verdict
|
|
38
|
-
function normalizeSeverityForShip(sev) {
|
|
39
|
-
if (!sev) return 'WARN';
|
|
40
|
-
const s = String(sev).toLowerCase();
|
|
41
|
-
if (s === 'block' || s === 'critical' || s === 'high') return 'BLOCK';
|
|
42
|
-
if (s === 'warn' || s === 'warning' || s === 'medium') return 'WARN';
|
|
43
|
-
return 'INFO';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Helper to categorize findings for score breakdown
|
|
47
|
-
function categorizeFindings(finding) {
|
|
48
|
-
const category = (finding.category || '').toLowerCase();
|
|
49
|
-
const engine = (finding.engine || '').toLowerCase();
|
|
50
|
-
const validator = (finding.validator || '').toLowerCase();
|
|
51
|
-
|
|
52
|
-
// Security
|
|
53
|
-
if (category.includes('secret') || category.includes('security') ||
|
|
54
|
-
category.includes('auth') || category.includes('billing') ||
|
|
55
|
-
engine.includes('secret') || engine.includes('security')) {
|
|
56
|
-
return 'security';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Hallucinations
|
|
60
|
-
if (category.includes('hallucination') || category.includes('fake') ||
|
|
61
|
-
category.includes('mock') || engine.includes('hallucination')) {
|
|
62
|
-
return 'hallucination';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Routes
|
|
66
|
-
if (category.includes('route') || category.includes('missing') ||
|
|
67
|
-
validator.includes('route')) {
|
|
68
|
-
return 'routes';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Contracts
|
|
72
|
-
if (category.includes('contract') || category.includes('drift') ||
|
|
73
|
-
validator.includes('contract')) {
|
|
74
|
-
return 'contracts';
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Dependencies
|
|
78
|
-
if (category.includes('dependency') || category.includes('license') ||
|
|
79
|
-
validator.includes('dep') || validator.includes('license')) {
|
|
80
|
-
return 'dependencies';
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Default to quality
|
|
84
|
-
return 'quality';
|
|
85
|
-
}
|
|
86
28
|
const {
|
|
87
29
|
findMissingRoutes,
|
|
88
30
|
findEnvGaps,
|
|
@@ -97,213 +39,6 @@ const { findContractDrift, loadContracts, hasContracts, getDriftSummary } = requ
|
|
|
97
39
|
const upsell = require("./lib/upsell");
|
|
98
40
|
const entitlements = require("./lib/entitlements-v2");
|
|
99
41
|
|
|
100
|
-
// V7: World-class proof certificate and risk radar
|
|
101
|
-
let proofCertificate;
|
|
102
|
-
try {
|
|
103
|
-
proofCertificate = require("./lib/proof-certificate");
|
|
104
|
-
} catch (e) {
|
|
105
|
-
proofCertificate = null;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Import vibecheck engines for enhanced analysis
|
|
109
|
-
let vibeEngines;
|
|
110
|
-
try {
|
|
111
|
-
vibeEngines = require("./lib/engines/vibecheck-engines");
|
|
112
|
-
} catch (e) {
|
|
113
|
-
vibeEngines = null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
117
|
-
// ENHANCED ANALYSIS WITH VIBECHECK ENGINES
|
|
118
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
119
|
-
|
|
120
|
-
const CODE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
121
|
-
const IGNORE_PATTERNS = ['node_modules', '.git', 'dist', 'build', '.next', '.nuxt', 'coverage', '__pycache__', '.vibecheck'];
|
|
122
|
-
|
|
123
|
-
function* walkFilesForShip(dir, depth = 0, maxDepth = 8) {
|
|
124
|
-
if (depth > maxDepth) return;
|
|
125
|
-
|
|
126
|
-
let entries;
|
|
127
|
-
try {
|
|
128
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
129
|
-
} catch {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
for (const entry of entries) {
|
|
134
|
-
const fullPath = path.join(dir, entry.name);
|
|
135
|
-
|
|
136
|
-
if (entry.isDirectory()) {
|
|
137
|
-
if (IGNORE_PATTERNS.some(p => entry.name.includes(p))) continue;
|
|
138
|
-
yield* walkFilesForShip(fullPath, depth + 1, maxDepth);
|
|
139
|
-
} else if (entry.isFile()) {
|
|
140
|
-
const ext = path.extname(entry.name);
|
|
141
|
-
if (CODE_EXTENSIONS.includes(ext)) {
|
|
142
|
-
yield fullPath;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async function runVibeEngineAnalysis(projectPath, opts = {}) {
|
|
149
|
-
if (!vibeEngines) return [];
|
|
150
|
-
|
|
151
|
-
const findings = [];
|
|
152
|
-
const files = Array.from(walkFilesForShip(projectPath));
|
|
153
|
-
|
|
154
|
-
// Limit files to analyze in ship mode (performance)
|
|
155
|
-
const filesToAnalyze = files.slice(0, 500);
|
|
156
|
-
|
|
157
|
-
for (const filePath of filesToAnalyze) {
|
|
158
|
-
try {
|
|
159
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
160
|
-
|
|
161
|
-
// Skip test files unless explicitly included
|
|
162
|
-
if (!opts.includeTests && (
|
|
163
|
-
filePath.includes('.test.') ||
|
|
164
|
-
filePath.includes('.spec.') ||
|
|
165
|
-
filePath.includes('__tests__')
|
|
166
|
-
)) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Run async patterns analysis - critical for production
|
|
171
|
-
if (vibeEngines.analyzeAsyncPatterns) {
|
|
172
|
-
try {
|
|
173
|
-
const asyncFindings = vibeEngines.analyzeAsyncPatterns(content, filePath);
|
|
174
|
-
findings.push(...asyncFindings.filter(f =>
|
|
175
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
176
|
-
).map(f => ({
|
|
177
|
-
...f,
|
|
178
|
-
category: f.category || 'AsyncPatterns',
|
|
179
|
-
// Map to ship finding format
|
|
180
|
-
title: f.title,
|
|
181
|
-
why: f.message,
|
|
182
|
-
severity: f.severity,
|
|
183
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
184
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
185
|
-
})));
|
|
186
|
-
} catch {}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Run env variable analysis - security critical
|
|
190
|
-
if (vibeEngines.analyzeEnvVariables) {
|
|
191
|
-
try {
|
|
192
|
-
const envFindings = vibeEngines.analyzeEnvVariables(content, filePath);
|
|
193
|
-
findings.push(...envFindings.filter(f =>
|
|
194
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
195
|
-
).map(f => ({
|
|
196
|
-
...f,
|
|
197
|
-
category: f.category || 'EnvVariable',
|
|
198
|
-
title: f.title,
|
|
199
|
-
why: f.message,
|
|
200
|
-
severity: f.severity,
|
|
201
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
202
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
203
|
-
})));
|
|
204
|
-
} catch {}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Run AI hallucination detection - core vibecheck functionality
|
|
208
|
-
if (vibeEngines.analyzeAIHallucinations) {
|
|
209
|
-
try {
|
|
210
|
-
const aiFindings = vibeEngines.analyzeAIHallucinations(content, filePath, {
|
|
211
|
-
includeTests: opts.includeTests || false,
|
|
212
|
-
});
|
|
213
|
-
findings.push(...aiFindings.filter(f =>
|
|
214
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
215
|
-
).map(f => ({
|
|
216
|
-
...f,
|
|
217
|
-
category: f.category || 'AIHallucination',
|
|
218
|
-
title: f.title || f.type,
|
|
219
|
-
why: f.message,
|
|
220
|
-
severity: f.severity,
|
|
221
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
222
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
223
|
-
})));
|
|
224
|
-
} catch {}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Run React patterns analysis (critical for React apps)
|
|
228
|
-
if (vibeEngines.analyzeReactPatterns) {
|
|
229
|
-
try {
|
|
230
|
-
const reactFindings = vibeEngines.analyzeReactPatterns(content, filePath);
|
|
231
|
-
findings.push(...reactFindings.filter(f =>
|
|
232
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
233
|
-
).map(f => ({
|
|
234
|
-
...f,
|
|
235
|
-
category: f.category || 'ReactPatterns',
|
|
236
|
-
title: f.title,
|
|
237
|
-
why: f.message,
|
|
238
|
-
severity: f.severity,
|
|
239
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
240
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
241
|
-
})));
|
|
242
|
-
} catch {}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Run database patterns analysis (critical for production)
|
|
246
|
-
if (vibeEngines.analyzeDatabasePatterns) {
|
|
247
|
-
try {
|
|
248
|
-
const dbFindings = vibeEngines.analyzeDatabasePatterns(content, filePath);
|
|
249
|
-
findings.push(...dbFindings.filter(f =>
|
|
250
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
251
|
-
).map(f => ({
|
|
252
|
-
...f,
|
|
253
|
-
category: f.category || 'DatabasePatterns',
|
|
254
|
-
title: f.title,
|
|
255
|
-
why: f.message,
|
|
256
|
-
severity: f.severity,
|
|
257
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
258
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
259
|
-
})));
|
|
260
|
-
} catch {}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Run error handling analysis
|
|
264
|
-
if (vibeEngines.analyzeErrorHandling) {
|
|
265
|
-
try {
|
|
266
|
-
const errorFindings = vibeEngines.analyzeErrorHandling(content, filePath);
|
|
267
|
-
findings.push(...errorFindings.filter(f =>
|
|
268
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
269
|
-
).map(f => ({
|
|
270
|
-
...f,
|
|
271
|
-
category: f.category || 'ErrorHandling',
|
|
272
|
-
title: f.title,
|
|
273
|
-
why: f.message,
|
|
274
|
-
severity: f.severity,
|
|
275
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
276
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
277
|
-
})));
|
|
278
|
-
} catch {}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
} catch (e) {
|
|
282
|
-
// Skip files that can't be read
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Run env setup analysis at project level
|
|
287
|
-
if (vibeEngines.analyzeEnvSetup) {
|
|
288
|
-
try {
|
|
289
|
-
const setupFindings = vibeEngines.analyzeEnvSetup(projectPath);
|
|
290
|
-
findings.push(...setupFindings.filter(f =>
|
|
291
|
-
f.severity === 'BLOCK' || f.severity === 'WARN'
|
|
292
|
-
).map(f => ({
|
|
293
|
-
...f,
|
|
294
|
-
category: f.category || 'EnvSetup',
|
|
295
|
-
title: f.title,
|
|
296
|
-
why: f.message,
|
|
297
|
-
severity: f.severity,
|
|
298
|
-
evidence: [{ file: f.file, lines: String(f.line) }],
|
|
299
|
-
fixHints: [f.fixHint].filter(Boolean),
|
|
300
|
-
})));
|
|
301
|
-
} catch {}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
return findings;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
42
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
308
43
|
// ENHANCED TERMINAL UI & OUTPUT MODULES
|
|
309
44
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -319,7 +54,7 @@ const {
|
|
|
319
54
|
} = require("./lib/terminal-ui");
|
|
320
55
|
|
|
321
56
|
const {
|
|
322
|
-
formatShipOutput
|
|
57
|
+
formatShipOutput,
|
|
323
58
|
renderVerdictCard,
|
|
324
59
|
renderFixModeHeader,
|
|
325
60
|
renderFixResults,
|
|
@@ -329,13 +64,6 @@ const {
|
|
|
329
64
|
shipIcons,
|
|
330
65
|
} = require("./lib/ship-output");
|
|
331
66
|
|
|
332
|
-
// Unified Output System
|
|
333
|
-
const { output } = require("./lib/output/index.js");
|
|
334
|
-
|
|
335
|
-
const {
|
|
336
|
-
formatShipOutput,
|
|
337
|
-
} = require("./lib/ship-output-enterprise");
|
|
338
|
-
|
|
339
67
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
340
68
|
// PREMIUM BANNER
|
|
341
69
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -628,8 +356,6 @@ function getCategoryIcon(category) {
|
|
|
628
356
|
'MissingRoute': ICONS.route,
|
|
629
357
|
'EnvContract': ICONS.env,
|
|
630
358
|
'EnvGap': ICONS.env,
|
|
631
|
-
'EnvVariable': ICONS.env,
|
|
632
|
-
'EnvSetup': ICONS.env,
|
|
633
359
|
'FakeSuccess': ICONS.ghost,
|
|
634
360
|
'GhostAuth': ICONS.auth,
|
|
635
361
|
'StripeWebhook': ICONS.money,
|
|
@@ -640,33 +366,6 @@ function getCategoryIcon(category) {
|
|
|
640
366
|
'Security': ICONS.shield,
|
|
641
367
|
'Auth': ICONS.lock,
|
|
642
368
|
'Fake Code': ICONS.ghost,
|
|
643
|
-
// New engine categories
|
|
644
|
-
'AsyncPatterns': ICONS.lightning,
|
|
645
|
-
'AIHallucination': ICONS.ghost,
|
|
646
|
-
'NamingConventions': '📝',
|
|
647
|
-
'floating_promise': ICONS.lightning,
|
|
648
|
-
'empty_async_catch': ICONS.bug,
|
|
649
|
-
'exposed_secret': ICONS.key,
|
|
650
|
-
'insecure_default': ICONS.warning,
|
|
651
|
-
// React patterns
|
|
652
|
-
'ReactPatterns': '⚛️',
|
|
653
|
-
'missing_key': '⚛️',
|
|
654
|
-
'conditional_hook': '⚛️',
|
|
655
|
-
'direct_state_mutation': '⚛️',
|
|
656
|
-
'stale_closure': '⚛️',
|
|
657
|
-
// Database patterns
|
|
658
|
-
'DatabasePatterns': '🗃️',
|
|
659
|
-
'n_plus_1_query': '🗃️',
|
|
660
|
-
'query_in_loop': '🗃️',
|
|
661
|
-
'unbounded_query': '🗃️',
|
|
662
|
-
'missing_transaction': '🗃️',
|
|
663
|
-
'raw_query_interpolation': ICONS.key,
|
|
664
|
-
// Error handling
|
|
665
|
-
'ErrorHandling': ICONS.bug,
|
|
666
|
-
'empty_catch': ICONS.bug,
|
|
667
|
-
'generic_error_message': ICONS.bug,
|
|
668
|
-
// Import order
|
|
669
|
-
'ImportOrder': '📦',
|
|
670
369
|
};
|
|
671
370
|
return icons[category] || ICONS.bug;
|
|
672
371
|
}
|
|
@@ -931,11 +630,6 @@ function printHelp(showBanner = true) {
|
|
|
931
630
|
${colors.accent}--verbose, -v${ansi.reset} Show detailed progress
|
|
932
631
|
${colors.accent}--help, -h${ansi.reset} Show this help
|
|
933
632
|
|
|
934
|
-
${ansi.bold}${colors.accent}Deploy Gate (CI/CD Integration):${ansi.reset}
|
|
935
|
-
${colors.accent}--gate, -g${ansi.reset} Enable deploy gate mode ${ansi.dim}(blocks deploys on failures)${ansi.reset}
|
|
936
|
-
${colors.accent}--fail-on${ansi.reset} What triggers failure: fake-features, warnings, any, blockers
|
|
937
|
-
${ansi.dim}(default: fake-features)${ansi.reset}
|
|
938
|
-
|
|
939
633
|
${ansi.bold}Exit Codes:${ansi.reset}
|
|
940
634
|
${colors.success}0${ansi.reset} SHIP — Ready to ship
|
|
941
635
|
${colors.warning}1${ansi.reset} WARN — Warnings found, review recommended
|
|
@@ -953,20 +647,6 @@ function printHelp(showBanner = true) {
|
|
|
953
647
|
|
|
954
648
|
${ansi.dim}# Strict CI mode (warnings = failure)${ansi.reset}
|
|
955
649
|
vibecheck ship --strict --ci
|
|
956
|
-
|
|
957
|
-
${ansi.bold}${colors.accent}Deploy Gate Examples:${ansi.reset}
|
|
958
|
-
|
|
959
|
-
${ansi.dim}# Block deploy if fake features detected (default)${ansi.reset}
|
|
960
|
-
vibecheck ship --gate
|
|
961
|
-
|
|
962
|
-
${ansi.dim}# Block deploy on any warning${ansi.reset}
|
|
963
|
-
vibecheck ship --gate --fail-on=warnings
|
|
964
|
-
|
|
965
|
-
${ansi.dim}# Block deploy only on critical blockers${ansi.reset}
|
|
966
|
-
vibecheck ship --gate --fail-on=blockers
|
|
967
|
-
|
|
968
|
-
${ansi.dim}# Use in GitHub Actions / Vercel / Netlify${ansi.reset}
|
|
969
|
-
vibecheck ship --gate && npm run build
|
|
970
650
|
`);
|
|
971
651
|
}
|
|
972
652
|
|
|
@@ -1048,40 +728,13 @@ function getClaimType(category) {
|
|
|
1048
728
|
const map = {
|
|
1049
729
|
'MissingRoute': 'route_exists',
|
|
1050
730
|
'EnvContract': 'env_declared',
|
|
1051
|
-
'EnvVariable': 'env_validated',
|
|
1052
|
-
'EnvSetup': 'env_secured',
|
|
1053
731
|
'FakeSuccess': 'success_verified',
|
|
1054
732
|
'GhostAuth': 'auth_protected',
|
|
1055
733
|
'StripeWebhook': 'billing_enforced',
|
|
1056
734
|
'PaidSurface': 'billing_enforced',
|
|
1057
735
|
'OwnerModeBypass': 'billing_enforced',
|
|
1058
736
|
'DeadUI': 'ui_wired',
|
|
1059
|
-
'ContractDrift': 'contract_satisfied'
|
|
1060
|
-
// New engine claim types
|
|
1061
|
-
'AsyncPatterns': 'promises_handled',
|
|
1062
|
-
'AIHallucination': 'implementation_real',
|
|
1063
|
-
'NamingConventions': 'code_quality',
|
|
1064
|
-
'floating_promise': 'promises_handled',
|
|
1065
|
-
'empty_async_catch': 'errors_handled',
|
|
1066
|
-
'exposed_secret': 'secrets_secured',
|
|
1067
|
-
'insecure_default': 'config_secured',
|
|
1068
|
-
// React patterns
|
|
1069
|
-
'ReactPatterns': 'react_patterns_valid',
|
|
1070
|
-
'missing_key': 'list_keys_present',
|
|
1071
|
-
'conditional_hook': 'hooks_order_valid',
|
|
1072
|
-
'direct_state_mutation': 'state_immutable',
|
|
1073
|
-
'stale_closure': 'deps_correct',
|
|
1074
|
-
// Database patterns
|
|
1075
|
-
'DatabasePatterns': 'db_patterns_optimal',
|
|
1076
|
-
'n_plus_1_query': 'queries_optimized',
|
|
1077
|
-
'query_in_loop': 'queries_batched',
|
|
1078
|
-
'unbounded_query': 'queries_limited',
|
|
1079
|
-
'missing_transaction': 'transactions_used',
|
|
1080
|
-
'raw_query_interpolation': 'queries_parameterized',
|
|
1081
|
-
// Error handling
|
|
1082
|
-
'ErrorHandling': 'errors_handled',
|
|
1083
|
-
'empty_catch': 'errors_logged',
|
|
1084
|
-
'generic_error_message': 'errors_descriptive',
|
|
737
|
+
'ContractDrift': 'contract_satisfied'
|
|
1085
738
|
};
|
|
1086
739
|
return map[category] || 'ui_wired';
|
|
1087
740
|
}
|
|
@@ -1090,40 +743,13 @@ function getGapType(category) {
|
|
|
1090
743
|
const map = {
|
|
1091
744
|
'MissingRoute': 'missing_handler',
|
|
1092
745
|
'EnvContract': 'missing_verification',
|
|
1093
|
-
'EnvVariable': 'missing_validation',
|
|
1094
|
-
'EnvSetup': 'missing_security',
|
|
1095
746
|
'FakeSuccess': 'missing_verification',
|
|
1096
747
|
'GhostAuth': 'missing_gate',
|
|
1097
748
|
'StripeWebhook': 'missing_verification',
|
|
1098
749
|
'PaidSurface': 'missing_gate',
|
|
1099
750
|
'OwnerModeBypass': 'missing_gate',
|
|
1100
751
|
'DeadUI': 'missing_handler',
|
|
1101
|
-
'ContractDrift': 'contract_drift'
|
|
1102
|
-
// New engine gap types
|
|
1103
|
-
'AsyncPatterns': 'unhandled_async',
|
|
1104
|
-
'AIHallucination': 'stub_implementation',
|
|
1105
|
-
'NamingConventions': 'naming_issue',
|
|
1106
|
-
'floating_promise': 'unhandled_promise',
|
|
1107
|
-
'empty_async_catch': 'swallowed_error',
|
|
1108
|
-
'exposed_secret': 'exposed_credential',
|
|
1109
|
-
'insecure_default': 'insecure_config',
|
|
1110
|
-
// React patterns
|
|
1111
|
-
'ReactPatterns': 'react_antipattern',
|
|
1112
|
-
'missing_key': 'missing_list_key',
|
|
1113
|
-
'conditional_hook': 'invalid_hook_call',
|
|
1114
|
-
'direct_state_mutation': 'state_mutation',
|
|
1115
|
-
'stale_closure': 'stale_deps',
|
|
1116
|
-
// Database patterns
|
|
1117
|
-
'DatabasePatterns': 'db_antipattern',
|
|
1118
|
-
'n_plus_1_query': 'n_plus_1',
|
|
1119
|
-
'query_in_loop': 'loop_query',
|
|
1120
|
-
'unbounded_query': 'no_limit',
|
|
1121
|
-
'missing_transaction': 'no_transaction',
|
|
1122
|
-
'raw_query_interpolation': 'sql_injection_risk',
|
|
1123
|
-
// Error handling
|
|
1124
|
-
'ErrorHandling': 'poor_error_handling',
|
|
1125
|
-
'empty_catch': 'swallowed_error',
|
|
1126
|
-
'generic_error_message': 'generic_error',
|
|
752
|
+
'ContractDrift': 'contract_drift'
|
|
1127
753
|
};
|
|
1128
754
|
return map[category] || 'untested_path';
|
|
1129
755
|
}
|
|
@@ -1150,10 +776,6 @@ function parseArgs(args) {
|
|
|
1150
776
|
help: globalFlags.help || false,
|
|
1151
777
|
noBanner: globalFlags.noBanner || false,
|
|
1152
778
|
quiet: globalFlags.quiet || false,
|
|
1153
|
-
// Deploy Gate mode - for CI/CD integration (Vercel, Netlify, GitHub Actions)
|
|
1154
|
-
gate: false,
|
|
1155
|
-
// Deploy Gate options
|
|
1156
|
-
failOn: "fake-features", // fake-features, warnings, any
|
|
1157
779
|
};
|
|
1158
780
|
|
|
1159
781
|
// Parse command-specific args
|
|
@@ -1169,21 +791,6 @@ function parseArgs(args) {
|
|
|
1169
791
|
}
|
|
1170
792
|
else if (a.startsWith("--path=")) opts.path = a.split("=")[1];
|
|
1171
793
|
else if (a === "--path" || a === "-p") opts.path = args[++i];
|
|
1172
|
-
// Deploy Gate flags for CI/CD integration
|
|
1173
|
-
else if (a === "--gate" || a === "-g") {
|
|
1174
|
-
opts.gate = true;
|
|
1175
|
-
opts.ci = true; // Gate mode implies CI mode
|
|
1176
|
-
opts.json = true; // Gate mode outputs JSON for parsing
|
|
1177
|
-
}
|
|
1178
|
-
else if (a === "--fail-on") {
|
|
1179
|
-
const next = cleanArgs[++i];
|
|
1180
|
-
if (["fake-features", "warnings", "any", "blockers"].includes(next)) {
|
|
1181
|
-
opts.failOn = next;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
else if (a.startsWith("--fail-on=")) {
|
|
1185
|
-
opts.failOn = a.split("=")[1];
|
|
1186
|
-
}
|
|
1187
794
|
}
|
|
1188
795
|
|
|
1189
796
|
return opts;
|
|
@@ -1201,13 +808,6 @@ async function runShip(args, context = {}) {
|
|
|
1201
808
|
const opts = parseArgs(args);
|
|
1202
809
|
const executionStart = Date.now();
|
|
1203
810
|
|
|
1204
|
-
// Configure unified output mode
|
|
1205
|
-
output.setMode({
|
|
1206
|
-
json: opts.json,
|
|
1207
|
-
quiet: opts.quiet,
|
|
1208
|
-
ci: opts.ci
|
|
1209
|
-
});
|
|
1210
|
-
|
|
1211
811
|
// Show help if requested
|
|
1212
812
|
if (opts.help) {
|
|
1213
813
|
printHelp(shouldShowBanner(opts));
|
|
@@ -1224,7 +824,7 @@ async function runShip(args, context = {}) {
|
|
|
1224
824
|
} catch (err) {
|
|
1225
825
|
if (err.code === 'LIMIT_EXCEEDED' || err.code === 'FEATURE_NOT_AVAILABLE') {
|
|
1226
826
|
console.error(`\n ${colors.error}${icons.error}${ansi.reset} ${err.upgradePrompt || err.message}\n`);
|
|
1227
|
-
return
|
|
827
|
+
return EXIT_CODES.WARN;
|
|
1228
828
|
}
|
|
1229
829
|
throw err;
|
|
1230
830
|
}
|
|
@@ -1262,36 +862,26 @@ async function runShip(args, context = {}) {
|
|
|
1262
862
|
spinner = new Spinner({ color: colors.accent });
|
|
1263
863
|
}
|
|
1264
864
|
|
|
1265
|
-
//
|
|
1266
|
-
|
|
1267
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
1268
|
-
if (spinner) spinner.start(`Running comprehensive analysis (${ALL_ENGINES.length} engines)...`);
|
|
1269
|
-
|
|
1270
|
-
const engineResult = await runShipEngines(projectPath, {
|
|
1271
|
-
maxFiles: 2000,
|
|
1272
|
-
onProgress: opts.verbose ? (phase, pct) => {
|
|
1273
|
-
if (spinner) spinner.text = `${phase}: ${pct}%`;
|
|
1274
|
-
} : undefined,
|
|
1275
|
-
});
|
|
865
|
+
// Phase 1: Production Integrity Check
|
|
866
|
+
if (spinner) spinner.start('Checking production integrity...');
|
|
1276
867
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
868
|
+
try {
|
|
869
|
+
const { auditProductionIntegrity } = require(
|
|
870
|
+
path.join(__dirname, "../../scripts/audit-production-integrity.js"),
|
|
871
|
+
);
|
|
872
|
+
const { results: integrityResults, integrity } = await auditProductionIntegrity(projectPath);
|
|
873
|
+
results.score = integrity.score;
|
|
874
|
+
results.grade = integrity.grade;
|
|
875
|
+
results.canShip = integrity.canShip;
|
|
876
|
+
results.deductions = integrity.deductions;
|
|
877
|
+
results.integrity = integrityResults;
|
|
878
|
+
} catch (err) {
|
|
879
|
+
if (opts.verbose) console.warn(` ${ansi.dim}Integrity check skipped: ${err.message}${ansi.reset}`);
|
|
880
|
+
}
|
|
1289
881
|
|
|
1290
|
-
if (spinner) spinner.succeed(
|
|
882
|
+
if (spinner) spinner.succeed('Production integrity checked');
|
|
1291
883
|
|
|
1292
|
-
//
|
|
1293
|
-
// PHASE 3: Legacy analyzers (route truth, billing, etc.)
|
|
1294
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
884
|
+
// Phase 2: Route Truth Analysis
|
|
1295
885
|
if (spinner) spinner.start('Building route truth map...');
|
|
1296
886
|
|
|
1297
887
|
const fastifyEntry = detectFastifyEntry(projectPath);
|
|
@@ -1299,8 +889,8 @@ async function runShip(args, context = {}) {
|
|
|
1299
889
|
writeTruthpack(projectPath, truthpack);
|
|
1300
890
|
results.truthpack = truthpack;
|
|
1301
891
|
|
|
1302
|
-
// Run
|
|
1303
|
-
const
|
|
892
|
+
// Run all analyzers
|
|
893
|
+
const allFindings = [
|
|
1304
894
|
...findMissingRoutes(truthpack),
|
|
1305
895
|
...findEnvGaps(truthpack),
|
|
1306
896
|
...findFakeSuccess(projectPath),
|
|
@@ -1308,6 +898,7 @@ async function runShip(args, context = {}) {
|
|
|
1308
898
|
...findStripeWebhookViolations(truthpack),
|
|
1309
899
|
...findPaidSurfaceNotEnforced(truthpack),
|
|
1310
900
|
...findOwnerModeBypass(projectPath),
|
|
901
|
+
// Merge runtime findings if --with runtime is specified
|
|
1311
902
|
...(opts.withRuntime ? findingsFromReality(projectPath) : [])
|
|
1312
903
|
];
|
|
1313
904
|
|
|
@@ -1315,38 +906,12 @@ async function runShip(args, context = {}) {
|
|
|
1315
906
|
if (hasContracts(projectPath)) {
|
|
1316
907
|
const contracts = loadContracts(projectPath);
|
|
1317
908
|
const driftFindings = findContractDrift(contracts, truthpack);
|
|
1318
|
-
|
|
909
|
+
allFindings.push(...driftFindings);
|
|
1319
910
|
}
|
|
1320
911
|
|
|
1321
|
-
if (spinner) spinner.succeed(`Route truth mapped (${truthpack.routes?.server?.length || 0} routes)`);
|
|
1322
|
-
|
|
1323
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
1324
|
-
// Combine all findings
|
|
1325
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
1326
|
-
const allFindings = [
|
|
1327
|
-
// Engine findings (17+ engines)
|
|
1328
|
-
...engineResult.findings.map(f => ({
|
|
1329
|
-
...f,
|
|
1330
|
-
source: 'engine',
|
|
1331
|
-
severity: normalizeSeverityForShip(f.severity),
|
|
1332
|
-
})),
|
|
1333
|
-
// Validator findings (6 ship-only validators)
|
|
1334
|
-
...validatorResult.findings.map(f => ({
|
|
1335
|
-
...f,
|
|
1336
|
-
source: 'validator',
|
|
1337
|
-
severity: normalizeSeverityForShip(f.severity),
|
|
1338
|
-
})),
|
|
1339
|
-
// Legacy analyzer findings
|
|
1340
|
-
...legacyFindings.map(f => ({
|
|
1341
|
-
...f,
|
|
1342
|
-
source: 'legacy',
|
|
1343
|
-
severity: normalizeSeverityForShip(f.severity),
|
|
1344
|
-
})),
|
|
1345
|
-
];
|
|
1346
|
-
|
|
1347
912
|
results.findings = allFindings;
|
|
1348
|
-
|
|
1349
|
-
|
|
913
|
+
|
|
914
|
+
if (spinner) spinner.succeed(`Route truth mapped (${truthpack.routes?.server?.length || 0} routes)`);
|
|
1350
915
|
|
|
1351
916
|
// Phase 3: Build Proof Graph
|
|
1352
917
|
if (spinner) spinner.start('Building proof graph...');
|
|
@@ -1356,94 +921,33 @@ async function runShip(args, context = {}) {
|
|
|
1356
921
|
|
|
1357
922
|
if (spinner) spinner.succeed(`Proof graph built (${proofGraph.summary.totalClaims} claims)`);
|
|
1358
923
|
|
|
1359
|
-
//
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
const blockers = allFindings.filter(f => f.severity === 'BLOCK');
|
|
1363
|
-
const warnings = allFindings.filter(f => f.severity === 'WARN');
|
|
1364
|
-
const infos = allFindings.filter(f => f.severity === 'INFO');
|
|
1365
|
-
|
|
1366
|
-
// Check for hallucinations (critical for vibecheck)
|
|
1367
|
-
const hallucinations = allFindings.filter(f =>
|
|
1368
|
-
f.engine === 'ai-hallucination-engine' ||
|
|
1369
|
-
f.category?.includes('AIHallucination') ||
|
|
1370
|
-
f.category?.includes('Hallucination')
|
|
1371
|
-
);
|
|
924
|
+
// Calculate final verdict
|
|
925
|
+
const blockers = allFindings.filter(f => f.severity === 'BLOCK' || f.severity === 'critical');
|
|
926
|
+
const warnings = allFindings.filter(f => f.severity === 'WARN' || f.severity === 'warning');
|
|
1372
927
|
|
|
1373
928
|
results.blockers = blockers;
|
|
1374
929
|
results.warnings = warnings;
|
|
1375
930
|
|
|
1376
|
-
//
|
|
1377
|
-
|
|
1378
|
-
|
|
931
|
+
// Apply strict mode
|
|
932
|
+
if (opts.strict && warnings.length > 0) {
|
|
933
|
+
results.canShip = false;
|
|
934
|
+
}
|
|
1379
935
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
quality: 0,
|
|
1384
|
-
hallucination: 0,
|
|
1385
|
-
routes: 0,
|
|
1386
|
-
contracts: 0,
|
|
1387
|
-
dependencies: 0,
|
|
1388
|
-
};
|
|
936
|
+
if (blockers.length > 0) {
|
|
937
|
+
results.canShip = false;
|
|
938
|
+
}
|
|
1389
939
|
|
|
940
|
+
// Deduct score for findings
|
|
1390
941
|
for (const finding of allFindings) {
|
|
1391
|
-
const category = categorizeFindings(finding);
|
|
1392
|
-
|
|
1393
942
|
if (finding.severity === 'BLOCK') {
|
|
1394
|
-
|
|
943
|
+
results.score = Math.max(0, results.score - 15);
|
|
1395
944
|
} else if (finding.severity === 'WARN') {
|
|
1396
|
-
|
|
1397
|
-
} else {
|
|
1398
|
-
categoryDeductions[category] += 1;
|
|
945
|
+
results.score = Math.max(0, results.score - 5);
|
|
1399
946
|
}
|
|
1400
947
|
}
|
|
1401
948
|
|
|
1402
|
-
|
|
1403
|
-
const
|
|
1404
|
-
categoryDeductions.security * 1.5 + // Security issues weighted higher
|
|
1405
|
-
categoryDeductions.hallucination * 2.0 + // AI hallucinations weighted highest
|
|
1406
|
-
categoryDeductions.quality * 0.8 +
|
|
1407
|
-
categoryDeductions.routes * 1.0 +
|
|
1408
|
-
categoryDeductions.contracts * 1.0 +
|
|
1409
|
-
categoryDeductions.dependencies * 0.5
|
|
1410
|
-
);
|
|
1411
|
-
|
|
1412
|
-
score = Math.max(0, Math.round(100 - totalDeduction));
|
|
1413
|
-
results.score = score;
|
|
1414
|
-
|
|
1415
|
-
// Determine grade
|
|
1416
|
-
results.grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 50 ? 'D' : 'F';
|
|
1417
|
-
|
|
1418
|
-
// Determine verdict using the specified rules
|
|
1419
|
-
let verdict;
|
|
1420
|
-
const hasCritical = blockers.length > 0;
|
|
1421
|
-
const hasHallucinations = hallucinations.filter(f => f.severity !== 'INFO').length > 0;
|
|
1422
|
-
|
|
1423
|
-
if (hasCritical || score < 50) {
|
|
1424
|
-
verdict = 'BLOCK';
|
|
1425
|
-
results.canShip = false;
|
|
1426
|
-
} else if (hasHallucinations || score < 75 || (opts.strict && warnings.length > 0)) {
|
|
1427
|
-
verdict = 'WARN';
|
|
1428
|
-
results.canShip = false;
|
|
1429
|
-
} else {
|
|
1430
|
-
verdict = 'SHIP';
|
|
1431
|
-
results.canShip = true;
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
// Build breakdown by category
|
|
1435
|
-
const breakdown = {
|
|
1436
|
-
security: allFindings.filter(f => categorizeFindings(f) === 'security'),
|
|
1437
|
-
quality: allFindings.filter(f => categorizeFindings(f) === 'quality'),
|
|
1438
|
-
hallucination: hallucinations,
|
|
1439
|
-
routes: allFindings.filter(f => categorizeFindings(f) === 'routes'),
|
|
1440
|
-
contracts: allFindings.filter(f => categorizeFindings(f) === 'contracts'),
|
|
1441
|
-
dependencies: allFindings.filter(f => categorizeFindings(f) === 'dependencies'),
|
|
1442
|
-
};
|
|
1443
|
-
|
|
1444
|
-
results.breakdown = breakdown;
|
|
1445
|
-
|
|
1446
|
-
const duration = Date.now() - executionStart;
|
|
949
|
+
const verdict = results.canShip ? 'SHIP' : blockers.length > 0 ? 'BLOCK' : 'WARN';
|
|
950
|
+
const duration = Date.now() - startTime;
|
|
1447
951
|
|
|
1448
952
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1449
953
|
// OUTPUT
|
|
@@ -1527,7 +1031,7 @@ async function runShip(args, context = {}) {
|
|
|
1527
1031
|
if (spinner) spinner.succeed('Safe fixes applied');
|
|
1528
1032
|
}
|
|
1529
1033
|
|
|
1530
|
-
// Human-readable output using
|
|
1034
|
+
// Human-readable output using ship-output module
|
|
1531
1035
|
const result = {
|
|
1532
1036
|
verdict,
|
|
1533
1037
|
score: results.score,
|
|
@@ -1540,109 +1044,30 @@ async function runShip(args, context = {}) {
|
|
|
1540
1044
|
duration: Date.now() - executionStart,
|
|
1541
1045
|
};
|
|
1542
1046
|
|
|
1543
|
-
// Get current tier for output formatting
|
|
1544
|
-
const currentTier = context?.authInfo?.access?.tier || getCurrentTier() || "free";
|
|
1545
|
-
|
|
1546
|
-
// Use enterprise format
|
|
1547
1047
|
console.log(formatShipOutput(result, {
|
|
1548
|
-
|
|
1048
|
+
verbose: opts.verbose,
|
|
1049
|
+
showFix: opts.fix,
|
|
1050
|
+
showBadge: opts.badge,
|
|
1051
|
+
outputDir,
|
|
1052
|
+
projectPath,
|
|
1549
1053
|
}));
|
|
1550
1054
|
|
|
1551
|
-
//
|
|
1552
|
-
if (proofCertificate && !opts.quiet && !opts.json && !opts.ci) {
|
|
1553
|
-
// Risk Radar visualization
|
|
1554
|
-
const riskRadar = proofCertificate.calculateRiskRadar(allFindings);
|
|
1555
|
-
console.log();
|
|
1556
|
-
console.log(proofCertificate.renderRiskRadar(riskRadar));
|
|
1557
|
-
|
|
1558
|
-
// Pre-flight Checklist
|
|
1559
|
-
const preflight = proofCertificate.runPreflightChecklist(allFindings, proofGraph);
|
|
1560
|
-
console.log();
|
|
1561
|
-
console.log(proofCertificate.renderPreflightChecklist(preflight));
|
|
1562
|
-
|
|
1563
|
-
// Generate and save Proof Certificate
|
|
1564
|
-
const certificate = proofCertificate.generateProofCertificate({
|
|
1565
|
-
projectPath,
|
|
1566
|
-
projectName: path.basename(projectPath),
|
|
1567
|
-
verdict,
|
|
1568
|
-
score: results.score,
|
|
1569
|
-
findings: allFindings,
|
|
1570
|
-
truthpack,
|
|
1571
|
-
proofGraph,
|
|
1572
|
-
duration: Date.now() - executionStart,
|
|
1573
|
-
tier: currentTier,
|
|
1574
|
-
version: require('../../package.json').version || '1.0.0',
|
|
1575
|
-
});
|
|
1576
|
-
|
|
1577
|
-
// Save certificate
|
|
1578
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
1579
|
-
fs.writeFileSync(
|
|
1580
|
-
path.join(outputDir, 'proof-certificate.json'),
|
|
1581
|
-
JSON.stringify(certificate.certificate, null, 2)
|
|
1582
|
-
);
|
|
1583
|
-
|
|
1584
|
-
// Show certificate ID
|
|
1585
|
-
console.log();
|
|
1586
|
-
console.log(` ${ansi.dim}╭${'─'.repeat(58)}╮${ansi.reset}`);
|
|
1587
|
-
console.log(` ${ansi.dim}│${ansi.reset} ${colors.accent}📜 PROOF CERTIFICATE${ansi.reset} ${ansi.dim}│${ansi.reset}`);
|
|
1588
|
-
console.log(` ${ansi.dim}├${'─'.repeat(58)}┤${ansi.reset}`);
|
|
1589
|
-
console.log(` ${ansi.dim}│${ansi.reset} ID: ${ansi.cyan}${certificate.certificate.certificateId}${ansi.reset} ${ansi.dim}│${ansi.reset}`);
|
|
1590
|
-
console.log(` ${ansi.dim}│${ansi.reset} Short Code: ${ansi.bold}${certificate.shortCode}${ansi.reset} ${ansi.dim}│${ansi.reset}`);
|
|
1591
|
-
console.log(` ${ansi.dim}│${ansi.reset} Confidence: ${ansi.bold}${certificate.certificate.verdict.confidence}%${ansi.reset} ${ansi.dim}│${ansi.reset}`);
|
|
1592
|
-
console.log(` ${ansi.dim}│${ansi.reset} Expires: ${certificate.certificate.expires.slice(0, 10)} ${ansi.dim}│${ansi.reset}`);
|
|
1593
|
-
console.log(` ${ansi.dim}├${'─'.repeat(58)}┤${ansi.reset}`);
|
|
1594
|
-
console.log(` ${ansi.dim}│${ansi.reset} ${ansi.dim}Verify at:${ansi.reset} ${ansi.cyan}${certificate.certificate.verificationUrl.slice(0, 45)}${ansi.reset} ${ansi.dim}│${ansi.reset}`);
|
|
1595
|
-
console.log(` ${ansi.dim}╰${'─'.repeat(58)}╯${ansi.reset}`);
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
// Pro upsell for free users
|
|
1599
|
-
if (currentTier === 'free' && !opts.quiet) {
|
|
1600
|
-
console.log();
|
|
1601
|
-
console.log(` ${ansi.gray}${BOX.dTopLeft}${BOX.dHorizontal.repeat(66)}${BOX.dTopRight}${ansi.reset}`);
|
|
1602
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset}${' '.repeat(66)}${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1603
|
-
|
|
1604
|
-
if (verdict === 'SHIP') {
|
|
1605
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset} ${ansi.magenta}★ PRO${ansi.reset} Generate a ${ansi.bold}status badge${ansi.reset} to show off your clean code! ${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1606
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset} Run: ${ansi.cyan}vibecheck ship --badge${ansi.reset} ${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1607
|
-
} else if (allFindings.length > 0) {
|
|
1608
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset} ${ansi.magenta}★ PRO${ansi.reset} Auto-fix all ${ansi.bold}${allFindings.length} issues${ansi.reset} instantly with AI ${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1609
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset} Run: ${ansi.cyan}vibecheck fix --apply${ansi.reset} ${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset}${' '.repeat(66)}${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1613
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset} Upgrade: ${ansi.cyan}https://vibecheckai.dev/pricing${ansi.reset} ${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1614
|
-
console.log(` ${ansi.gray}${BOX.dVertical}${ansi.reset}${' '.repeat(66)}${ansi.gray}${BOX.dVertical}${ansi.reset}`);
|
|
1615
|
-
console.log(` ${ansi.gray}${BOX.dBottomLeft}${BOX.dHorizontal.repeat(66)}${BOX.dBottomRight}${ansi.reset}`);
|
|
1616
|
-
console.log();
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
// Badge file generation (PRO only)
|
|
1055
|
+
// Badge file generation
|
|
1620
1056
|
if (opts.badge) {
|
|
1621
|
-
const
|
|
1622
|
-
const { data: badgeData } = renderBadgeOutput(projectPath, verdict, results.score, {
|
|
1623
|
-
tier: currentTier,
|
|
1624
|
-
isVerified
|
|
1625
|
-
});
|
|
1057
|
+
const { data: badgeData } = renderBadgeOutput(projectPath, verdict, results.score);
|
|
1626
1058
|
|
|
1627
1059
|
// Save badge info
|
|
1628
1060
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
1629
1061
|
fs.writeFileSync(
|
|
1630
1062
|
path.join(outputDir, 'badge.json'),
|
|
1631
|
-
JSON.stringify({
|
|
1632
|
-
...badgeData,
|
|
1633
|
-
verdict,
|
|
1634
|
-
score: results.score,
|
|
1635
|
-
tier: currentTier,
|
|
1636
|
-
isVerified,
|
|
1637
|
-
generatedAt: new Date().toISOString()
|
|
1638
|
-
}, null, 2)
|
|
1063
|
+
JSON.stringify({ ...badgeData, verdict, score: results.score, generatedAt: new Date().toISOString() }, null, 2)
|
|
1639
1064
|
);
|
|
1640
1065
|
}
|
|
1641
1066
|
|
|
1642
1067
|
// Earned upsell: Badge withheld when verdict != SHIP
|
|
1643
1068
|
if (!results.canShip) {
|
|
1644
1069
|
const currentTier = context?.authInfo?.access?.tier || "free";
|
|
1645
|
-
if (currentTier
|
|
1070
|
+
if (entitlements.tierMeetsMinimum(currentTier, "starter")) {
|
|
1646
1071
|
// User has badge access but verdict prevents it
|
|
1647
1072
|
console.log(upsell.formatEarnedUpsell({
|
|
1648
1073
|
cmd: "ship",
|
|
@@ -1670,92 +1095,7 @@ async function runShip(args, context = {}) {
|
|
|
1670
1095
|
} catch {}
|
|
1671
1096
|
|
|
1672
1097
|
// Exit code: 0=SHIP, 1=WARN, 2=BLOCK
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
// Deploy Gate Mode: Stricter exit code logic for CI/CD integration
|
|
1676
|
-
if (opts.gate) {
|
|
1677
|
-
const hasFakeFeatures = allFindings.some(f =>
|
|
1678
|
-
f.category?.toLowerCase().includes('fake') ||
|
|
1679
|
-
f.category?.toLowerCase().includes('mock') ||
|
|
1680
|
-
f.type?.toLowerCase().includes('fake') ||
|
|
1681
|
-
f.title?.toLowerCase().includes('fake') ||
|
|
1682
|
-
f.title?.toLowerCase().includes('mock data')
|
|
1683
|
-
);
|
|
1684
|
-
|
|
1685
|
-
const hasBlockers = allFindings.some(f =>
|
|
1686
|
-
f.severity === 'BLOCK' || f.severity === 'critical' || f.severity === 'high'
|
|
1687
|
-
);
|
|
1688
|
-
|
|
1689
|
-
const hasWarnings = allFindings.some(f =>
|
|
1690
|
-
f.severity === 'WARN' || f.severity === 'warning' || f.severity === 'medium'
|
|
1691
|
-
);
|
|
1692
|
-
|
|
1693
|
-
// Determine gate failure based on --fail-on option
|
|
1694
|
-
let gateBlocked = false;
|
|
1695
|
-
let gateReason = '';
|
|
1696
|
-
|
|
1697
|
-
switch (opts.failOn) {
|
|
1698
|
-
case 'fake-features':
|
|
1699
|
-
gateBlocked = hasFakeFeatures;
|
|
1700
|
-
gateReason = 'Fake features detected';
|
|
1701
|
-
break;
|
|
1702
|
-
case 'warnings':
|
|
1703
|
-
gateBlocked = hasWarnings || hasBlockers || hasFakeFeatures;
|
|
1704
|
-
gateReason = hasBlockers ? 'Blockers found' : hasFakeFeatures ? 'Fake features detected' : 'Warnings found';
|
|
1705
|
-
break;
|
|
1706
|
-
case 'any':
|
|
1707
|
-
gateBlocked = allFindings.length > 0;
|
|
1708
|
-
gateReason = 'Issues detected';
|
|
1709
|
-
break;
|
|
1710
|
-
case 'blockers':
|
|
1711
|
-
default:
|
|
1712
|
-
gateBlocked = hasBlockers || hasFakeFeatures;
|
|
1713
|
-
gateReason = hasFakeFeatures ? 'Fake features detected' : 'Blockers found';
|
|
1714
|
-
break;
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
if (gateBlocked) {
|
|
1718
|
-
exitCode = EXIT.BLOCKING;
|
|
1719
|
-
|
|
1720
|
-
// Output gate-specific JSON for CI/CD parsing
|
|
1721
|
-
if (opts.json) {
|
|
1722
|
-
console.log(JSON.stringify({
|
|
1723
|
-
gate: {
|
|
1724
|
-
blocked: true,
|
|
1725
|
-
reason: gateReason,
|
|
1726
|
-
failOn: opts.failOn,
|
|
1727
|
-
hasFakeFeatures,
|
|
1728
|
-
hasBlockers,
|
|
1729
|
-
hasWarnings,
|
|
1730
|
-
issueCount: allFindings.length,
|
|
1731
|
-
},
|
|
1732
|
-
verdict,
|
|
1733
|
-
score: results.score,
|
|
1734
|
-
canShip: false,
|
|
1735
|
-
exitCode,
|
|
1736
|
-
findings: allFindings.slice(0, 20), // Top 20 findings
|
|
1737
|
-
timestamp: new Date().toISOString(),
|
|
1738
|
-
}, null, 2));
|
|
1739
|
-
}
|
|
1740
|
-
} else if (opts.json) {
|
|
1741
|
-
console.log(JSON.stringify({
|
|
1742
|
-
gate: {
|
|
1743
|
-
blocked: false,
|
|
1744
|
-
reason: 'All checks passed',
|
|
1745
|
-
failOn: opts.failOn,
|
|
1746
|
-
hasFakeFeatures: false,
|
|
1747
|
-
hasBlockers: false,
|
|
1748
|
-
hasWarnings,
|
|
1749
|
-
issueCount: allFindings.length,
|
|
1750
|
-
},
|
|
1751
|
-
verdict,
|
|
1752
|
-
score: results.score,
|
|
1753
|
-
canShip: true,
|
|
1754
|
-
exitCode,
|
|
1755
|
-
timestamp: new Date().toISOString(),
|
|
1756
|
-
}, null, 2));
|
|
1757
|
-
}
|
|
1758
|
-
}
|
|
1098
|
+
const exitCode = getExitCode(verdict);
|
|
1759
1099
|
|
|
1760
1100
|
// Save final results
|
|
1761
1101
|
saveArtifact(runId, "summary", {
|
|
@@ -1763,8 +1103,6 @@ async function runShip(args, context = {}) {
|
|
|
1763
1103
|
score: results.score,
|
|
1764
1104
|
canShip: results.canShip,
|
|
1765
1105
|
exitCode,
|
|
1766
|
-
gateMode: opts.gate,
|
|
1767
|
-
failOn: opts.failOn,
|
|
1768
1106
|
timestamp: new Date().toISOString()
|
|
1769
1107
|
});
|
|
1770
1108
|
|
|
@@ -1778,7 +1116,7 @@ async function runShip(args, context = {}) {
|
|
|
1778
1116
|
console.error(` ${ansi.dim}${error.stack}${ansi.reset}`);
|
|
1779
1117
|
}
|
|
1780
1118
|
|
|
1781
|
-
return
|
|
1119
|
+
return EXIT_CODES.ERROR;
|
|
1782
1120
|
}
|
|
1783
1121
|
}
|
|
1784
1122
|
|