@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,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan Output Schema & Validation
|
|
3
|
+
*
|
|
4
|
+
* Defines the stable contract for scan output in JSON mode.
|
|
5
|
+
* Used by CI/CD systems and programmatic consumers.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const SCHEMA_VERSION = "1.0.0";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} Finding
|
|
12
|
+
* @property {string} id - Unique finding identifier
|
|
13
|
+
* @property {string} type - Finding type (secret, stub, vulnerability, etc.)
|
|
14
|
+
* @property {'critical'|'high'|'medium'|'low'|'info'} severity - Severity level
|
|
15
|
+
* @property {string} message - Human-readable description
|
|
16
|
+
* @property {string} [file] - File path where found
|
|
17
|
+
* @property {number} [line] - Line number
|
|
18
|
+
* @property {number} confidence - Confidence score 0-100
|
|
19
|
+
* @property {string} [suggestedFix] - Remediation guidance
|
|
20
|
+
* @property {boolean} blocksShip - Whether this blocks shipping
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} ScanResult
|
|
25
|
+
* @property {string} schemaVersion - Schema version for compatibility
|
|
26
|
+
* @property {boolean} success - Whether scan completed without errors
|
|
27
|
+
* @property {'pass'|'fail'|'warn'} verdict - Overall verdict
|
|
28
|
+
* @property {number} score - Health score 0-100
|
|
29
|
+
* @property {Object} summary - Summary counts
|
|
30
|
+
* @property {number} summary.total - Total findings
|
|
31
|
+
* @property {number} summary.critical - Critical findings
|
|
32
|
+
* @property {number} summary.high - High findings
|
|
33
|
+
* @property {number} summary.medium - Medium findings
|
|
34
|
+
* @property {number} summary.low - Low findings
|
|
35
|
+
* @property {number} summary.blockers - Findings that block shipping
|
|
36
|
+
* @property {Finding[]} findings - All findings
|
|
37
|
+
* @property {Object} metadata - Scan metadata
|
|
38
|
+
* @property {string} metadata.scanId - Unique scan ID
|
|
39
|
+
* @property {string} metadata.timestamp - ISO timestamp
|
|
40
|
+
* @property {number} metadata.duration - Duration in ms
|
|
41
|
+
* @property {string} metadata.projectPath - Scanned path
|
|
42
|
+
* @property {Object} [error] - Error details if failed
|
|
43
|
+
* @property {string} error.message - Error message
|
|
44
|
+
* @property {string} error.code - Error code
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Confidence levels for different finding types
|
|
49
|
+
*/
|
|
50
|
+
const CONFIDENCE_LEVELS = {
|
|
51
|
+
// High confidence - these are almost certainly issues
|
|
52
|
+
AWS_KEY: 95,
|
|
53
|
+
PRIVATE_KEY: 95,
|
|
54
|
+
STRIPE_LIVE_KEY: 95,
|
|
55
|
+
GITHUB_TOKEN: 90,
|
|
56
|
+
DATABASE_URL: 90,
|
|
57
|
+
|
|
58
|
+
// Medium-high confidence - very likely issues
|
|
59
|
+
GENERIC_API_KEY: 75,
|
|
60
|
+
JWT_TOKEN: 70,
|
|
61
|
+
BEARER_TOKEN: 70,
|
|
62
|
+
HARDCODED_PASSWORD: 70,
|
|
63
|
+
|
|
64
|
+
// Medium confidence - review recommended
|
|
65
|
+
TODO_COMMENT: 50,
|
|
66
|
+
MOCK_DATA: 60,
|
|
67
|
+
PLACEHOLDER: 65,
|
|
68
|
+
LOREM_IPSUM: 80,
|
|
69
|
+
|
|
70
|
+
// Lower confidence - context-dependent
|
|
71
|
+
LOCALHOST_URL: 40,
|
|
72
|
+
TEST_EMAIL: 35,
|
|
73
|
+
CONSOLE_LOG: 30,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Determine if a finding should block shipping
|
|
78
|
+
* Based on severity and confidence
|
|
79
|
+
*/
|
|
80
|
+
function isBlocker(finding) {
|
|
81
|
+
// Critical findings block only if confidence > 80% (hardened threshold)
|
|
82
|
+
if (finding.severity === 'critical' && finding.confidence > 80) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// High findings block only if confidence > 90% (hardened threshold)
|
|
87
|
+
if (finding.severity === 'high' && finding.confidence > 90) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Secrets always block in ship mode (high confidence by nature)
|
|
92
|
+
if (finding.type?.includes('secret') || finding.type?.includes('key')) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get confidence score for a finding type
|
|
101
|
+
*/
|
|
102
|
+
function getConfidenceScore(type, context = {}) {
|
|
103
|
+
const baseConfidence = CONFIDENCE_LEVELS[type] || 50;
|
|
104
|
+
|
|
105
|
+
// Adjust based on context
|
|
106
|
+
let adjusted = baseConfidence;
|
|
107
|
+
|
|
108
|
+
// Lower confidence if in test/fixture file
|
|
109
|
+
if (context.isTestFile) {
|
|
110
|
+
adjusted = Math.max(10, adjusted - 30);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Higher confidence if in source file
|
|
114
|
+
if (context.isSourceFile) {
|
|
115
|
+
adjusted = Math.min(100, adjusted + 10);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Lower confidence for commented code
|
|
119
|
+
if (context.inComment) {
|
|
120
|
+
adjusted = Math.max(10, adjusted - 20);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return Math.round(adjusted);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Calculate overall verdict from findings
|
|
128
|
+
* Uses hardened blocker logic - only high-confidence findings block
|
|
129
|
+
* SECURITY: High-confidence critical/high findings always block, even if blocksShip is explicitly false
|
|
130
|
+
*/
|
|
131
|
+
function calculateVerdict(findings) {
|
|
132
|
+
if (!findings || findings.length === 0) {
|
|
133
|
+
return 'pass';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Apply hardened blocker logic - high-confidence critical/high findings always block
|
|
137
|
+
const blockers = findings.filter(f => {
|
|
138
|
+
// If explicitly marked as blocker, respect it
|
|
139
|
+
if (f.blocksShip === true) return true;
|
|
140
|
+
|
|
141
|
+
// Apply hardened thresholds: critical > 80%, high > 90%
|
|
142
|
+
if (f.severity === 'critical' && f.confidence > 80) return true;
|
|
143
|
+
if (f.severity === 'high' && f.confidence > 90) return true;
|
|
144
|
+
|
|
145
|
+
// Secrets always block
|
|
146
|
+
if (f.type?.includes('secret') || f.type?.includes('key')) return true;
|
|
147
|
+
|
|
148
|
+
return false;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Any blockers = fail
|
|
152
|
+
if (blockers.length > 0) {
|
|
153
|
+
return 'fail';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Any critical, high, or medium findings = warn (but don't block if confidence too low)
|
|
157
|
+
const criticals = findings.filter(f => f.severity === 'critical');
|
|
158
|
+
const highs = findings.filter(f => f.severity === 'high');
|
|
159
|
+
const mediums = findings.filter(f => f.severity === 'medium');
|
|
160
|
+
if (criticals.length > 0 || highs.length > 0 || mediums.length > 0) {
|
|
161
|
+
return 'warn';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Only low/info findings = pass
|
|
165
|
+
return 'pass';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Calculate health score from findings
|
|
170
|
+
*/
|
|
171
|
+
function calculateScore(findings) {
|
|
172
|
+
let score = 100;
|
|
173
|
+
|
|
174
|
+
for (const finding of findings) {
|
|
175
|
+
const weight = {
|
|
176
|
+
critical: 25,
|
|
177
|
+
high: 15,
|
|
178
|
+
medium: 5,
|
|
179
|
+
low: 2,
|
|
180
|
+
info: 0,
|
|
181
|
+
}[finding.severity] || 0;
|
|
182
|
+
|
|
183
|
+
// Weight by confidence
|
|
184
|
+
const adjustedWeight = weight * (finding.confidence / 100);
|
|
185
|
+
score -= adjustedWeight;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return Math.max(0, Math.round(score));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Deduplicate findings by unique key
|
|
193
|
+
*/
|
|
194
|
+
function dedupeFindings(findings) {
|
|
195
|
+
const seen = new Map();
|
|
196
|
+
|
|
197
|
+
for (const finding of findings) {
|
|
198
|
+
// Create unique key based on type, file, line, and message
|
|
199
|
+
const key = `${finding.type}:${finding.file || ''}:${finding.line || ''}:${finding.message?.slice(0, 50) || ''}`;
|
|
200
|
+
|
|
201
|
+
if (!seen.has(key)) {
|
|
202
|
+
seen.set(key, finding);
|
|
203
|
+
} else {
|
|
204
|
+
// Keep the higher severity/confidence one
|
|
205
|
+
const existing = seen.get(key);
|
|
206
|
+
const severityOrder = { critical: 4, high: 3, medium: 2, low: 1, info: 0 };
|
|
207
|
+
|
|
208
|
+
if (severityOrder[finding.severity] > severityOrder[existing.severity] ||
|
|
209
|
+
(severityOrder[finding.severity] === severityOrder[existing.severity] &&
|
|
210
|
+
finding.confidence > existing.confidence)) {
|
|
211
|
+
seen.set(key, finding);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return Array.from(seen.values());
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Sort findings by shipping impact (blockers first, then by severity/confidence)
|
|
221
|
+
* This ensures users see the most critical issues that block shipping first.
|
|
222
|
+
*/
|
|
223
|
+
function sortFindings(findings) {
|
|
224
|
+
const severityOrder = { critical: 4, high: 3, medium: 2, low: 1, info: 0 };
|
|
225
|
+
|
|
226
|
+
return [...findings].sort((a, b) => {
|
|
227
|
+
// 1. Blockers first (most important - these block shipping)
|
|
228
|
+
const aIsBlocker = a.blocksShip === true;
|
|
229
|
+
const bIsBlocker = b.blocksShip === true;
|
|
230
|
+
if (aIsBlocker !== bIsBlocker) {
|
|
231
|
+
return aIsBlocker ? -1 : 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 2. Then by severity (critical > high > medium > low > info)
|
|
235
|
+
if (severityOrder[a.severity] !== severityOrder[b.severity]) {
|
|
236
|
+
return severityOrder[b.severity] - severityOrder[a.severity];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// 3. Then by confidence (higher confidence = more important)
|
|
240
|
+
return b.confidence - a.confidence;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create a valid scan result object
|
|
246
|
+
*/
|
|
247
|
+
function createScanResult(options) {
|
|
248
|
+
const {
|
|
249
|
+
findings = [],
|
|
250
|
+
projectPath = process.cwd(),
|
|
251
|
+
scanId = `scan_${Date.now()}`,
|
|
252
|
+
startTime = Date.now(),
|
|
253
|
+
error = null,
|
|
254
|
+
} = options;
|
|
255
|
+
|
|
256
|
+
// Process findings
|
|
257
|
+
const processedFindings = findings.map(f => ({
|
|
258
|
+
...f,
|
|
259
|
+
confidence: f.confidence || getConfidenceScore(f.type),
|
|
260
|
+
blocksShip: f.blocksShip ?? isBlocker(f),
|
|
261
|
+
}));
|
|
262
|
+
|
|
263
|
+
const dedupedFindings = dedupeFindings(processedFindings);
|
|
264
|
+
const sortedFindings = sortFindings(dedupedFindings);
|
|
265
|
+
|
|
266
|
+
const summary = {
|
|
267
|
+
total: sortedFindings.length,
|
|
268
|
+
critical: sortedFindings.filter(f => f.severity === 'critical').length,
|
|
269
|
+
high: sortedFindings.filter(f => f.severity === 'high').length,
|
|
270
|
+
medium: sortedFindings.filter(f => f.severity === 'medium').length,
|
|
271
|
+
low: sortedFindings.filter(f => f.severity === 'low').length,
|
|
272
|
+
blockers: sortedFindings.filter(f => f.blocksShip).length,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
schemaVersion: SCHEMA_VERSION,
|
|
277
|
+
success: !error,
|
|
278
|
+
verdict: error ? 'fail' : calculateVerdict(sortedFindings),
|
|
279
|
+
score: calculateScore(sortedFindings),
|
|
280
|
+
summary,
|
|
281
|
+
findings: sortedFindings,
|
|
282
|
+
metadata: {
|
|
283
|
+
scanId,
|
|
284
|
+
timestamp: new Date().toISOString(),
|
|
285
|
+
duration: Date.now() - startTime,
|
|
286
|
+
projectPath,
|
|
287
|
+
version: require('../../../package.json').version,
|
|
288
|
+
},
|
|
289
|
+
...(error ? { error: { message: error.message, code: error.code || 'SCAN_ERROR' } } : {}),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Validate a scan result against the schema
|
|
295
|
+
*/
|
|
296
|
+
function validateScanResult(result) {
|
|
297
|
+
const errors = [];
|
|
298
|
+
|
|
299
|
+
if (!result.schemaVersion) {
|
|
300
|
+
errors.push("Missing schemaVersion");
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (typeof result.success !== 'boolean') {
|
|
304
|
+
errors.push("Invalid or missing success field");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (!['pass', 'fail', 'warn'].includes(result.verdict)) {
|
|
308
|
+
errors.push(`Invalid verdict: ${result.verdict}`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (typeof result.score !== 'number' || result.score < 0 || result.score > 100) {
|
|
312
|
+
errors.push(`Invalid score: ${result.score}`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!result.summary || typeof result.summary.total !== 'number') {
|
|
316
|
+
errors.push("Invalid or missing summary");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (!Array.isArray(result.findings)) {
|
|
320
|
+
errors.push("Findings must be an array");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!result.metadata?.scanId || !result.metadata?.timestamp) {
|
|
324
|
+
errors.push("Missing required metadata fields");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
valid: errors.length === 0,
|
|
329
|
+
errors,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
module.exports = {
|
|
334
|
+
SCHEMA_VERSION,
|
|
335
|
+
CONFIDENCE_LEVELS,
|
|
336
|
+
isBlocker,
|
|
337
|
+
getConfidenceScore,
|
|
338
|
+
calculateVerdict,
|
|
339
|
+
calculateScore,
|
|
340
|
+
dedupeFindings,
|
|
341
|
+
sortFindings,
|
|
342
|
+
createScanResult,
|
|
343
|
+
validateScanResult,
|
|
344
|
+
};
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Score History Tracking
|
|
3
|
+
*
|
|
4
|
+
* Tracks Vibe Score history over time for trend analysis,
|
|
5
|
+
* streaks, and gamification.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get history file path for a project
|
|
13
|
+
*/
|
|
14
|
+
function getHistoryPath(projectPath) {
|
|
15
|
+
return path.join(projectPath, ".vibecheck", "history.json");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Load score history
|
|
20
|
+
*/
|
|
21
|
+
function loadHistory(projectPath) {
|
|
22
|
+
const historyPath = getHistoryPath(projectPath);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
if (fs.existsSync(historyPath)) {
|
|
26
|
+
return JSON.parse(fs.readFileSync(historyPath, "utf8"));
|
|
27
|
+
}
|
|
28
|
+
} catch {}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
projectId: path.basename(projectPath),
|
|
32
|
+
checks: [],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Save score history
|
|
38
|
+
*/
|
|
39
|
+
function saveHistory(projectPath, history) {
|
|
40
|
+
const historyPath = getHistoryPath(projectPath);
|
|
41
|
+
const dir = path.dirname(historyPath);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
if (!fs.existsSync(dir)) {
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
fs.writeFileSync(historyPath, JSON.stringify(history, null, 2));
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.warn(`Warning: Could not save history: ${err.message}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Record a new check
|
|
55
|
+
*/
|
|
56
|
+
function recordCheck(projectPath, checkData) {
|
|
57
|
+
const history = loadHistory(projectPath);
|
|
58
|
+
|
|
59
|
+
const check = {
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
score: checkData.score || 0,
|
|
62
|
+
verdict: checkData.verdict || "BLOCK",
|
|
63
|
+
commitSha: checkData.commitSha || null,
|
|
64
|
+
commitMessage: checkData.commitMessage || null,
|
|
65
|
+
branch: checkData.branch || null,
|
|
66
|
+
categoryScores: checkData.categoryScores || {},
|
|
67
|
+
findingCounts: checkData.findingCounts || {
|
|
68
|
+
critical: 0,
|
|
69
|
+
high: 0,
|
|
70
|
+
medium: 0,
|
|
71
|
+
low: 0,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
history.checks.unshift(check);
|
|
76
|
+
|
|
77
|
+
// Keep only last 100 checks
|
|
78
|
+
if (history.checks.length > 100) {
|
|
79
|
+
history.checks = history.checks.slice(0, 100);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
saveHistory(projectPath, history);
|
|
83
|
+
|
|
84
|
+
return check;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Calculate trend from recent checks
|
|
89
|
+
*/
|
|
90
|
+
function calculateTrend(projectPath, limit = 10) {
|
|
91
|
+
const history = loadHistory(projectPath);
|
|
92
|
+
const recentChecks = history.checks.slice(0, limit);
|
|
93
|
+
|
|
94
|
+
if (recentChecks.length < 2) {
|
|
95
|
+
return {
|
|
96
|
+
direction: "stable",
|
|
97
|
+
delta: 0,
|
|
98
|
+
previousScore: null,
|
|
99
|
+
streak: null,
|
|
100
|
+
sparkline: [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const latest = recentChecks[0].score;
|
|
105
|
+
const previous = recentChecks[1].score;
|
|
106
|
+
const delta = latest - previous;
|
|
107
|
+
|
|
108
|
+
// Calculate streak
|
|
109
|
+
let streak = { count: 1, type: recentChecks[0].verdict };
|
|
110
|
+
for (let i = 1; i < recentChecks.length; i++) {
|
|
111
|
+
if (recentChecks[i].verdict === streak.type) {
|
|
112
|
+
streak.count++;
|
|
113
|
+
} else {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Generate sparkline data (last 10 scores)
|
|
119
|
+
const sparkline = recentChecks.slice(0, 10).map(c => c.score).reverse();
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
direction: delta > 0 ? "up" : delta < 0 ? "down" : "stable",
|
|
123
|
+
delta: Math.abs(delta),
|
|
124
|
+
previousScore: previous,
|
|
125
|
+
streak: streak.count >= 3 ? streak : null,
|
|
126
|
+
sparkline,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get milestones achieved
|
|
132
|
+
*/
|
|
133
|
+
function getMilestones(projectPath) {
|
|
134
|
+
const history = loadHistory(projectPath);
|
|
135
|
+
const milestones = [];
|
|
136
|
+
|
|
137
|
+
if (history.checks.length === 0) return milestones;
|
|
138
|
+
|
|
139
|
+
const latest = history.checks[0];
|
|
140
|
+
|
|
141
|
+
// First check
|
|
142
|
+
if (history.checks.length === 1) {
|
|
143
|
+
milestones.push("First check completed!");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// First 90+ score
|
|
147
|
+
const first90 = history.checks.find(c => c.score >= 90);
|
|
148
|
+
if (first90 && first90 === latest) {
|
|
149
|
+
milestones.push("First 90+ score!");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Perfect 100
|
|
153
|
+
if (latest.score === 100) {
|
|
154
|
+
milestones.push("Perfect 100! 🏆");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Streak milestones
|
|
158
|
+
const trend = calculateTrend(projectPath);
|
|
159
|
+
if (trend.streak) {
|
|
160
|
+
if (trend.streak.count >= 10 && trend.streak.type === "SHIP") {
|
|
161
|
+
milestones.push("10 SHIP streak! 🔥🔥🔥");
|
|
162
|
+
} else if (trend.streak.count >= 5 && trend.streak.type === "SHIP") {
|
|
163
|
+
milestones.push("5 SHIP streak! 🔥");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Improvement milestones
|
|
168
|
+
if (trend.direction === "up" && trend.delta >= 10) {
|
|
169
|
+
milestones.push(`+${trend.delta} points improvement!`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return milestones;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Format history for CLI display
|
|
177
|
+
*/
|
|
178
|
+
function formatHistoryDisplay(projectPath, limit = 10) {
|
|
179
|
+
const c = {
|
|
180
|
+
reset: "\x1b[0m",
|
|
181
|
+
bold: "\x1b[1m",
|
|
182
|
+
dim: "\x1b[2m",
|
|
183
|
+
red: "\x1b[31m",
|
|
184
|
+
green: "\x1b[32m",
|
|
185
|
+
yellow: "\x1b[33m",
|
|
186
|
+
cyan: "\x1b[36m",
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const history = loadHistory(projectPath);
|
|
190
|
+
const trend = calculateTrend(projectPath);
|
|
191
|
+
const milestones = getMilestones(projectPath);
|
|
192
|
+
|
|
193
|
+
if (history.checks.length === 0) {
|
|
194
|
+
return `${c.dim}No history yet. Run \`vibecheck ship\` to start tracking.${c.reset}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let output = `\n${c.bold}📊 Score History${c.reset}\n\n`;
|
|
198
|
+
|
|
199
|
+
// Trend line
|
|
200
|
+
if (trend.direction !== "stable") {
|
|
201
|
+
const trendIcon = trend.direction === "up" ? "↑" : "↓";
|
|
202
|
+
const trendColor = trend.direction === "up" ? c.green : c.red;
|
|
203
|
+
output += ` ${trendColor}${trendIcon} ${trend.delta} since last check${c.reset}\n`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Streak
|
|
207
|
+
if (trend.streak) {
|
|
208
|
+
output += ` ${c.yellow}🔥 ${trend.streak.count} consecutive ${trend.streak.type} verdicts${c.reset}\n`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Milestones
|
|
212
|
+
for (const milestone of milestones) {
|
|
213
|
+
output += ` ${c.cyan}🏆 ${milestone}${c.reset}\n`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
output += `\n ${c.dim}Recent checks:${c.reset}\n`;
|
|
217
|
+
|
|
218
|
+
// Recent checks
|
|
219
|
+
const recentChecks = history.checks.slice(0, limit);
|
|
220
|
+
for (const check of recentChecks) {
|
|
221
|
+
const date = new Date(check.timestamp);
|
|
222
|
+
const timeAgo = formatTimeAgo(date);
|
|
223
|
+
const verdictColor = check.verdict === "SHIP" ? c.green :
|
|
224
|
+
check.verdict === "WARN" ? c.yellow : c.red;
|
|
225
|
+
const verdictIcon = check.verdict === "SHIP" ? "✅" :
|
|
226
|
+
check.verdict === "WARN" ? "⚠️" : "🚫";
|
|
227
|
+
|
|
228
|
+
output += ` ${c.dim}${timeAgo.padEnd(12)}${c.reset} ${verdictColor}${check.score.toString().padStart(3)}${c.reset} ${verdictIcon} ${verdictColor}${check.verdict}${c.reset}`;
|
|
229
|
+
if (check.commitSha) {
|
|
230
|
+
output += ` ${c.dim}${check.commitSha.substring(0, 7)}${c.reset}`;
|
|
231
|
+
}
|
|
232
|
+
output += "\n";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Sparkline
|
|
236
|
+
if (trend.sparkline.length > 2) {
|
|
237
|
+
output += `\n ${c.dim}Trend:${c.reset} ${formatSparkline(trend.sparkline)}\n`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return output;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Format relative time
|
|
245
|
+
*/
|
|
246
|
+
function formatTimeAgo(date) {
|
|
247
|
+
const now = new Date();
|
|
248
|
+
const diffMs = now - date;
|
|
249
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
250
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
251
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
252
|
+
|
|
253
|
+
if (diffMins < 1) return "just now";
|
|
254
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
255
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
256
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
257
|
+
return date.toLocaleDateString();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Format sparkline from scores
|
|
262
|
+
*/
|
|
263
|
+
function formatSparkline(scores) {
|
|
264
|
+
const chars = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
|
|
265
|
+
const min = Math.min(...scores);
|
|
266
|
+
const max = Math.max(...scores);
|
|
267
|
+
const range = max - min || 1;
|
|
268
|
+
|
|
269
|
+
return scores.map(s => {
|
|
270
|
+
const idx = Math.floor(((s - min) / range) * (chars.length - 1));
|
|
271
|
+
return chars[idx];
|
|
272
|
+
}).join("");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = {
|
|
276
|
+
loadHistory,
|
|
277
|
+
saveHistory,
|
|
278
|
+
recordCheck,
|
|
279
|
+
calculateTrend,
|
|
280
|
+
getMilestones,
|
|
281
|
+
formatHistoryDisplay,
|
|
282
|
+
};
|