@vibecheckai/cli 2.8.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/bin/_deprecations.js +35 -0
- package/bin/_router.js +46 -0
- package/bin/cli-hygiene.js +241 -0
- package/bin/guardrail.js +834 -0
- package/bin/runners/cli-utils.js +1070 -0
- package/bin/runners/context/ai-task-decomposer.js +337 -0
- package/bin/runners/context/analyzer.js +462 -0
- package/bin/runners/context/api-contracts.js +427 -0
- package/bin/runners/context/context-diff.js +342 -0
- package/bin/runners/context/context-pruner.js +291 -0
- package/bin/runners/context/dependency-graph.js +414 -0
- package/bin/runners/context/generators/claude.js +107 -0
- package/bin/runners/context/generators/codex.js +108 -0
- package/bin/runners/context/generators/copilot.js +119 -0
- package/bin/runners/context/generators/cursor.js +514 -0
- package/bin/runners/context/generators/mcp.js +151 -0
- package/bin/runners/context/generators/windsurf.js +180 -0
- package/bin/runners/context/git-context.js +302 -0
- package/bin/runners/context/index.js +1042 -0
- package/bin/runners/context/insights.js +173 -0
- package/bin/runners/context/mcp-server/generate-rules.js +337 -0
- package/bin/runners/context/mcp-server/index.js +1176 -0
- package/bin/runners/context/mcp-server/package.json +24 -0
- package/bin/runners/context/memory.js +200 -0
- package/bin/runners/context/monorepo.js +215 -0
- package/bin/runners/context/multi-repo-federation.js +404 -0
- package/bin/runners/context/patterns.js +253 -0
- package/bin/runners/context/proof-context.js +972 -0
- package/bin/runners/context/security-scanner.js +303 -0
- package/bin/runners/context/semantic-search.js +350 -0
- package/bin/runners/context/shared.js +264 -0
- package/bin/runners/context/team-conventions.js +310 -0
- package/bin/runners/lib/ai-bridge.js +416 -0
- package/bin/runners/lib/analysis-core.js +271 -0
- package/bin/runners/lib/analyzers.js +541 -0
- package/bin/runners/lib/audit-bridge.js +391 -0
- package/bin/runners/lib/auth-truth.js +193 -0
- package/bin/runners/lib/auth.js +215 -0
- package/bin/runners/lib/backup.js +62 -0
- package/bin/runners/lib/billing.js +107 -0
- package/bin/runners/lib/claims.js +118 -0
- package/bin/runners/lib/cli-ui.js +540 -0
- package/bin/runners/lib/compliance-bridge-new.js +0 -0
- package/bin/runners/lib/compliance-bridge.js +165 -0
- package/bin/runners/lib/contracts/auth-contract.js +194 -0
- package/bin/runners/lib/contracts/env-contract.js +178 -0
- package/bin/runners/lib/contracts/external-contract.js +198 -0
- package/bin/runners/lib/contracts/guard.js +168 -0
- package/bin/runners/lib/contracts/index.js +89 -0
- package/bin/runners/lib/contracts/plan-validator.js +311 -0
- package/bin/runners/lib/contracts/route-contract.js +192 -0
- package/bin/runners/lib/detect.js +89 -0
- package/bin/runners/lib/doctor/autofix.js +254 -0
- package/bin/runners/lib/doctor/index.js +37 -0
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
- package/bin/runners/lib/doctor/modules/index.js +46 -0
- package/bin/runners/lib/doctor/modules/network.js +250 -0
- package/bin/runners/lib/doctor/modules/project.js +312 -0
- package/bin/runners/lib/doctor/modules/runtime.js +224 -0
- package/bin/runners/lib/doctor/modules/security.js +348 -0
- package/bin/runners/lib/doctor/modules/system.js +213 -0
- package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
- package/bin/runners/lib/doctor/reporter.js +262 -0
- package/bin/runners/lib/doctor/service.js +262 -0
- package/bin/runners/lib/doctor/types.js +113 -0
- package/bin/runners/lib/doctor/ui.js +263 -0
- package/bin/runners/lib/doctor-enhanced.js +233 -0
- package/bin/runners/lib/doctor-v2.js +608 -0
- package/bin/runners/lib/enforcement.js +72 -0
- package/bin/runners/lib/enterprise-detect.js +603 -0
- package/bin/runners/lib/enterprise-init.js +942 -0
- package/bin/runners/lib/entitlements-v2.js +381 -0
- package/bin/runners/lib/entitlements.generated.js +0 -0
- package/bin/runners/lib/entitlements.js +332 -0
- package/bin/runners/lib/env-template.js +66 -0
- package/bin/runners/lib/env.js +189 -0
- package/bin/runners/lib/error-handler.js +320 -0
- package/bin/runners/lib/firewall-prompt.js +50 -0
- package/bin/runners/lib/graph/graph-builder.js +265 -0
- package/bin/runners/lib/graph/html-renderer.js +413 -0
- package/bin/runners/lib/graph/index.js +32 -0
- package/bin/runners/lib/graph/runtime-collector.js +215 -0
- package/bin/runners/lib/graph/static-extractor.js +518 -0
- package/bin/runners/lib/init-wizard.js +308 -0
- package/bin/runners/lib/json-output.js +76 -0
- package/bin/runners/lib/llm.js +75 -0
- package/bin/runners/lib/meter.js +61 -0
- package/bin/runners/lib/missions/evidence.js +126 -0
- package/bin/runners/lib/missions/plan.js +69 -0
- package/bin/runners/lib/missions/templates.js +147 -0
- package/bin/runners/lib/patch.js +40 -0
- package/bin/runners/lib/permissions/auth-model.js +213 -0
- package/bin/runners/lib/permissions/idor-prover.js +205 -0
- package/bin/runners/lib/permissions/index.js +45 -0
- package/bin/runners/lib/permissions/matrix-builder.js +198 -0
- package/bin/runners/lib/pkgjson.js +28 -0
- package/bin/runners/lib/preflight.js +142 -0
- package/bin/runners/lib/reality-findings.js +84 -0
- package/bin/runners/lib/redact.js +29 -0
- package/bin/runners/lib/replay/capsule-manager.js +154 -0
- package/bin/runners/lib/replay/index.js +263 -0
- package/bin/runners/lib/replay/player.js +348 -0
- package/bin/runners/lib/replay/recorder.js +331 -0
- package/bin/runners/lib/report-engine.js +447 -0
- package/bin/runners/lib/report-html.js +1117 -0
- package/bin/runners/lib/report-templates.js +964 -0
- package/bin/runners/lib/route-detection.js +1140 -0
- package/bin/runners/lib/route-truth.js +477 -0
- package/bin/runners/lib/sandbox/index.js +59 -0
- package/bin/runners/lib/sandbox/proof-chain.js +399 -0
- package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
- package/bin/runners/lib/sandbox/worktree.js +174 -0
- package/bin/runners/lib/scan-cache.js +330 -0
- package/bin/runners/lib/scan-output-schema.js +344 -0
- package/bin/runners/lib/score-history.js +282 -0
- package/bin/runners/lib/security-bridge.js +249 -0
- package/bin/runners/lib/server-usage.js +513 -0
- package/bin/runners/lib/share-pack.js +239 -0
- package/bin/runners/lib/snippets.js +67 -0
- package/bin/runners/lib/truth.js +667 -0
- package/bin/runners/lib/unified-output.js +189 -0
- package/bin/runners/lib/validate-patch.js +156 -0
- package/bin/runners/lib/verification.js +345 -0
- package/bin/runners/reality/engine.js +917 -0
- package/bin/runners/reality/flows.js +122 -0
- package/bin/runners/reality/report.js +378 -0
- package/bin/runners/reality/session.js +193 -0
- package/bin/runners/runAIAgent.js +2 -0
- package/bin/runners/runAudit.js +2 -0
- package/bin/runners/runAuth.js +106 -0
- package/bin/runners/runAutopilot.js +2 -0
- package/bin/runners/runBadge.js +2 -0
- package/bin/runners/runCertify.js +2 -0
- package/bin/runners/runClaimVerifier.js +483 -0
- package/bin/runners/runContext.js +56 -0
- package/bin/runners/runContextCompiler.js +385 -0
- package/bin/runners/runCtx.js +187 -0
- package/bin/runners/runCtxGuard.js +176 -0
- package/bin/runners/runCtxSync.js +116 -0
- package/bin/runners/runDashboard.js +10 -0
- package/bin/runners/runDoctor.js +245 -0
- package/bin/runners/runEnhancedShip.js +2 -0
- package/bin/runners/runFix.js +735 -0
- package/bin/runners/runFixPacks.js +2 -0
- package/bin/runners/runGate.js +17 -0
- package/bin/runners/runGraph.js +283 -0
- package/bin/runners/runInit.js +260 -0
- package/bin/runners/runInitGha.js +101 -0
- package/bin/runners/runInstall.js +76 -0
- package/bin/runners/runInteractive.js +388 -0
- package/bin/runners/runLaunch.js +2 -0
- package/bin/runners/runMcp.js +19 -0
- package/bin/runners/runMdc.js +2 -0
- package/bin/runners/runMissionGenerator.js +282 -0
- package/bin/runners/runNaturalLanguage.js +3 -0
- package/bin/runners/runPR.js +96 -0
- package/bin/runners/runPermissions.js +290 -0
- package/bin/runners/runPromptFirewall.js +211 -0
- package/bin/runners/runProof.js +2 -0
- package/bin/runners/runProve.js +392 -0
- package/bin/runners/runReality.js +489 -0
- package/bin/runners/runRealitySniff.js +2 -0
- package/bin/runners/runReplay.js +469 -0
- package/bin/runners/runReport.js +478 -0
- package/bin/runners/runScan.js +835 -0
- package/bin/runners/runShare.js +34 -0
- package/bin/runners/runShip.js +1062 -0
- package/bin/runners/runStatus.js +136 -0
- package/bin/runners/runTruthpack.js +634 -0
- package/bin/runners/runUpgrade.js +2 -0
- package/bin/runners/runValidate.js +2 -0
- package/bin/runners/runVerifyAgentOutput.js +2 -0
- package/bin/runners/runWatch.js +230 -0
- package/bin/runners/utils.js +360 -0
- package/bin/scan.js +612 -0
- package/bin/vibecheck.js +834 -0
- package/package.json +11 -11
- package/dist/autopatch/verified-autopatch.d.ts +0 -111
- package/dist/autopatch/verified-autopatch.d.ts.map +0 -1
- package/dist/autopatch/verified-autopatch.js +0 -503
- package/dist/autopatch/verified-autopatch.js.map +0 -1
- package/dist/bundles/index.js +0 -8
- package/dist/bundles/vibecheck-core.js +0 -25799
- package/dist/bundles/vibecheck-security.js +0 -208693
- package/dist/bundles/vibecheck-ship.js +0 -2318
- package/dist/commands/baseline.d.ts +0 -7
- package/dist/commands/baseline.d.ts.map +0 -1
- package/dist/commands/baseline.js +0 -79
- package/dist/commands/baseline.js.map +0 -1
- package/dist/commands/cache.d.ts +0 -13
- package/dist/commands/cache.d.ts.map +0 -1
- package/dist/commands/cache.js +0 -165
- package/dist/commands/cache.js.map +0 -1
- package/dist/commands/checkpoint.d.ts +0 -8
- package/dist/commands/checkpoint.d.ts.map +0 -1
- package/dist/commands/checkpoint.js +0 -35
- package/dist/commands/checkpoint.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -17
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -226
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/evidence.d.ts +0 -45
- package/dist/commands/evidence.d.ts.map +0 -1
- package/dist/commands/evidence.js +0 -197
- package/dist/commands/evidence.js.map +0 -1
- package/dist/commands/explain.d.ts +0 -8
- package/dist/commands/explain.d.ts.map +0 -1
- package/dist/commands/explain.js +0 -52
- package/dist/commands/explain.js.map +0 -1
- package/dist/commands/fix-consolidated.d.ts +0 -19
- package/dist/commands/fix-consolidated.d.ts.map +0 -1
- package/dist/commands/fix-consolidated.js +0 -165
- package/dist/commands/fix-consolidated.js.map +0 -1
- package/dist/commands/index.d.ts +0 -8
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js +0 -15
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -125
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/launcher.d.ts +0 -10
- package/dist/commands/launcher.d.ts.map +0 -1
- package/dist/commands/launcher.js +0 -174
- package/dist/commands/launcher.js.map +0 -1
- package/dist/commands/on.d.ts +0 -8
- package/dist/commands/on.d.ts.map +0 -1
- package/dist/commands/on.js +0 -123
- package/dist/commands/on.js.map +0 -1
- package/dist/commands/replay.d.ts +0 -8
- package/dist/commands/replay.d.ts.map +0 -1
- package/dist/commands/replay.js +0 -52
- package/dist/commands/replay.js.map +0 -1
- package/dist/commands/scan-consolidated.d.ts +0 -61
- package/dist/commands/scan-consolidated.d.ts.map +0 -1
- package/dist/commands/scan-consolidated.js +0 -243
- package/dist/commands/scan-consolidated.js.map +0 -1
- package/dist/commands/scan-secrets.d.ts +0 -47
- package/dist/commands/scan-secrets.d.ts.map +0 -1
- package/dist/commands/scan-secrets.js +0 -225
- package/dist/commands/scan-secrets.js.map +0 -1
- package/dist/commands/scan-vulnerabilities-enhanced.d.ts +0 -41
- package/dist/commands/scan-vulnerabilities-enhanced.d.ts.map +0 -1
- package/dist/commands/scan-vulnerabilities-enhanced.js +0 -368
- package/dist/commands/scan-vulnerabilities-enhanced.js.map +0 -1
- package/dist/commands/scan-vulnerabilities-osv.d.ts +0 -58
- package/dist/commands/scan-vulnerabilities-osv.d.ts.map +0 -1
- package/dist/commands/scan-vulnerabilities-osv.js +0 -722
- package/dist/commands/scan-vulnerabilities-osv.js.map +0 -1
- package/dist/commands/scan-vulnerabilities.d.ts +0 -32
- package/dist/commands/scan-vulnerabilities.d.ts.map +0 -1
- package/dist/commands/scan-vulnerabilities.js +0 -283
- package/dist/commands/scan-vulnerabilities.js.map +0 -1
- package/dist/commands/secrets-allowlist.d.ts +0 -7
- package/dist/commands/secrets-allowlist.d.ts.map +0 -1
- package/dist/commands/secrets-allowlist.js +0 -85
- package/dist/commands/secrets-allowlist.js.map +0 -1
- package/dist/commands/ship-consolidated.d.ts +0 -58
- package/dist/commands/ship-consolidated.d.ts.map +0 -1
- package/dist/commands/ship-consolidated.js +0 -515
- package/dist/commands/ship-consolidated.js.map +0 -1
- package/dist/commands/stats.d.ts +0 -8
- package/dist/commands/stats.d.ts.map +0 -1
- package/dist/commands/stats.js +0 -134
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/upgrade.d.ts +0 -8
- package/dist/commands/upgrade.d.ts.map +0 -1
- package/dist/commands/upgrade.js +0 -30
- package/dist/commands/upgrade.js.map +0 -1
- package/dist/fix/applicator.d.ts +0 -44
- package/dist/fix/applicator.d.ts.map +0 -1
- package/dist/fix/applicator.js +0 -144
- package/dist/fix/applicator.js.map +0 -1
- package/dist/fix/backup.d.ts +0 -38
- package/dist/fix/backup.d.ts.map +0 -1
- package/dist/fix/backup.js +0 -154
- package/dist/fix/backup.js.map +0 -1
- package/dist/fix/engine.d.ts +0 -55
- package/dist/fix/engine.d.ts.map +0 -1
- package/dist/fix/engine.js +0 -285
- package/dist/fix/engine.js.map +0 -1
- package/dist/fix/index.d.ts +0 -5
- package/dist/fix/index.d.ts.map +0 -1
- package/dist/fix/index.js +0 -12
- package/dist/fix/index.js.map +0 -1
- package/dist/fix/interactive.d.ts +0 -22
- package/dist/fix/interactive.d.ts.map +0 -1
- package/dist/fix/interactive.js +0 -172
- package/dist/fix/interactive.js.map +0 -1
- package/dist/formatters/index.d.ts +0 -6
- package/dist/formatters/index.d.ts.map +0 -1
- package/dist/formatters/index.js +0 -11
- package/dist/formatters/index.js.map +0 -1
- package/dist/formatters/sarif-enhanced.d.ts +0 -78
- package/dist/formatters/sarif-enhanced.d.ts.map +0 -1
- package/dist/formatters/sarif-enhanced.js +0 -144
- package/dist/formatters/sarif-enhanced.js.map +0 -1
- package/dist/formatters/sarif-v2.d.ts +0 -121
- package/dist/formatters/sarif-v2.d.ts.map +0 -1
- package/dist/formatters/sarif-v2.js +0 -356
- package/dist/formatters/sarif-v2.js.map +0 -1
- package/dist/formatters/sarif.d.ts +0 -72
- package/dist/formatters/sarif.d.ts.map +0 -1
- package/dist/formatters/sarif.js +0 -146
- package/dist/formatters/sarif.js.map +0 -1
- package/dist/index.d.ts +0 -61
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4388
- package/dist/index.js.map +0 -1
- package/dist/init/ci-generator.d.ts +0 -18
- package/dist/init/ci-generator.d.ts.map +0 -1
- package/dist/init/ci-generator.js +0 -317
- package/dist/init/ci-generator.js.map +0 -1
- package/dist/init/detect-framework.d.ts +0 -15
- package/dist/init/detect-framework.d.ts.map +0 -1
- package/dist/init/detect-framework.js +0 -301
- package/dist/init/detect-framework.js.map +0 -1
- package/dist/init/hooks-installer.d.ts +0 -22
- package/dist/init/hooks-installer.d.ts.map +0 -1
- package/dist/init/hooks-installer.js +0 -310
- package/dist/init/hooks-installer.js.map +0 -1
- package/dist/init/index.d.ts +0 -8
- package/dist/init/index.d.ts.map +0 -1
- package/dist/init/index.js +0 -22
- package/dist/init/index.js.map +0 -1
- package/dist/init/templates.d.ts +0 -402
- package/dist/init/templates.d.ts.map +0 -1
- package/dist/init/templates.js +0 -240
- package/dist/init/templates.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -12
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -42
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/telemetry.d.ts +0 -40
- package/dist/mcp/telemetry.d.ts.map +0 -1
- package/dist/mcp/telemetry.js +0 -98
- package/dist/mcp/telemetry.js.map +0 -1
- package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts +0 -32
- package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts.map +0 -1
- package/dist/reality/no-dead-buttons/button-sweep-generator.js +0 -236
- package/dist/reality/no-dead-buttons/button-sweep-generator.js.map +0 -1
- package/dist/reality/no-dead-buttons/index.d.ts +0 -11
- package/dist/reality/no-dead-buttons/index.d.ts.map +0 -1
- package/dist/reality/no-dead-buttons/index.js +0 -18
- package/dist/reality/no-dead-buttons/index.js.map +0 -1
- package/dist/reality/no-dead-buttons/static-scanner.d.ts +0 -34
- package/dist/reality/no-dead-buttons/static-scanner.d.ts.map +0 -1
- package/dist/reality/no-dead-buttons/static-scanner.js +0 -230
- package/dist/reality/no-dead-buttons/static-scanner.js.map +0 -1
- package/dist/reality/reality-graph.d.ts +0 -192
- package/dist/reality/reality-graph.d.ts.map +0 -1
- package/dist/reality/reality-graph.js +0 -600
- package/dist/reality/reality-graph.js.map +0 -1
- package/dist/reality/reality-runner.d.ts +0 -89
- package/dist/reality/reality-runner.d.ts.map +0 -1
- package/dist/reality/reality-runner.js +0 -540
- package/dist/reality/reality-runner.js.map +0 -1
- package/dist/reality/receipt-generator.d.ts +0 -152
- package/dist/reality/receipt-generator.d.ts.map +0 -1
- package/dist/reality/receipt-generator.js +0 -495
- package/dist/reality/receipt-generator.js.map +0 -1
- package/dist/reality/runtime-tracer.d.ts +0 -75
- package/dist/reality/runtime-tracer.d.ts.map +0 -1
- package/dist/reality/runtime-tracer.js +0 -109
- package/dist/reality/runtime-tracer.js.map +0 -1
- package/dist/runtime/auth-utils.d.ts +0 -43
- package/dist/runtime/auth-utils.d.ts.map +0 -1
- package/dist/runtime/auth-utils.js +0 -130
- package/dist/runtime/auth-utils.js.map +0 -1
- package/dist/runtime/client.d.ts +0 -74
- package/dist/runtime/client.d.ts.map +0 -1
- package/dist/runtime/client.js +0 -222
- package/dist/runtime/client.js.map +0 -1
- package/dist/runtime/creds.d.ts +0 -48
- package/dist/runtime/creds.d.ts.map +0 -1
- package/dist/runtime/creds.js +0 -245
- package/dist/runtime/creds.js.map +0 -1
- package/dist/runtime/exit-codes.d.ts +0 -49
- package/dist/runtime/exit-codes.d.ts.map +0 -1
- package/dist/runtime/exit-codes.js +0 -93
- package/dist/runtime/exit-codes.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -9
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js +0 -25
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/json-output.d.ts +0 -42
- package/dist/runtime/json-output.d.ts.map +0 -1
- package/dist/runtime/json-output.js +0 -59
- package/dist/runtime/json-output.js.map +0 -1
- package/dist/runtime/semver.d.ts +0 -37
- package/dist/runtime/semver.d.ts.map +0 -1
- package/dist/runtime/semver.js +0 -110
- package/dist/runtime/semver.js.map +0 -1
- package/dist/scan/dead-ui-detector.d.ts +0 -48
- package/dist/scan/dead-ui-detector.d.ts.map +0 -1
- package/dist/scan/dead-ui-detector.js +0 -170
- package/dist/scan/dead-ui-detector.js.map +0 -1
- package/dist/scan/playwright-sweep.d.ts +0 -40
- package/dist/scan/playwright-sweep.d.ts.map +0 -1
- package/dist/scan/playwright-sweep.js +0 -216
- package/dist/scan/playwright-sweep.js.map +0 -1
- package/dist/scan/proof-bundle.d.ts +0 -25
- package/dist/scan/proof-bundle.d.ts.map +0 -1
- package/dist/scan/proof-bundle.js +0 -203
- package/dist/scan/proof-bundle.js.map +0 -1
- package/dist/scan/proof-graph.d.ts +0 -59
- package/dist/scan/proof-graph.d.ts.map +0 -1
- package/dist/scan/proof-graph.js +0 -64
- package/dist/scan/proof-graph.js.map +0 -1
- package/dist/scan/reality-sniff.d.ts +0 -56
- package/dist/scan/reality-sniff.d.ts.map +0 -1
- package/dist/scan/reality-sniff.js +0 -200
- package/dist/scan/reality-sniff.js.map +0 -1
- package/dist/scan/structural-verifier.d.ts +0 -20
- package/dist/scan/structural-verifier.d.ts.map +0 -1
- package/dist/scan/structural-verifier.js +0 -112
- package/dist/scan/structural-verifier.js.map +0 -1
- package/dist/scan/verification-engine.d.ts +0 -47
- package/dist/scan/verification-engine.d.ts.map +0 -1
- package/dist/scan/verification-engine.js +0 -141
- package/dist/scan/verification-engine.js.map +0 -1
- package/dist/scanner/baseline.d.ts +0 -52
- package/dist/scanner/baseline.d.ts.map +0 -1
- package/dist/scanner/baseline.js +0 -85
- package/dist/scanner/baseline.js.map +0 -1
- package/dist/scanner/incremental.d.ts +0 -30
- package/dist/scanner/incremental.d.ts.map +0 -1
- package/dist/scanner/incremental.js +0 -82
- package/dist/scanner/incremental.js.map +0 -1
- package/dist/scanner/parallel.d.ts +0 -43
- package/dist/scanner/parallel.d.ts.map +0 -1
- package/dist/scanner/parallel.js +0 -99
- package/dist/scanner/parallel.js.map +0 -1
- package/dist/standalone.d.ts +0 -1
- package/dist/standalone.d.ts.map +0 -1
- package/dist/standalone.js +0 -1
- package/dist/standalone.js.map +0 -1
- package/dist/truth-pack/index.d.ts +0 -102
- package/dist/truth-pack/index.d.ts.map +0 -1
- package/dist/truth-pack/index.js +0 -694
- package/dist/truth-pack/index.js.map +0 -1
- package/dist/ui/frame.d.ts +0 -68
- package/dist/ui/frame.d.ts.map +0 -1
- package/dist/ui/frame.js +0 -165
- package/dist/ui/frame.js.map +0 -1
- package/dist/ui/index.d.ts +0 -5
- package/dist/ui/index.d.ts.map +0 -1
- package/dist/ui/index.js +0 -16
- package/dist/ui/index.js.map +0 -1
- package/dist/ui.d.ts +0 -36
- package/dist/ui.d.ts.map +0 -1
- package/dist/ui.js +0 -45
- package/dist/ui.js.map +0 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Output System
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent, deterministic output across all vibecheck commands.
|
|
5
|
+
* This is what makes vibecheck feel "enterprise-grade".
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Graceful fallback for missing compiled modules
|
|
9
|
+
let EXIT_CODES, formatVerdictOutput;
|
|
10
|
+
|
|
11
|
+
// Exit codes per product spec:
|
|
12
|
+
// 0 = SHIP / no blockers
|
|
13
|
+
// 1 = WARN (allowed if you choose)
|
|
14
|
+
// 2 = BLOCK / blockers found
|
|
15
|
+
EXIT_CODES = {
|
|
16
|
+
SHIP: 0, // Ready to ship, no blockers
|
|
17
|
+
PASS: 0, // Alias for SHIP
|
|
18
|
+
WARN: 1, // Warnings found (allowed)
|
|
19
|
+
BLOCK: 2, // Blockers found, do not ship
|
|
20
|
+
FAIL: 2, // Alias for BLOCK
|
|
21
|
+
MISCONFIG: 2, // Configuration error = block
|
|
22
|
+
INTERNAL: 2, // Internal error = block (safe default)
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const verdictFormatter = require('../../../dist/lib/cli/verdict-formatter');
|
|
27
|
+
formatVerdictOutput = verdictFormatter.formatVerdictOutput;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
// Fallback when dist not built
|
|
30
|
+
formatVerdictOutput = (verdict, options) => {
|
|
31
|
+
const c = {
|
|
32
|
+
reset: '\x1b[0m',
|
|
33
|
+
green: '\x1b[32m',
|
|
34
|
+
red: '\x1b[31m',
|
|
35
|
+
yellow: '\x1b[33m',
|
|
36
|
+
cyan: '\x1b[36m',
|
|
37
|
+
dim: '\x1b[2m',
|
|
38
|
+
bold: '\x1b[1m',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (!verdict) return 'No verdict available';
|
|
42
|
+
|
|
43
|
+
const icon = verdict.verdict === 'PASS' ? `${c.green}✓${c.reset}` :
|
|
44
|
+
verdict.verdict === 'FAIL' ? `${c.red}✗${c.reset}` :
|
|
45
|
+
`${c.yellow}⚠${c.reset}`;
|
|
46
|
+
|
|
47
|
+
let output = `\n${icon} ${c.bold}${verdict.verdict}${c.reset}\n`;
|
|
48
|
+
|
|
49
|
+
if (verdict.summary) {
|
|
50
|
+
output += `\n${c.dim}Summary:${c.reset}\n`;
|
|
51
|
+
output += ` Blockers: ${verdict.summary.blockers || 0}\n`;
|
|
52
|
+
output += ` Warnings: ${verdict.summary.warnings || 0}\n`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (verdict.findings && verdict.findings.length > 0) {
|
|
56
|
+
output += `\n${c.dim}Findings:${c.reset}\n`;
|
|
57
|
+
for (const finding of verdict.findings.slice(0, 10)) {
|
|
58
|
+
const sevColor = finding.severity === 'critical' ? c.red :
|
|
59
|
+
finding.severity === 'high' ? c.red :
|
|
60
|
+
finding.severity === 'medium' ? c.yellow : c.dim;
|
|
61
|
+
output += ` ${sevColor}[${finding.severity?.toUpperCase() || 'INFO'}]${c.reset} ${finding.title || finding.message || 'Unknown issue'}\n`;
|
|
62
|
+
if (finding.file) {
|
|
63
|
+
output += ` ${c.cyan}${finding.file}${finding.line ? `:${finding.line}` : ''}${c.reset}\n`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (verdict.findings.length > 10) {
|
|
67
|
+
output += ` ${c.dim}... and ${verdict.findings.length - 10} more${c.reset}\n`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return output;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Format scan output with unified contract
|
|
77
|
+
*/
|
|
78
|
+
function formatScanOutput(result, options = {}) {
|
|
79
|
+
const { verbose = false, json = false } = options;
|
|
80
|
+
|
|
81
|
+
if (json) {
|
|
82
|
+
return JSON.stringify(result, null, 2);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return formatVerdictOutput(result.verdict, { verbose, json });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get exit code from verdict
|
|
90
|
+
* Per spec: 0=SHIP, 1=WARN, 2=BLOCK
|
|
91
|
+
*/
|
|
92
|
+
function getExitCode(verdict) {
|
|
93
|
+
if (!verdict) return EXIT_CODES.BLOCK; // Safe default
|
|
94
|
+
|
|
95
|
+
switch (verdict.verdict) {
|
|
96
|
+
case 'SHIP':
|
|
97
|
+
case 'PASS':
|
|
98
|
+
return EXIT_CODES.SHIP; // 0
|
|
99
|
+
case 'WARN':
|
|
100
|
+
return EXIT_CODES.WARN; // 1
|
|
101
|
+
case 'BLOCK':
|
|
102
|
+
case 'FAIL':
|
|
103
|
+
return EXIT_CODES.BLOCK; // 2
|
|
104
|
+
case 'ERROR':
|
|
105
|
+
case 'MISCONFIG':
|
|
106
|
+
return EXIT_CODES.BLOCK; // 2 (safe default)
|
|
107
|
+
default:
|
|
108
|
+
return EXIT_CODES.BLOCK; // 2 (safe default)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Handle errors with proper exit codes
|
|
114
|
+
*/
|
|
115
|
+
function handleError(error, context = '') {
|
|
116
|
+
const errorType = classifyError(error);
|
|
117
|
+
|
|
118
|
+
let exitCode = EXIT_CODES.INTERNAL;
|
|
119
|
+
let message = error.message || 'Unknown error';
|
|
120
|
+
let nextStep = 'Run: vibecheck doctor';
|
|
121
|
+
|
|
122
|
+
switch (errorType) {
|
|
123
|
+
case 'MISCONFIG':
|
|
124
|
+
exitCode = EXIT_CODES.MISCONFIG;
|
|
125
|
+
message = `Configuration error: ${message}`;
|
|
126
|
+
nextStep = 'Run: vibecheck doctor --fix';
|
|
127
|
+
break;
|
|
128
|
+
case 'MISSING_DEPS':
|
|
129
|
+
exitCode = EXIT_CODES.MISCONFIG;
|
|
130
|
+
message = `Missing dependencies: ${message}`;
|
|
131
|
+
nextStep = 'Run: vibecheck doctor';
|
|
132
|
+
break;
|
|
133
|
+
case 'PERMISSION':
|
|
134
|
+
exitCode = EXIT_CODES.MISCONFIG;
|
|
135
|
+
message = `Permission error: ${message}`;
|
|
136
|
+
nextStep = 'Check file permissions and run: vibecheck doctor';
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
exitCode = EXIT_CODES.INTERNAL;
|
|
140
|
+
message = `Internal error: ${message}`;
|
|
141
|
+
nextStep = 'This looks like a bug. Run: vibecheck doctor';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
exitCode,
|
|
146
|
+
message: `${context ? `[${context}] ` : ''}${message}`,
|
|
147
|
+
nextStep,
|
|
148
|
+
errorType,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function classifyError(error) {
|
|
153
|
+
const message = (error.message || '').toLowerCase();
|
|
154
|
+
const code = error.code || '';
|
|
155
|
+
|
|
156
|
+
if (code === 'ENOENT' || message.includes('not found') || message.includes('missing')) {
|
|
157
|
+
return 'MISSING_DEPS';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (code === 'EACCES' || code === 'EPERM' || message.includes('permission')) {
|
|
161
|
+
return 'PERMISSION';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (message.includes('config') || message.includes('environment') || message.includes('env')) {
|
|
165
|
+
return 'MISCONFIG';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return 'INTERNAL';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Print error with proper formatting
|
|
173
|
+
*/
|
|
174
|
+
function printError(error, context = '') {
|
|
175
|
+
const handled = handleError(error, context);
|
|
176
|
+
|
|
177
|
+
console.error(`\n${handled.message}`);
|
|
178
|
+
console.error(`\n${handled.nextStep}\n`);
|
|
179
|
+
|
|
180
|
+
return handled.exitCode;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = {
|
|
184
|
+
formatScanOutput,
|
|
185
|
+
getExitCode,
|
|
186
|
+
handleError,
|
|
187
|
+
printError,
|
|
188
|
+
EXIT_CODES,
|
|
189
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// bin/runners/lib/validate-patch.js
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
function isRelSafe(p) {
|
|
6
|
+
if (!p || typeof p !== "string") return false;
|
|
7
|
+
if (p.includes("\0")) return false;
|
|
8
|
+
if (path.isAbsolute(p)) return false;
|
|
9
|
+
const norm = path.normalize(p).replace(/\\/g, "/");
|
|
10
|
+
if (norm.startsWith("../") || norm.startsWith("..\\")) return false;
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseDiffTouchedFiles(diff) {
|
|
15
|
+
const files = new Set();
|
|
16
|
+
const lines = String(diff || "").split(/\r?\n/);
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
if (line.startsWith("+++ ")) {
|
|
19
|
+
const p = line.slice(4).trim();
|
|
20
|
+
if (p === "/dev/null") continue;
|
|
21
|
+
const cleaned = p.startsWith("b/") ? p.slice(2) : p;
|
|
22
|
+
files.add(cleaned);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return Array.from(files);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function countChangedLines(diff) {
|
|
29
|
+
const lines = String(diff || "").split(/\r?\n/);
|
|
30
|
+
let adds = 0, dels = 0;
|
|
31
|
+
for (const l of lines) {
|
|
32
|
+
if (l.startsWith("+++ ") || l.startsWith("--- ") || l.startsWith("@@")) continue;
|
|
33
|
+
if (l.startsWith("+")) adds++;
|
|
34
|
+
if (l.startsWith("-")) dels++;
|
|
35
|
+
}
|
|
36
|
+
return { adds, dels, total: adds + dels };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function extractAddedApiStrings(diff) {
|
|
40
|
+
const out = [];
|
|
41
|
+
const lines = String(diff || "").split(/\r?\n/);
|
|
42
|
+
for (const l of lines) {
|
|
43
|
+
if (!l.startsWith("+") || l.startsWith("+++")) continue;
|
|
44
|
+
const m = l.match(/["'`](\/api\/[^"'` ]+)["'`]/g);
|
|
45
|
+
if (m) out.push(...m.map(x => x.replace(/^[+"'`]+|[+"'`]+$/g, "")));
|
|
46
|
+
}
|
|
47
|
+
return Array.from(new Set(out));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function extractAddedEnvNames(diff) {
|
|
51
|
+
const out = new Set();
|
|
52
|
+
const lines = String(diff || "").split(/\r?\n/);
|
|
53
|
+
for (const l of lines) {
|
|
54
|
+
if (!l.startsWith("+") || l.startsWith("+++")) continue;
|
|
55
|
+
|
|
56
|
+
const re1 = /process\.env\.([A-Z0-9_]+)/g;
|
|
57
|
+
let m;
|
|
58
|
+
while ((m = re1.exec(l)) !== null) out.add(m[1]);
|
|
59
|
+
|
|
60
|
+
const re2 = /import\.meta\.env\.([A-Z0-9_]+)/g;
|
|
61
|
+
while ((m = re2.exec(l)) !== null) out.add(m[1]);
|
|
62
|
+
}
|
|
63
|
+
return Array.from(out);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validatePatchResponse({
|
|
67
|
+
repoRoot,
|
|
68
|
+
patchJson,
|
|
69
|
+
mission,
|
|
70
|
+
truthpack,
|
|
71
|
+
allowedFiles,
|
|
72
|
+
limits
|
|
73
|
+
}) {
|
|
74
|
+
const errors = [];
|
|
75
|
+
const warnings = [];
|
|
76
|
+
|
|
77
|
+
const lim = {
|
|
78
|
+
maxEdits: limits?.maxEdits ?? 6,
|
|
79
|
+
maxFiles: limits?.maxFiles ?? 6,
|
|
80
|
+
maxChangedLines: limits?.maxChangedLines ?? 400
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (!patchJson || typeof patchJson !== "object") errors.push("Patch JSON missing or not an object.");
|
|
84
|
+
if (patchJson.status !== "ok") errors.push(`Patch status must be "ok" (got ${patchJson?.status}).`);
|
|
85
|
+
if (!Array.isArray(patchJson.edits)) errors.push("Patch edits must be an array.");
|
|
86
|
+
if ((patchJson.edits || []).length > lim.maxEdits) errors.push(`Too many edits (>${lim.maxEdits}).`);
|
|
87
|
+
|
|
88
|
+
if (errors.length) return { ok: false, errors, warnings };
|
|
89
|
+
|
|
90
|
+
const allowed = new Set((allowedFiles || []).filter(Boolean));
|
|
91
|
+
const touchedAll = new Set();
|
|
92
|
+
|
|
93
|
+
for (const ed of patchJson.edits) {
|
|
94
|
+
if (!ed || typeof ed !== "object") { errors.push("Edit entry not an object."); continue; }
|
|
95
|
+
if (!isRelSafe(ed.path)) errors.push(`Unsafe edit path: ${ed.path}`);
|
|
96
|
+
if (typeof ed.diff !== "string" || !ed.diff.includes("\n+++ ")) errors.push(`Diff missing or not unified for: ${ed.path}`);
|
|
97
|
+
|
|
98
|
+
const touched = parseDiffTouchedFiles(ed.diff);
|
|
99
|
+
for (const f of touched) touchedAll.add(f);
|
|
100
|
+
|
|
101
|
+
if (touched.length === 0) errors.push(`No touched file detected in diff for ${ed.path}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const touchedList = Array.from(touchedAll);
|
|
105
|
+
if (touchedList.length > lim.maxFiles) errors.push(`Too many touched files (>${lim.maxFiles}).`);
|
|
106
|
+
|
|
107
|
+
for (const f of touchedList) {
|
|
108
|
+
if (!isRelSafe(f)) errors.push(`Unsafe touched file: ${f}`);
|
|
109
|
+
if (allowed.size && !allowed.has(f)) {
|
|
110
|
+
errors.push(`Touched file not allowed by mission evidence: ${f}`);
|
|
111
|
+
}
|
|
112
|
+
if (f.includes("node_modules/") || f.includes(".next/") || f.includes("dist/") || f.includes("build/")) {
|
|
113
|
+
errors.push(`Touched forbidden build/vendor file: ${f}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let totalChanged = 0;
|
|
118
|
+
for (const ed of patchJson.edits) totalChanged += countChangedLines(ed.diff).total;
|
|
119
|
+
if (totalChanged > lim.maxChangedLines) errors.push(`Patch too large (>${lim.maxChangedLines} changed lines).`);
|
|
120
|
+
|
|
121
|
+
const type = mission?.type || "GENERIC_FIX";
|
|
122
|
+
const combinedDiff = patchJson.edits.map(e => e.diff).join("\n");
|
|
123
|
+
|
|
124
|
+
const addedApis = extractAddedApiStrings(combinedDiff);
|
|
125
|
+
if (addedApis.length && type !== "FIX_MISSING_ROUTE") {
|
|
126
|
+
errors.push(`No-drift: patch adds /api strings (${addedApis.join(", ")}) but mission is ${type}.`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const addedEnv = extractAddedEnvNames(combinedDiff);
|
|
130
|
+
if (addedEnv.length && type !== "FIX_ENV_CONTRACT") {
|
|
131
|
+
warnings.push(`Patch introduces new env var usage (${addedEnv.join(", ")}). If that wasn't intended, reject this patch.`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const touchesEntitlements = /enforceFeature|enforceLimit|getEntitlements|subscription|tier|plan|credits/i.test(combinedDiff);
|
|
135
|
+
if (touchesEntitlements && !["ENFORCE_PAID_SURFACE","FIX_STRIPE_WEBHOOKS","REMOVE_OWNER_MODE"].includes(type)) {
|
|
136
|
+
errors.push(`No-drift: patch touches entitlements/billing logic but mission is ${type}.`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const touchesMiddleware = /middleware\.(ts|js)|matcher\s*:|NextResponse\.(redirect|rewrite)/i.test(combinedDiff);
|
|
140
|
+
if (touchesMiddleware && type !== "ADD_SERVER_AUTH") {
|
|
141
|
+
warnings.push("Patch touches Next middleware/matcher outside ADD_SERVER_AUTH mission. Verify intent.");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
for (const f of touchedList) {
|
|
145
|
+
const abs = path.join(repoRoot, f);
|
|
146
|
+
if (!fs.existsSync(abs)) {
|
|
147
|
+
if (type === "FIX_MISSING_ROUTE" && (f.includes("app/api/") || f.includes("pages/api/"))) continue;
|
|
148
|
+
warnings.push(`Touched file does not exist (would be created): ${f}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (errors.length) return { ok: false, errors, warnings };
|
|
153
|
+
return { ok: true, errors: [], warnings };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = { validatePatchResponse, parseDiffTouchedFiles };
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification Module - Pure JavaScript Implementation
|
|
3
|
+
* For CLI usage without TypeScript compilation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const os = require("os");
|
|
9
|
+
const crypto = require("crypto");
|
|
10
|
+
const { spawn } = require("child_process");
|
|
11
|
+
|
|
12
|
+
// Constants
|
|
13
|
+
const PROTECTED_PATHS = [
|
|
14
|
+
".git",
|
|
15
|
+
"node_modules",
|
|
16
|
+
".env",
|
|
17
|
+
".env.local",
|
|
18
|
+
".env.production",
|
|
19
|
+
".env.development",
|
|
20
|
+
"package-lock.json",
|
|
21
|
+
"pnpm-lock.yaml",
|
|
22
|
+
"yarn.lock",
|
|
23
|
+
"bun.lockb",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const DANGEROUS_COMMANDS = [
|
|
27
|
+
"rm -rf",
|
|
28
|
+
"rm -r /",
|
|
29
|
+
"rmdir /s",
|
|
30
|
+
"del /f /s /q",
|
|
31
|
+
"sudo",
|
|
32
|
+
"chmod 777",
|
|
33
|
+
"curl | bash",
|
|
34
|
+
"curl | sh",
|
|
35
|
+
"wget | bash",
|
|
36
|
+
"wget | sh",
|
|
37
|
+
"> /dev/sd",
|
|
38
|
+
"mkfs",
|
|
39
|
+
"dd if=",
|
|
40
|
+
":(){:|:&};:",
|
|
41
|
+
"format c:",
|
|
42
|
+
"rd /s /q",
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const SECRET_PATTERNS = [
|
|
46
|
+
{ name: "AWS Access Key", pattern: /AKIA[0-9A-Z]{16}/g, severity: "critical" },
|
|
47
|
+
{ name: "GitHub Token", pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/g, severity: "critical" },
|
|
48
|
+
{ name: "Stripe Key", pattern: /sk_live_[0-9a-zA-Z]{24}/g, severity: "critical" },
|
|
49
|
+
{ name: "Private Key", pattern: /-----BEGIN (?:RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----/g, severity: "critical" },
|
|
50
|
+
{ name: "Database URL", pattern: /(?:postgres|mysql|mongodb|redis):\/\/[^\s'"]+:[^\s'"]+@[^\s'"]+/gi, severity: "critical" },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const STUB_PATTERNS = [
|
|
54
|
+
{ name: "Placeholder function", pattern: /throw new Error\(['"]not implemented['"]\)/gi },
|
|
55
|
+
{ name: "Console placeholder", pattern: /console\.log\(['"]placeholder['"]\)/gi },
|
|
56
|
+
{ name: "Lorem ipsum", pattern: /lorem\s+ipsum/gi },
|
|
57
|
+
{ name: "NotImplementedError", pattern: /raise NotImplementedError/g },
|
|
58
|
+
{ name: "unimplemented!", pattern: /unimplemented!\(\)/g },
|
|
59
|
+
{ name: "todo!", pattern: /todo!\(\)/g },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const FORMAT_RETRY_PROMPT = `Your response was not in the required format. Please respond with ONLY valid JSON in this exact structure:
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
"format": "vibecheck-v1",
|
|
66
|
+
"diff": "<unified diff for ALL file changes>",
|
|
67
|
+
"commands": ["optional array of commands to run"],
|
|
68
|
+
"tests": ["optional array of test commands"],
|
|
69
|
+
"notes": "optional notes"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
If you cannot provide the requested changes, respond with:
|
|
73
|
+
{ "format": "vibecheck-v1", "error": "reason why you cannot provide the changes" }
|
|
74
|
+
|
|
75
|
+
Do NOT include any markdown fencing, explanations, or text outside the JSON object.`;
|
|
76
|
+
|
|
77
|
+
const DIFF_FORMAT_RETRY_PROMPT = `Your diff is malformed. The diff field must be a valid unified diff containing:
|
|
78
|
+
- File headers starting with "diff --git a/path b/path"
|
|
79
|
+
- Old file marker "--- a/path" or "--- /dev/null" for new files
|
|
80
|
+
- New file marker "+++ b/path"
|
|
81
|
+
- Hunk headers like "@@ -start,count +start,count @@"
|
|
82
|
+
|
|
83
|
+
Please regenerate your response with a properly formatted unified diff.`;
|
|
84
|
+
|
|
85
|
+
// Extract JSON from raw input
|
|
86
|
+
function extractJson(raw) {
|
|
87
|
+
const trimmed = raw.trim();
|
|
88
|
+
if (trimmed.startsWith("{")) return trimmed;
|
|
89
|
+
|
|
90
|
+
const jsonFenceMatch = trimmed.match(/```json\s*([\s\S]*?)\s*```/);
|
|
91
|
+
if (jsonFenceMatch) return jsonFenceMatch[1].trim();
|
|
92
|
+
|
|
93
|
+
const plainFenceMatch = trimmed.match(/```\s*([\s\S]*?)\s*```/);
|
|
94
|
+
if (plainFenceMatch) {
|
|
95
|
+
const content = plainFenceMatch[1].trim();
|
|
96
|
+
if (content.startsWith("{")) return content;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Validate diff structure
|
|
103
|
+
function isValidDiffStructure(diff) {
|
|
104
|
+
if (!diff || typeof diff !== "string" || diff.trim().length === 0) return false;
|
|
105
|
+
const hasDiffHeader = diff.includes("diff --git") || diff.includes("diff -");
|
|
106
|
+
const hasOldMarker = diff.includes("---");
|
|
107
|
+
const hasNewMarker = diff.includes("+++");
|
|
108
|
+
const hasHunk = /@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@/.test(diff);
|
|
109
|
+
return hasDiffHeader && hasOldMarker && hasNewMarker && hasHunk;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Parse diff to extract files
|
|
113
|
+
function parseDiff(diffStr) {
|
|
114
|
+
const files = [];
|
|
115
|
+
const fileChunks = diffStr.split(/^diff --git /m).filter(Boolean);
|
|
116
|
+
|
|
117
|
+
for (const chunk of fileChunks) {
|
|
118
|
+
const lines = chunk.split("\n");
|
|
119
|
+
if (lines.length === 0) continue;
|
|
120
|
+
const headerMatch = lines[0].match(/a\/(.+?)\s+b\/(.+)/);
|
|
121
|
+
if (!headerMatch) continue;
|
|
122
|
+
files.push({ path: headerMatch[2], additions: 0, deletions: 0 });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { files, totalFiles: files.length };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Validate format
|
|
129
|
+
function validateFormat(raw) {
|
|
130
|
+
if (!raw || typeof raw !== "string") {
|
|
131
|
+
return { valid: false, retryPrompt: FORMAT_RETRY_PROMPT, error: "Empty input" };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const jsonStr = extractJson(raw);
|
|
135
|
+
if (!jsonStr) {
|
|
136
|
+
return { valid: false, retryPrompt: FORMAT_RETRY_PROMPT, error: "Could not extract JSON" };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let parsed;
|
|
140
|
+
try {
|
|
141
|
+
parsed = JSON.parse(jsonStr);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
return { valid: false, retryPrompt: FORMAT_RETRY_PROMPT, error: `JSON parse error: ${e.message}` };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!parsed || typeof parsed !== "object") {
|
|
147
|
+
return { valid: false, retryPrompt: FORMAT_RETRY_PROMPT, error: "Response must be a JSON object" };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (parsed.format !== "vibecheck-v1") {
|
|
151
|
+
return { valid: false, retryPrompt: FORMAT_RETRY_PROMPT, error: `Invalid format: ${parsed.format}` };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (parsed.error) {
|
|
155
|
+
return { valid: true, output: { format: "vibecheck-v1", diff: "", error: parsed.error } };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (typeof parsed.diff !== "string" || parsed.diff.trim().length === 0) {
|
|
159
|
+
return { valid: false, retryPrompt: DIFF_FORMAT_RETRY_PROMPT, error: "Empty diff" };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!isValidDiffStructure(parsed.diff)) {
|
|
163
|
+
return { valid: false, retryPrompt: DIFF_FORMAT_RETRY_PROMPT, error: "Invalid diff structure" };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { valid: true, output: parsed };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Validate path
|
|
170
|
+
function validatePath(filePath) {
|
|
171
|
+
const normalized = filePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
172
|
+
|
|
173
|
+
if (normalized.includes("..") || normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized)) {
|
|
174
|
+
return { status: "fail", message: `Path traversal detected: ${filePath}` };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (const protected_ of PROTECTED_PATHS) {
|
|
178
|
+
if (normalized === protected_ || normalized.startsWith(protected_ + "/")) {
|
|
179
|
+
return { status: "fail", message: `Protected path: ${filePath}` };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return { status: "pass", message: `Safe: ${normalized}` };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Validate command
|
|
187
|
+
function validateCommand(command) {
|
|
188
|
+
const normalized = command.toLowerCase().trim();
|
|
189
|
+
for (const dangerous of DANGEROUS_COMMANDS) {
|
|
190
|
+
if (normalized.includes(dangerous.toLowerCase())) {
|
|
191
|
+
return { status: "fail", message: `Dangerous command: ${command}` };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return { status: "pass", message: "Safe command" };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Detect secrets
|
|
198
|
+
function detectSecrets(content, filePath) {
|
|
199
|
+
if (filePath.endsWith(".md") || filePath.includes("__mocks__")) {
|
|
200
|
+
return { status: "pass", message: "Skipped" };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
for (const { name, pattern, severity } of SECRET_PATTERNS) {
|
|
204
|
+
pattern.lastIndex = 0;
|
|
205
|
+
if (pattern.test(content)) {
|
|
206
|
+
return { status: "fail", message: `${severity.toUpperCase()} secret: ${name}` };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { status: "pass", message: "No secrets" };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Detect stubs
|
|
213
|
+
function detectStubs(content, mode) {
|
|
214
|
+
for (const { name, pattern } of STUB_PATTERNS) {
|
|
215
|
+
pattern.lastIndex = 0;
|
|
216
|
+
if (pattern.test(content)) {
|
|
217
|
+
return { status: "fail", message: `Placeholder code: ${name}` };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return { status: "pass", message: "No stubs" };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Build failure context
|
|
224
|
+
function buildFailureContext(blockers) {
|
|
225
|
+
if (blockers.length === 0) return "";
|
|
226
|
+
|
|
227
|
+
const top3 = blockers.slice(0, 3);
|
|
228
|
+
return `## Verification Failed
|
|
229
|
+
|
|
230
|
+
Fix ONLY these issues. Return corrected diff in vibecheck-v1 JSON format.
|
|
231
|
+
|
|
232
|
+
### Issues:
|
|
233
|
+
${top3.map((b, i) => `${i + 1}. ${b}`).join("\n")}
|
|
234
|
+
${blockers.length > 3 ? `\n... and ${blockers.length - 3} more` : ""}
|
|
235
|
+
|
|
236
|
+
Respond with corrected vibecheck-v1 JSON only.`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Main verification function
|
|
240
|
+
async function verifyAgentOutput(rawResponse, context) {
|
|
241
|
+
const checks = [];
|
|
242
|
+
const blockers = [];
|
|
243
|
+
const warnings = [];
|
|
244
|
+
|
|
245
|
+
// Format validation
|
|
246
|
+
const formatResult = validateFormat(rawResponse);
|
|
247
|
+
if (!formatResult.valid) {
|
|
248
|
+
return {
|
|
249
|
+
success: false,
|
|
250
|
+
checks: [{ check: "format-validation", status: "fail", message: formatResult.error }],
|
|
251
|
+
blockers: [formatResult.error],
|
|
252
|
+
warnings: [],
|
|
253
|
+
failureContext: formatResult.retryPrompt,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const output = formatResult.output;
|
|
258
|
+
|
|
259
|
+
// Handle error response
|
|
260
|
+
if (output.error) {
|
|
261
|
+
return {
|
|
262
|
+
success: false,
|
|
263
|
+
checks: [{ check: "agent-error", status: "fail", message: output.error }],
|
|
264
|
+
blockers: [`Agent error: ${output.error}`],
|
|
265
|
+
warnings: [],
|
|
266
|
+
parsedOutput: output,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Diff structure
|
|
271
|
+
checks.push({ check: "diff-structure", status: "pass", message: "Valid diff" });
|
|
272
|
+
|
|
273
|
+
// Path validation
|
|
274
|
+
const parsed = parseDiff(output.diff);
|
|
275
|
+
for (const file of parsed.files) {
|
|
276
|
+
const pathResult = validatePath(file.path);
|
|
277
|
+
if (pathResult.status === "fail") {
|
|
278
|
+
checks.push({ check: "path-safety", status: "fail", message: pathResult.message, file: file.path });
|
|
279
|
+
blockers.push(pathResult.message);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!blockers.some(b => b.includes("Path"))) {
|
|
283
|
+
checks.push({ check: "path-safety", status: "pass", message: `${parsed.files.length} path(s) validated` });
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Command validation
|
|
287
|
+
if (output.commands && output.commands.length > 0) {
|
|
288
|
+
for (const cmd of output.commands) {
|
|
289
|
+
const cmdResult = validateCommand(cmd);
|
|
290
|
+
if (cmdResult.status === "fail") {
|
|
291
|
+
checks.push({ check: "command-safety", status: "fail", message: cmdResult.message });
|
|
292
|
+
blockers.push(cmdResult.message);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (!blockers.some(b => b.includes("Dangerous"))) {
|
|
296
|
+
checks.push({ check: "command-safety", status: "pass", message: `${output.commands.length} command(s) validated` });
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
checks.push({ check: "command-safety", status: "pass", message: "No commands" });
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Fail fast on blockers
|
|
303
|
+
if (blockers.length > 0) {
|
|
304
|
+
return {
|
|
305
|
+
success: false,
|
|
306
|
+
checks,
|
|
307
|
+
blockers,
|
|
308
|
+
warnings,
|
|
309
|
+
failureContext: buildFailureContext(blockers),
|
|
310
|
+
parsedOutput: output,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Content checks (simplified - check diff content directly)
|
|
315
|
+
const secretCheck = detectSecrets(output.diff, "diff");
|
|
316
|
+
if (secretCheck.status === "fail") {
|
|
317
|
+
checks.push({ check: "secret-detection", status: "fail", message: secretCheck.message });
|
|
318
|
+
blockers.push(secretCheck.message);
|
|
319
|
+
} else {
|
|
320
|
+
checks.push({ check: "secret-detection", status: "pass", message: "No secrets in diff" });
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const stubCheck = detectStubs(output.diff, context.mode);
|
|
324
|
+
if (stubCheck.status === "fail" && context.mode === "ship") {
|
|
325
|
+
checks.push({ check: "stub-detection", status: "fail", message: stubCheck.message });
|
|
326
|
+
blockers.push(stubCheck.message);
|
|
327
|
+
} else if (stubCheck.status === "fail") {
|
|
328
|
+
checks.push({ check: "stub-detection", status: "warn", message: stubCheck.message });
|
|
329
|
+
warnings.push(stubCheck.message);
|
|
330
|
+
} else {
|
|
331
|
+
checks.push({ check: "stub-detection", status: "pass", message: "No placeholder code" });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const success = blockers.length === 0;
|
|
335
|
+
return {
|
|
336
|
+
success,
|
|
337
|
+
checks,
|
|
338
|
+
blockers,
|
|
339
|
+
warnings,
|
|
340
|
+
failureContext: success ? undefined : buildFailureContext(blockers),
|
|
341
|
+
parsedOutput: output,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
module.exports = { verifyAgentOutput };
|