vibecheck-ai 2.0.1 → 5.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/bin/.generated +25 -0
- package/bin/_deprecations.js +463 -0
- package/bin/_router.js +46 -0
- package/bin/cli-hygiene.js +241 -0
- package/bin/dev/run-v2-torture.js +30 -0
- package/bin/registry.js +656 -0
- package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
- package/bin/runners/ENHANCEMENT_GUIDE.md +121 -0
- package/bin/runners/REPORT_AUDIT.md +64 -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 +513 -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-enhanced.js +2525 -0
- package/bin/runners/context/generators/cursor.js +514 -0
- package/bin/runners/context/generators/mcp.js +169 -0
- package/bin/runners/context/generators/windsurf.js +180 -0
- package/bin/runners/context/git-context.js +304 -0
- package/bin/runners/context/index.js +1110 -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 +1264 -0
- package/bin/runners/context/security-scanner.js +541 -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 +336 -0
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -0
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
- package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
- package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
- package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
- package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
- package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
- package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
- package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
- package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
- package/bin/runners/lib/agent-firewall/index.js +200 -0
- package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
- package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
- package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
- package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
- package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
- package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
- package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
- package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
- package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
- package/bin/runners/lib/agent-firewall/interceptor/base.js +308 -0
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
- package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +79 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +227 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +191 -0
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
- package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
- package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
- package/bin/runners/lib/agent-firewall/session/index.js +26 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
- package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
- package/bin/runners/lib/ai-bridge.js +416 -0
- package/bin/runners/lib/analysis-core.js +309 -0
- package/bin/runners/lib/analyzers.js +2500 -0
- package/bin/runners/lib/api-client.js +269 -0
- package/bin/runners/lib/approve-output.js +235 -0
- package/bin/runners/lib/artifact-envelope.js +540 -0
- package/bin/runners/lib/assets/vibecheck-logo.png +0 -0
- package/bin/runners/lib/audit-bridge.js +391 -0
- package/bin/runners/lib/auth-shared.js +977 -0
- package/bin/runners/lib/auth-truth.js +193 -0
- package/bin/runners/lib/auth.js +215 -0
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/backup.js +62 -0
- package/bin/runners/lib/billing.js +107 -0
- package/bin/runners/lib/checkpoint.js +941 -0
- package/bin/runners/lib/claims.js +118 -0
- package/bin/runners/lib/classify-output.js +204 -0
- package/bin/runners/lib/cleanup/engine.js +571 -0
- package/bin/runners/lib/cleanup/index.js +53 -0
- package/bin/runners/lib/cleanup/output.js +375 -0
- package/bin/runners/lib/cleanup/rules.js +1060 -0
- package/bin/runners/lib/cli-output.js +400 -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 +202 -0
- package/bin/runners/lib/contracts/env-contract.js +181 -0
- package/bin/runners/lib/contracts/external-contract.js +206 -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 +199 -0
- package/bin/runners/lib/contracts.js +804 -0
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/detect.js +89 -0
- package/bin/runners/lib/detectors-v2.js +622 -0
- package/bin/runners/lib/doctor/autofix.js +254 -0
- package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
- package/bin/runners/lib/doctor/failure-signatures.js +526 -0
- package/bin/runners/lib/doctor/fix-script.js +336 -0
- package/bin/runners/lib/doctor/index.js +37 -0
- package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
- package/bin/runners/lib/doctor/modules/index.js +105 -0
- package/bin/runners/lib/doctor/modules/network.js +250 -0
- package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
- package/bin/runners/lib/doctor/modules/project.js +312 -0
- package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
- package/bin/runners/lib/doctor/modules/runtime.js +224 -0
- package/bin/runners/lib/doctor/modules/security.js +350 -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/safe-repair.js +384 -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-output.js +226 -0
- package/bin/runners/lib/doctor-v2.js +608 -0
- package/bin/runners/lib/drift.js +425 -0
- package/bin/runners/lib/enforcement.js +72 -0
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +190 -0
- package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
- package/bin/runners/lib/engines/ast-cache.js +99 -0
- package/bin/runners/lib/engines/attack-detector.js +1192 -0
- package/bin/runners/lib/engines/code-quality-engine.js +255 -0
- package/bin/runners/lib/engines/console-logs-engine.js +115 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
- package/bin/runners/lib/engines/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
- package/bin/runners/lib/engines/file-filter.js +131 -0
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
- package/bin/runners/lib/engines/mock-data-engine.js +272 -0
- package/bin/runners/lib/engines/parallel-processor.js +71 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
- package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
- package/bin/runners/lib/engines/type-aware-engine.js +152 -0
- package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
- package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
- package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -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 +265 -0
- package/bin/runners/lib/entitlements.generated.js +0 -0
- package/bin/runners/lib/entitlements.js +340 -0
- package/bin/runners/lib/env-resolver.js +417 -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 +368 -0
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +684 -0
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/extractors/client-calls.js +990 -0
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -0
- package/bin/runners/lib/extractors/fastify-routes.js +426 -0
- package/bin/runners/lib/extractors/index.js +363 -0
- package/bin/runners/lib/extractors/next-routes.js +524 -0
- package/bin/runners/lib/extractors/proof-graph.js +431 -0
- package/bin/runners/lib/extractors/route-matcher.js +451 -0
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -0
- package/bin/runners/lib/extractors/ui-bindings.js +547 -0
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/findings-schema.js +281 -0
- package/bin/runners/lib/fingerprint.js +377 -0
- package/bin/runners/lib/firewall-prompt.js +50 -0
- package/bin/runners/lib/fix-output.js +228 -0
- package/bin/runners/lib/global-flags.js +250 -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/help-formatter.js +413 -0
- package/bin/runners/lib/html-proof-report.js +913 -0
- package/bin/runners/lib/html-report.js +650 -0
- package/bin/runners/lib/init-wizard.js +601 -0
- package/bin/runners/lib/interactive-menu.js +1496 -0
- package/bin/runners/lib/json-output.js +76 -0
- package/bin/runners/lib/llm.js +75 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/meter.js +61 -0
- package/bin/runners/lib/missions/briefing.js +427 -0
- package/bin/runners/lib/missions/checkpoint.js +753 -0
- package/bin/runners/lib/missions/evidence.js +126 -0
- package/bin/runners/lib/missions/hardening.js +851 -0
- package/bin/runners/lib/missions/plan.js +648 -0
- package/bin/runners/lib/missions/safety-gates.js +645 -0
- package/bin/runners/lib/missions/schema.js +478 -0
- package/bin/runners/lib/missions/templates.js +317 -0
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/packs/bundle.js +675 -0
- package/bin/runners/lib/packs/evidence-pack.js +671 -0
- package/bin/runners/lib/packs/pack-factory.js +837 -0
- package/bin/runners/lib/packs/permissions-pack.js +686 -0
- package/bin/runners/lib/packs/proof-graph-pack.js +779 -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/policy.js +295 -0
- package/bin/runners/lib/polish/accessibility.js +62 -0
- package/bin/runners/lib/polish/analyzer.js +93 -0
- package/bin/runners/lib/polish/backend.js +87 -0
- package/bin/runners/lib/polish/configuration.js +83 -0
- package/bin/runners/lib/polish/documentation.js +83 -0
- package/bin/runners/lib/polish/frontend.js +817 -0
- package/bin/runners/lib/polish/index.js +27 -0
- package/bin/runners/lib/polish/infrastructure.js +80 -0
- package/bin/runners/lib/polish/internationalization.js +85 -0
- package/bin/runners/lib/polish/libraries.js +180 -0
- package/bin/runners/lib/polish/observability.js +75 -0
- package/bin/runners/lib/polish/performance.js +64 -0
- package/bin/runners/lib/polish/privacy.js +110 -0
- package/bin/runners/lib/polish/resilience.js +92 -0
- package/bin/runners/lib/polish/security.js +78 -0
- package/bin/runners/lib/polish/seo.js +71 -0
- package/bin/runners/lib/polish/styles.js +62 -0
- package/bin/runners/lib/polish/utils.js +104 -0
- package/bin/runners/lib/preflight.js +142 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/prove-output.js +220 -0
- package/bin/runners/lib/reality/correlation-detectors.js +359 -0
- package/bin/runners/lib/reality/index.js +318 -0
- package/bin/runners/lib/reality/request-hashing.js +416 -0
- package/bin/runners/lib/reality/request-mapper.js +453 -0
- package/bin/runners/lib/reality/safety-rails.js +463 -0
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -0
- package/bin/runners/lib/reality/toast-detector.js +393 -0
- package/bin/runners/lib/reality-findings.js +84 -0
- package/bin/runners/lib/reality-output.js +231 -0
- package/bin/runners/lib/receipts.js +179 -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 +626 -0
- package/bin/runners/lib/report-html.js +1233 -0
- package/bin/runners/lib/report-output.js +366 -0
- package/bin/runners/lib/report-templates.js +967 -0
- package/bin/runners/lib/report.js +135 -0
- package/bin/runners/lib/route-detection.js +1209 -0
- package/bin/runners/lib/route-truth.js +1322 -0
- package/bin/runners/lib/safelist/index.js +96 -0
- package/bin/runners/lib/safelist/integration.js +334 -0
- package/bin/runners/lib/safelist/matcher.js +696 -0
- package/bin/runners/lib/safelist/schema.js +948 -0
- package/bin/runners/lib/safelist/store.js +438 -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/scan-output.js +631 -0
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schema-validator.js +350 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/contracts.schema.json +160 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/finding.schema.json +100 -0
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -0
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -0
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -0
- package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -0
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -0
- package/bin/runners/lib/schemas/validator.js +465 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -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/ship-gate.js +832 -0
- package/bin/runners/lib/ship-manifest.js +1153 -0
- package/bin/runners/lib/ship-output-enterprise.js +239 -0
- package/bin/runners/lib/ship-output.js +1128 -0
- package/bin/runners/lib/snippets.js +67 -0
- package/bin/runners/lib/status-output.js +340 -0
- package/bin/runners/lib/terminal-ui.js +356 -0
- package/bin/runners/lib/truth.js +1691 -0
- package/bin/runners/lib/ui.js +562 -0
- package/bin/runners/lib/unified-cli-output.js +947 -0
- package/bin/runners/lib/unified-output.js +197 -0
- package/bin/runners/lib/upsell.js +410 -0
- package/bin/runners/lib/usage.js +153 -0
- package/bin/runners/lib/validate-patch.js +156 -0
- package/bin/runners/lib/verdict-engine.js +628 -0
- package/bin/runners/lib/verification.js +345 -0
- package/bin/runners/lib/why-tree.js +650 -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 +229 -0
- package/bin/runners/runAgent.d.ts +5 -0
- package/bin/runners/runAgent.js +161 -0
- package/bin/runners/runAllowlist.js +418 -0
- package/bin/runners/runApprove.js +320 -0
- package/bin/runners/runAudit.js +692 -0
- package/bin/runners/runAuth.js +731 -0
- package/bin/runners/runCI.js +353 -0
- package/bin/runners/runCheckpoint.js +530 -0
- package/bin/runners/runClassify.js +928 -0
- package/bin/runners/runCleanup.js +343 -0
- package/bin/runners/runContext.d.ts +4 -0
- package/bin/runners/runContext.js +175 -0
- package/bin/runners/runDoctor.js +877 -0
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.d.ts +5 -0
- package/bin/runners/runFirewall.js +134 -0
- package/bin/runners/runFirewallHook.d.ts +5 -0
- package/bin/runners/runFirewallHook.js +56 -0
- package/bin/runners/runFix.js +1355 -0
- package/bin/runners/runForge.js +451 -0
- package/bin/runners/runGuard.js +262 -0
- package/bin/runners/runInit.js +1927 -0
- package/bin/runners/runIntent.js +906 -0
- package/bin/runners/runKickoff.js +878 -0
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runLaunch.js +2000 -0
- package/bin/runners/runLink.js +785 -0
- package/bin/runners/runMcp.js +1875 -0
- package/bin/runners/runPacks.js +2089 -0
- package/bin/runners/runPolish.d.ts +4 -0
- package/bin/runners/runPolish.js +390 -0
- package/bin/runners/runPromptFirewall.js +211 -0
- package/bin/runners/runProve.js +1411 -0
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +2260 -0
- package/bin/runners/runReport.js +726 -0
- package/bin/runners/runRuntime.js +110 -0
- package/bin/runners/runSafelist.js +1190 -0
- package/bin/runners/runScan.js +688 -0
- package/bin/runners/runShield.js +1282 -0
- package/bin/runners/runShip.js +1660 -0
- package/bin/runners/runTruth.d.ts +5 -0
- package/bin/runners/runTruth.js +101 -0
- package/bin/runners/runValidate.js +179 -0
- package/bin/runners/runWatch.js +478 -0
- package/bin/runners/utils.js +360 -0
- package/bin/scan.js +617 -0
- package/bin/vibecheck.js +1617 -0
- package/dist/guardrail/index.d.ts +2405 -0
- package/dist/guardrail/index.js +9747 -0
- package/dist/guardrail/index.js.map +1 -0
- package/dist/scanner/index.d.ts +282 -0
- package/dist/scanner/index.js +3395 -0
- package/dist/scanner/index.js.map +1 -0
- package/package.json +123 -104
- package/README.md +0 -491
- package/dist/index.js +0 -99711
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,1927 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibecheck init - Enterprise Project Setup
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* ENTERPRISE EDITION - World-Class Terminal Experience
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
*
|
|
8
|
+
* Configure your project for production-grade verification.
|
|
9
|
+
* Interactive wizard or quick setup for any project type.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require("fs");
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
|
|
15
|
+
const { EXIT } = require("./lib/exit-codes");
|
|
16
|
+
|
|
17
|
+
// Use enhanced wizard if available
|
|
18
|
+
let InitWizard;
|
|
19
|
+
try {
|
|
20
|
+
InitWizard = require("./lib/init-wizard").InitWizard;
|
|
21
|
+
} catch {
|
|
22
|
+
InitWizard = null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Enterprise init
|
|
26
|
+
let EnterpriseInit;
|
|
27
|
+
try {
|
|
28
|
+
EnterpriseInit = require("./lib/enterprise-init").EnterpriseInit;
|
|
29
|
+
} catch {
|
|
30
|
+
EnterpriseInit = null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
34
|
+
// ADVANCED TERMINAL - ANSI CODES & UTILITIES
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
36
|
+
|
|
37
|
+
const c = {
|
|
38
|
+
reset: '\x1b[0m',
|
|
39
|
+
bold: '\x1b[1m',
|
|
40
|
+
dim: '\x1b[2m',
|
|
41
|
+
italic: '\x1b[3m',
|
|
42
|
+
underline: '\x1b[4m',
|
|
43
|
+
blink: '\x1b[5m',
|
|
44
|
+
inverse: '\x1b[7m',
|
|
45
|
+
hidden: '\x1b[8m',
|
|
46
|
+
strike: '\x1b[9m',
|
|
47
|
+
// Colors
|
|
48
|
+
black: '\x1b[30m',
|
|
49
|
+
red: '\x1b[31m',
|
|
50
|
+
green: '\x1b[32m',
|
|
51
|
+
yellow: '\x1b[33m',
|
|
52
|
+
blue: '\x1b[34m',
|
|
53
|
+
magenta: '\x1b[35m',
|
|
54
|
+
cyan: '\x1b[36m',
|
|
55
|
+
white: '\x1b[37m',
|
|
56
|
+
// Bright colors
|
|
57
|
+
gray: '\x1b[90m',
|
|
58
|
+
brightRed: '\x1b[91m',
|
|
59
|
+
brightGreen: '\x1b[92m',
|
|
60
|
+
brightYellow: '\x1b[93m',
|
|
61
|
+
brightBlue: '\x1b[94m',
|
|
62
|
+
brightMagenta: '\x1b[95m',
|
|
63
|
+
brightCyan: '\x1b[96m',
|
|
64
|
+
brightWhite: '\x1b[97m',
|
|
65
|
+
// Background
|
|
66
|
+
bgBlack: '\x1b[40m',
|
|
67
|
+
bgRed: '\x1b[41m',
|
|
68
|
+
bgGreen: '\x1b[42m',
|
|
69
|
+
bgYellow: '\x1b[43m',
|
|
70
|
+
bgBlue: '\x1b[44m',
|
|
71
|
+
bgMagenta: '\x1b[45m',
|
|
72
|
+
bgCyan: '\x1b[46m',
|
|
73
|
+
bgWhite: '\x1b[47m',
|
|
74
|
+
// Cursor control
|
|
75
|
+
cursorUp: (n = 1) => `\x1b[${n}A`,
|
|
76
|
+
cursorDown: (n = 1) => `\x1b[${n}B`,
|
|
77
|
+
cursorRight: (n = 1) => `\x1b[${n}C`,
|
|
78
|
+
cursorLeft: (n = 1) => `\x1b[${n}D`,
|
|
79
|
+
clearLine: '\x1b[2K',
|
|
80
|
+
clearScreen: '\x1b[2J',
|
|
81
|
+
saveCursor: '\x1b[s',
|
|
82
|
+
restoreCursor: '\x1b[u',
|
|
83
|
+
hideCursor: '\x1b[?25l',
|
|
84
|
+
showCursor: '\x1b[?25h',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// True color support
|
|
88
|
+
const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
|
|
89
|
+
const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
|
|
90
|
+
|
|
91
|
+
// Premium color palette (gold/amber theme for "init/setup")
|
|
92
|
+
const colors = {
|
|
93
|
+
// Gradient for banner
|
|
94
|
+
gradient1: rgb(255, 215, 100), // Gold
|
|
95
|
+
gradient2: rgb(255, 200, 80), // Light gold
|
|
96
|
+
gradient3: rgb(255, 180, 60), // Amber
|
|
97
|
+
gradient4: rgb(255, 160, 40), // Deep amber
|
|
98
|
+
gradient5: rgb(255, 140, 20), // Orange-amber
|
|
99
|
+
gradient6: rgb(255, 120, 0), // Deep orange
|
|
100
|
+
|
|
101
|
+
// Category colors
|
|
102
|
+
framework: rgb(100, 200, 255), // Blue
|
|
103
|
+
database: rgb(200, 150, 255), // Purple
|
|
104
|
+
auth: rgb(100, 255, 180), // Green
|
|
105
|
+
payment: rgb(255, 200, 100), // Gold
|
|
106
|
+
ci: rgb(255, 150, 100), // Coral
|
|
107
|
+
deploy: rgb(150, 200, 255), // Light blue
|
|
108
|
+
testing: rgb(200, 255, 150), // Lime
|
|
109
|
+
|
|
110
|
+
// Status colors
|
|
111
|
+
success: rgb(0, 255, 150),
|
|
112
|
+
warning: rgb(255, 200, 0),
|
|
113
|
+
error: rgb(255, 80, 80),
|
|
114
|
+
info: rgb(100, 200, 255),
|
|
115
|
+
|
|
116
|
+
// UI colors
|
|
117
|
+
accent: rgb(255, 200, 100),
|
|
118
|
+
muted: rgb(140, 130, 100),
|
|
119
|
+
subtle: rgb(100, 90, 70),
|
|
120
|
+
highlight: rgb(255, 255, 255),
|
|
121
|
+
|
|
122
|
+
// Enterprise
|
|
123
|
+
enterprise: rgb(200, 150, 255),
|
|
124
|
+
compliance: rgb(100, 200, 150),
|
|
125
|
+
team: rgb(150, 180, 255),
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
129
|
+
// PREMIUM BANNER
|
|
130
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
131
|
+
|
|
132
|
+
const INIT_BANNER = `
|
|
133
|
+
${rgb(255, 220, 120)} ██╗███╗ ██╗██╗████████╗${c.reset}
|
|
134
|
+
${rgb(255, 200, 100)} ██║████╗ ██║██║╚══██╔══╝${c.reset}
|
|
135
|
+
${rgb(255, 180, 80)} ██║██╔██╗ ██║██║ ██║ ${c.reset}
|
|
136
|
+
${rgb(255, 160, 60)} ██║██║╚██╗██║██║ ██║ ${c.reset}
|
|
137
|
+
${rgb(255, 140, 40)} ██║██║ ╚████║██║ ██║ ${c.reset}
|
|
138
|
+
${rgb(255, 120, 20)} ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ${c.reset}
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
const BANNER_FULL = `
|
|
142
|
+
${rgb(255, 220, 120)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${c.reset}
|
|
143
|
+
${rgb(255, 200, 100)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${c.reset}
|
|
144
|
+
${rgb(255, 180, 80)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${c.reset}
|
|
145
|
+
${rgb(255, 160, 60)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${c.reset}
|
|
146
|
+
${rgb(255, 140, 40)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${c.reset}
|
|
147
|
+
${rgb(255, 120, 20)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${c.reset}
|
|
148
|
+
|
|
149
|
+
${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
|
|
150
|
+
${c.dim} │${c.reset} ${rgb(255, 200, 100)}⚡${c.reset} ${c.bold}INIT${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}Project Setup${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}Enterprise Ready${c.reset} ${c.dim}│${c.reset}
|
|
151
|
+
${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
155
|
+
// ICONS & SYMBOLS
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
157
|
+
|
|
158
|
+
const ICONS = {
|
|
159
|
+
// Main
|
|
160
|
+
init: '⚡',
|
|
161
|
+
setup: '🔧',
|
|
162
|
+
config: '⚙️',
|
|
163
|
+
wizard: '🧙',
|
|
164
|
+
|
|
165
|
+
// Status
|
|
166
|
+
check: '✓',
|
|
167
|
+
cross: '✗',
|
|
168
|
+
warning: '⚠',
|
|
169
|
+
info: 'ℹ',
|
|
170
|
+
arrow: '→',
|
|
171
|
+
bullet: '•',
|
|
172
|
+
|
|
173
|
+
// Categories
|
|
174
|
+
framework: '🏗️',
|
|
175
|
+
database: '🗄️',
|
|
176
|
+
auth: '🔐',
|
|
177
|
+
payment: '💳',
|
|
178
|
+
ci: '🔄',
|
|
179
|
+
deploy: '🚀',
|
|
180
|
+
testing: '🧪',
|
|
181
|
+
|
|
182
|
+
// Actions
|
|
183
|
+
create: '📝',
|
|
184
|
+
update: '✏️',
|
|
185
|
+
skip: '⏭️',
|
|
186
|
+
detect: '🔍',
|
|
187
|
+
repair: '🔧',
|
|
188
|
+
tool: '🛠️',
|
|
189
|
+
|
|
190
|
+
// Objects
|
|
191
|
+
file: '📄',
|
|
192
|
+
folder: '📁',
|
|
193
|
+
git: '🌿',
|
|
194
|
+
lock: '🔒',
|
|
195
|
+
shield: '🛡️',
|
|
196
|
+
team: '👥',
|
|
197
|
+
clock: '⏱',
|
|
198
|
+
lightning: '⚡',
|
|
199
|
+
sparkle: '✨',
|
|
200
|
+
star: '★',
|
|
201
|
+
|
|
202
|
+
// Enterprise
|
|
203
|
+
enterprise: '🏢',
|
|
204
|
+
compliance: '📋',
|
|
205
|
+
mcp: '🤖',
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
209
|
+
// BOX DRAWING
|
|
210
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
211
|
+
|
|
212
|
+
const BOX = {
|
|
213
|
+
topLeft: '╭', topRight: '╮', bottomLeft: '╰', bottomRight: '╯',
|
|
214
|
+
horizontal: '─', vertical: '│',
|
|
215
|
+
teeRight: '├', teeLeft: '┤', teeDown: '┬', teeUp: '┴',
|
|
216
|
+
cross: '┼',
|
|
217
|
+
// Double line
|
|
218
|
+
dTopLeft: '╔', dTopRight: '╗', dBottomLeft: '╚', dBottomRight: '╝',
|
|
219
|
+
dHorizontal: '═', dVertical: '║',
|
|
220
|
+
// Heavy
|
|
221
|
+
hTopLeft: '┏', hTopRight: '┓', hBottomLeft: '┗', hBottomRight: '┛',
|
|
222
|
+
hHorizontal: '━', hVertical: '┃',
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
226
|
+
// SPINNER & PROGRESS
|
|
227
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
228
|
+
|
|
229
|
+
const SPINNER_DOTS = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
|
|
230
|
+
const SPINNER_SETUP = ['⚡', '✨', '⚡', '✨'];
|
|
231
|
+
|
|
232
|
+
let spinnerIndex = 0;
|
|
233
|
+
let spinnerInterval = null;
|
|
234
|
+
let spinnerStartTime = null;
|
|
235
|
+
|
|
236
|
+
function formatDuration(ms) {
|
|
237
|
+
if (ms < 1000) return `${ms}ms`;
|
|
238
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
239
|
+
const mins = Math.floor(ms / 60000);
|
|
240
|
+
const secs = Math.floor((ms % 60000) / 1000);
|
|
241
|
+
return `${mins}m ${secs}s`;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function truncate(str, len) {
|
|
245
|
+
if (!str) return '';
|
|
246
|
+
if (str.length <= len) return str;
|
|
247
|
+
return str.slice(0, len - 3) + '...';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function padCenter(str, width) {
|
|
251
|
+
const padding = Math.max(0, width - str.length);
|
|
252
|
+
const left = Math.floor(padding / 2);
|
|
253
|
+
const right = padding - left;
|
|
254
|
+
return ' '.repeat(left) + str + ' '.repeat(right);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function startSpinner(message, color = colors.accent) {
|
|
258
|
+
spinnerStartTime = Date.now();
|
|
259
|
+
process.stdout.write(c.hideCursor);
|
|
260
|
+
|
|
261
|
+
spinnerInterval = setInterval(() => {
|
|
262
|
+
const elapsed = formatDuration(Date.now() - spinnerStartTime);
|
|
263
|
+
process.stdout.write(`\r${c.clearLine} ${color}${SPINNER_DOTS[spinnerIndex]}${c.reset} ${message} ${c.dim}${elapsed}${c.reset}`);
|
|
264
|
+
spinnerIndex = (spinnerIndex + 1) % SPINNER_DOTS.length;
|
|
265
|
+
}, 80);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function stopSpinner(message, success = true) {
|
|
269
|
+
if (spinnerInterval) {
|
|
270
|
+
clearInterval(spinnerInterval);
|
|
271
|
+
spinnerInterval = null;
|
|
272
|
+
}
|
|
273
|
+
const elapsed = spinnerStartTime ? formatDuration(Date.now() - spinnerStartTime) : '';
|
|
274
|
+
const icon = success ? `${colors.success}${ICONS.check}${c.reset}` : `${colors.error}${ICONS.cross}${c.reset}`;
|
|
275
|
+
process.stdout.write(`\r${c.clearLine} ${icon} ${message} ${c.dim}${elapsed}${c.reset}\n`);
|
|
276
|
+
process.stdout.write(c.showCursor);
|
|
277
|
+
spinnerStartTime = null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
281
|
+
// SECTION HEADERS
|
|
282
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
283
|
+
|
|
284
|
+
function printBanner() {
|
|
285
|
+
console.log(BANNER_FULL);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function printCompactBanner() {
|
|
289
|
+
console.log(INIT_BANNER);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function printDivider(char = '─', width = 69, color = c.dim) {
|
|
293
|
+
console.log(`${color} ${char.repeat(width)}${c.reset}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function printSection(title, icon = '◆') {
|
|
297
|
+
console.log();
|
|
298
|
+
console.log(` ${colors.accent}${icon}${c.reset} ${c.bold}${title}${c.reset}`);
|
|
299
|
+
printDivider();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
303
|
+
// FRAMEWORK-SPECIFIC CONFIGURATION
|
|
304
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
305
|
+
|
|
306
|
+
function getFrameworkConfig(detection) {
|
|
307
|
+
if (!detection || !detection.frameworks) {
|
|
308
|
+
return {
|
|
309
|
+
framework: "node",
|
|
310
|
+
checks: ["routes", "env", "auth", "security"],
|
|
311
|
+
ignorePaths: [],
|
|
312
|
+
extra: {},
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Find the primary detected framework
|
|
317
|
+
const detectedFrameworks = Object.entries(detection.frameworks)
|
|
318
|
+
.filter(([key, fw]) => fw.detected)
|
|
319
|
+
.map(([key, fw]) => ({ key, ...fw }));
|
|
320
|
+
|
|
321
|
+
if (detectedFrameworks.length === 0) {
|
|
322
|
+
return {
|
|
323
|
+
framework: "node",
|
|
324
|
+
checks: ["routes", "env", "auth", "security"],
|
|
325
|
+
ignorePaths: [],
|
|
326
|
+
extra: {},
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Use the first detected framework (usually the most specific)
|
|
331
|
+
const primary = detectedFrameworks[0];
|
|
332
|
+
const frameworkKey = primary.key;
|
|
333
|
+
|
|
334
|
+
// Framework-specific configurations
|
|
335
|
+
const frameworkConfigs = {
|
|
336
|
+
nextjs: {
|
|
337
|
+
framework: "nextjs",
|
|
338
|
+
checks: ["routes", "auth", "api", "security", "ssr"],
|
|
339
|
+
ignorePaths: [".next/", "out/", ".vercel/"],
|
|
340
|
+
extra: {},
|
|
341
|
+
},
|
|
342
|
+
remix: {
|
|
343
|
+
framework: "remix",
|
|
344
|
+
checks: ["routes", "auth", "api", "security", "loaders"],
|
|
345
|
+
ignorePaths: [".remix/", "build/"],
|
|
346
|
+
extra: {},
|
|
347
|
+
},
|
|
348
|
+
nuxt: {
|
|
349
|
+
framework: "nuxt",
|
|
350
|
+
checks: ["routes", "auth", "api", "security"],
|
|
351
|
+
ignorePaths: [".nuxt/", ".output/"],
|
|
352
|
+
extra: {},
|
|
353
|
+
},
|
|
354
|
+
sveltekit: {
|
|
355
|
+
framework: "sveltekit",
|
|
356
|
+
checks: ["routes", "auth", "api", "security"],
|
|
357
|
+
ignorePaths: [".svelte-kit/", "build/"],
|
|
358
|
+
extra: {},
|
|
359
|
+
},
|
|
360
|
+
react: {
|
|
361
|
+
framework: "react",
|
|
362
|
+
checks: ["components", "api", "security"],
|
|
363
|
+
ignorePaths: ["build/", "dist/"],
|
|
364
|
+
extra: {},
|
|
365
|
+
},
|
|
366
|
+
vue: {
|
|
367
|
+
framework: "vue",
|
|
368
|
+
checks: ["components", "api", "security"],
|
|
369
|
+
ignorePaths: ["dist/"],
|
|
370
|
+
extra: {},
|
|
371
|
+
},
|
|
372
|
+
fastify: {
|
|
373
|
+
framework: "fastify",
|
|
374
|
+
checks: ["routes", "auth", "api", "security"],
|
|
375
|
+
ignorePaths: [],
|
|
376
|
+
extra: {
|
|
377
|
+
fastify: {
|
|
378
|
+
plugins: detection.frameworks?.fastify?.plugins || [],
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
express: {
|
|
383
|
+
framework: "express",
|
|
384
|
+
checks: ["routes", "auth", "api", "security"],
|
|
385
|
+
ignorePaths: [],
|
|
386
|
+
extra: {},
|
|
387
|
+
},
|
|
388
|
+
nestjs: {
|
|
389
|
+
framework: "nestjs",
|
|
390
|
+
checks: ["routes", "auth", "api", "security", "modules"],
|
|
391
|
+
ignorePaths: ["dist/"],
|
|
392
|
+
extra: {},
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Get framework-specific config or use detected checks
|
|
397
|
+
const config = frameworkConfigs[frameworkKey] || {
|
|
398
|
+
framework: frameworkKey,
|
|
399
|
+
checks: primary.checks || ["routes", "env", "auth", "security"],
|
|
400
|
+
ignorePaths: [],
|
|
401
|
+
extra: {},
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// Merge detected checks if available
|
|
405
|
+
if (primary.checks && primary.checks.length > 0) {
|
|
406
|
+
config.checks = [...new Set([...config.checks, ...primary.checks])];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return config;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
413
|
+
// INIT STATE TRACKING
|
|
414
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
415
|
+
|
|
416
|
+
function saveInitState(targetDir, state) {
|
|
417
|
+
try {
|
|
418
|
+
const statePath = path.join(targetDir, ".vibecheck", ".init-state.json");
|
|
419
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
420
|
+
} catch (e) {
|
|
421
|
+
// Non-critical - state tracking is optional
|
|
422
|
+
if (process.env.VIBECHECK_DEBUG) {
|
|
423
|
+
console.error(`Failed to save init state: ${e.message}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function loadInitState(targetDir) {
|
|
429
|
+
try {
|
|
430
|
+
const statePath = path.join(targetDir, ".vibecheck", ".init-state.json");
|
|
431
|
+
if (fs.existsSync(statePath)) {
|
|
432
|
+
return JSON.parse(fs.readFileSync(statePath, "utf-8"));
|
|
433
|
+
}
|
|
434
|
+
} catch (e) {
|
|
435
|
+
// Non-critical
|
|
436
|
+
}
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
441
|
+
// POST-INIT VALIDATION
|
|
442
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
443
|
+
|
|
444
|
+
async function verifyInitSetup(targetDir, opts) {
|
|
445
|
+
const issues = [];
|
|
446
|
+
const vibecheckDir = path.join(targetDir, ".vibecheck");
|
|
447
|
+
|
|
448
|
+
// Check directory structure
|
|
449
|
+
const requiredDirs = [
|
|
450
|
+
vibecheckDir,
|
|
451
|
+
path.join(vibecheckDir, "results"),
|
|
452
|
+
path.join(vibecheckDir, "contracts"),
|
|
453
|
+
];
|
|
454
|
+
|
|
455
|
+
for (const dir of requiredDirs) {
|
|
456
|
+
if (!fs.existsSync(dir)) {
|
|
457
|
+
issues.push(`Missing directory: ${path.relative(targetDir, dir)}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Check config.json
|
|
462
|
+
const configPath = path.join(vibecheckDir, "config.json");
|
|
463
|
+
if (!fs.existsSync(configPath)) {
|
|
464
|
+
issues.push("Missing: .vibecheck/config.json");
|
|
465
|
+
} else {
|
|
466
|
+
try {
|
|
467
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
468
|
+
if (!config.version || !config.checks) {
|
|
469
|
+
issues.push("Invalid config.json structure");
|
|
470
|
+
}
|
|
471
|
+
} catch (e) {
|
|
472
|
+
issues.push(`Invalid config.json: ${e.message}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Check truthpack
|
|
477
|
+
const truthpackPath = path.join(vibecheckDir, "truthpack.json");
|
|
478
|
+
if (!fs.existsSync(truthpackPath)) {
|
|
479
|
+
issues.push("Missing: .vibecheck/truthpack.json (run 'vibecheck ctx build')");
|
|
480
|
+
} else {
|
|
481
|
+
try {
|
|
482
|
+
const truthpack = JSON.parse(fs.readFileSync(truthpackPath, "utf-8"));
|
|
483
|
+
if (!truthpack.version || !truthpack.generatedAt) {
|
|
484
|
+
issues.push("Invalid truthpack.json structure");
|
|
485
|
+
}
|
|
486
|
+
} catch (e) {
|
|
487
|
+
issues.push(`Invalid truthpack.json: ${e.message}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Check contracts
|
|
492
|
+
const contractsDir = path.join(vibecheckDir, "contracts");
|
|
493
|
+
const requiredContracts = ["routes.contract.json", "env.contract.json"];
|
|
494
|
+
for (const contract of requiredContracts) {
|
|
495
|
+
const contractPath = path.join(contractsDir, contract);
|
|
496
|
+
if (!fs.existsSync(contractPath)) {
|
|
497
|
+
issues.push(`Missing contract: ${contract}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (issues.length === 0 && !opts.json) {
|
|
502
|
+
console.log();
|
|
503
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} ${c.bold}Setup Verification:${c.reset} All checks passed`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return {
|
|
507
|
+
success: issues.length === 0,
|
|
508
|
+
issues,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
513
|
+
// FRAMEWORK-SPECIFIC RECOMMENDATIONS
|
|
514
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
515
|
+
|
|
516
|
+
function printFrameworkRecommendations(detection, opts) {
|
|
517
|
+
const frameworks = Object.keys(detection.frameworks || {}).filter(k => detection.frameworks[k].detected);
|
|
518
|
+
if (frameworks.length === 0) return;
|
|
519
|
+
|
|
520
|
+
const primaryFramework = frameworks[0];
|
|
521
|
+
const framework = detection.frameworks[primaryFramework];
|
|
522
|
+
|
|
523
|
+
const recommendations = [];
|
|
524
|
+
|
|
525
|
+
// Next.js specific
|
|
526
|
+
if (primaryFramework === 'nextjs') {
|
|
527
|
+
recommendations.push({
|
|
528
|
+
icon: ICONS.framework,
|
|
529
|
+
title: "Next.js Route Verification",
|
|
530
|
+
command: "vibecheck scan --routes",
|
|
531
|
+
description: "Verify all Next.js routes are properly configured",
|
|
532
|
+
});
|
|
533
|
+
if (!opts.connect) {
|
|
534
|
+
recommendations.push({
|
|
535
|
+
icon: ICONS.ci,
|
|
536
|
+
title: "Add Vercel Integration",
|
|
537
|
+
command: "vibecheck init --connect",
|
|
538
|
+
description: "Enable GitHub Actions for automatic PR checks",
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Fastify specific
|
|
544
|
+
if (primaryFramework === 'fastify') {
|
|
545
|
+
recommendations.push({
|
|
546
|
+
icon: ICONS.framework,
|
|
547
|
+
title: "Fastify Route Extraction",
|
|
548
|
+
command: "vibecheck scan --routes",
|
|
549
|
+
description: "Extract and verify all Fastify routes",
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Express specific
|
|
554
|
+
if (primaryFramework === 'express') {
|
|
555
|
+
recommendations.push({
|
|
556
|
+
icon: ICONS.framework,
|
|
557
|
+
title: "Express Route Analysis",
|
|
558
|
+
command: "vibecheck scan --routes",
|
|
559
|
+
description: "Analyze Express route definitions",
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Auth providers
|
|
564
|
+
const authProviders = Object.keys(detection.auth || {}).filter(k => detection.auth[k].detected);
|
|
565
|
+
if (authProviders.length > 0) {
|
|
566
|
+
recommendations.push({
|
|
567
|
+
icon: ICONS.auth,
|
|
568
|
+
title: "Auth Coverage Check",
|
|
569
|
+
command: "vibecheck scan --auth",
|
|
570
|
+
description: "Verify authentication coverage across routes",
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Payment providers
|
|
575
|
+
const paymentProviders = Object.keys(detection.payments || {}).filter(k => detection.payments[k].detected);
|
|
576
|
+
if (paymentProviders.length > 0) {
|
|
577
|
+
recommendations.push({
|
|
578
|
+
icon: ICONS.payment,
|
|
579
|
+
title: "Payment Flow Verification",
|
|
580
|
+
command: "vibecheck scan --billing",
|
|
581
|
+
description: "Verify payment webhook handlers and idempotency",
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (recommendations.length > 0) {
|
|
586
|
+
console.log();
|
|
587
|
+
printSection('RECOMMENDATIONS', ICONS.sparkle);
|
|
588
|
+
console.log();
|
|
589
|
+
for (const rec of recommendations) {
|
|
590
|
+
console.log(` ${rec.icon} ${c.bold}${rec.title}${c.reset}`);
|
|
591
|
+
console.log(` ${c.dim}${rec.description}${c.reset}`);
|
|
592
|
+
console.log(` ${c.cyan}${rec.command}${c.reset}`);
|
|
593
|
+
console.log();
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
599
|
+
// REPAIR MODE - Fix partial init state
|
|
600
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
601
|
+
|
|
602
|
+
async function runRepairMode(targetDir, projectName, opts) {
|
|
603
|
+
printSection('REPAIR MODE', ICONS.repair);
|
|
604
|
+
console.log();
|
|
605
|
+
console.log(` ${colors.info}${ICONS.info}${c.reset} Scanning for partial initialization state...`);
|
|
606
|
+
console.log();
|
|
607
|
+
|
|
608
|
+
// Load previous init state if available
|
|
609
|
+
const previousState = loadInitState(targetDir);
|
|
610
|
+
if (previousState && !opts.json) {
|
|
611
|
+
console.log(` ${c.dim}Previous init: ${previousState.timestamp} (${previousState.mode} mode)${c.reset}`);
|
|
612
|
+
if (previousState.errors && previousState.errors.length > 0) {
|
|
613
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${previousState.errors.length} error(s) from previous attempt`);
|
|
614
|
+
}
|
|
615
|
+
console.log();
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const vibecheckDir = path.join(targetDir, ".vibecheck");
|
|
619
|
+
const issues = [];
|
|
620
|
+
const fixes = [];
|
|
621
|
+
|
|
622
|
+
// Check for missing directories
|
|
623
|
+
const requiredDirs = [
|
|
624
|
+
vibecheckDir,
|
|
625
|
+
path.join(vibecheckDir, "results"),
|
|
626
|
+
path.join(vibecheckDir, "reports"),
|
|
627
|
+
path.join(vibecheckDir, "contracts"),
|
|
628
|
+
path.join(vibecheckDir, "missions"),
|
|
629
|
+
path.join(vibecheckDir, "checkpoints"),
|
|
630
|
+
path.join(vibecheckDir, "runs"),
|
|
631
|
+
];
|
|
632
|
+
|
|
633
|
+
for (const dir of requiredDirs) {
|
|
634
|
+
if (!fs.existsSync(dir)) {
|
|
635
|
+
issues.push(`Missing directory: ${path.relative(targetDir, dir)}`);
|
|
636
|
+
if (!opts.dryRun) {
|
|
637
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
638
|
+
fixes.push(`Created: ${path.relative(targetDir, dir)}`);
|
|
639
|
+
} else {
|
|
640
|
+
fixes.push(`Would create: ${path.relative(targetDir, dir)}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Check for missing config.json
|
|
646
|
+
const configPath = path.join(vibecheckDir, "config.json");
|
|
647
|
+
if (!fs.existsSync(configPath)) {
|
|
648
|
+
issues.push("Missing: .vibecheck/config.json");
|
|
649
|
+
if (!opts.dryRun) {
|
|
650
|
+
try {
|
|
651
|
+
const { detectAll } = require("./lib/enterprise-detect");
|
|
652
|
+
const detection = detectAll(targetDir);
|
|
653
|
+
const frameworkConfig = getFrameworkConfig(detection);
|
|
654
|
+
const config = {
|
|
655
|
+
version: "2.0.0",
|
|
656
|
+
project: projectName,
|
|
657
|
+
createdAt: new Date().toISOString(),
|
|
658
|
+
framework: frameworkConfig.framework || "node",
|
|
659
|
+
checks: frameworkConfig.checks || ["routes", "env", "auth", "security"],
|
|
660
|
+
output: ".vibecheck",
|
|
661
|
+
policy: {
|
|
662
|
+
allowlist: { domains: [], packages: [] },
|
|
663
|
+
ignore: {
|
|
664
|
+
paths: [
|
|
665
|
+
"node_modules",
|
|
666
|
+
"__tests__",
|
|
667
|
+
"*.test.*",
|
|
668
|
+
"*.spec.*",
|
|
669
|
+
...(frameworkConfig.ignorePaths || []),
|
|
670
|
+
],
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
thresholds: {
|
|
674
|
+
minScore: 70,
|
|
675
|
+
maxBlockers: 0,
|
|
676
|
+
maxWarnings: 10,
|
|
677
|
+
},
|
|
678
|
+
...(frameworkConfig.extra || {}),
|
|
679
|
+
};
|
|
680
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
681
|
+
fixes.push("Created: .vibecheck/config.json");
|
|
682
|
+
} catch (e) {
|
|
683
|
+
issues.push(`Failed to create config.json: ${e.message}`);
|
|
684
|
+
}
|
|
685
|
+
} else {
|
|
686
|
+
fixes.push("Would create: .vibecheck/config.json");
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Check for missing truthpack
|
|
691
|
+
const truthpackPath = path.join(vibecheckDir, "truthpack.json");
|
|
692
|
+
if (!fs.existsSync(truthpackPath)) {
|
|
693
|
+
issues.push("Missing: .vibecheck/truthpack.json");
|
|
694
|
+
if (!opts.dryRun) {
|
|
695
|
+
startSpinner('Generating truthpack...', colors.accent);
|
|
696
|
+
try {
|
|
697
|
+
const { runContext } = require("./runContext");
|
|
698
|
+
await runContext(["--path", targetDir, "--quiet"]);
|
|
699
|
+
stopSpinner('Truthpack generated', true);
|
|
700
|
+
fixes.push("Generated: .vibecheck/truthpack.json");
|
|
701
|
+
} catch (e) {
|
|
702
|
+
stopSpinner('Truthpack generation failed', false);
|
|
703
|
+
issues.push(`Failed to generate truthpack: ${e.message}`);
|
|
704
|
+
}
|
|
705
|
+
} else {
|
|
706
|
+
fixes.push("Would generate: .vibecheck/truthpack.json");
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Check for missing contracts
|
|
711
|
+
const contractsDir = path.join(vibecheckDir, "contracts");
|
|
712
|
+
const routeContractPath = path.join(contractsDir, "routes.contract.json");
|
|
713
|
+
const envContractPath = path.join(contractsDir, "env.contract.json");
|
|
714
|
+
|
|
715
|
+
if (!fs.existsSync(routeContractPath)) {
|
|
716
|
+
issues.push("Missing: .vibecheck/contracts/routes.contract.json");
|
|
717
|
+
if (!opts.dryRun) {
|
|
718
|
+
const routeContract = {
|
|
719
|
+
version: "1.0.0",
|
|
720
|
+
generatedAt: new Date().toISOString(),
|
|
721
|
+
routes: [],
|
|
722
|
+
description: "Route contract - populated by scan",
|
|
723
|
+
};
|
|
724
|
+
fs.writeFileSync(routeContractPath, JSON.stringify(routeContract, null, 2));
|
|
725
|
+
fixes.push("Created: .vibecheck/contracts/routes.contract.json");
|
|
726
|
+
} else {
|
|
727
|
+
fixes.push("Would create: .vibecheck/contracts/routes.contract.json");
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
if (!fs.existsSync(envContractPath)) {
|
|
732
|
+
issues.push("Missing: .vibecheck/contracts/env.contract.json");
|
|
733
|
+
if (!opts.dryRun) {
|
|
734
|
+
const envContract = {
|
|
735
|
+
version: "1.0.0",
|
|
736
|
+
generatedAt: new Date().toISOString(),
|
|
737
|
+
required: [],
|
|
738
|
+
optional: [],
|
|
739
|
+
description: "Environment contract - populated by scan",
|
|
740
|
+
};
|
|
741
|
+
fs.writeFileSync(envContractPath, JSON.stringify(envContract, null, 2));
|
|
742
|
+
fixes.push("Created: .vibecheck/contracts/env.contract.json");
|
|
743
|
+
} else {
|
|
744
|
+
fixes.push("Would create: .vibecheck/contracts/env.contract.json");
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Use previous state to prioritize fixes
|
|
749
|
+
if (previousState && previousState.errors && previousState.errors.length > 0) {
|
|
750
|
+
const previousErrors = previousState.errors.map(e => e.step);
|
|
751
|
+
// Prioritize fixing errors from previous attempt
|
|
752
|
+
const prioritizedIssues = [];
|
|
753
|
+
const otherIssues = [];
|
|
754
|
+
|
|
755
|
+
for (const issue of issues) {
|
|
756
|
+
const isPreviousError = previousErrors.some(step => issue.toLowerCase().includes(step));
|
|
757
|
+
if (isPreviousError) {
|
|
758
|
+
prioritizedIssues.push(issue);
|
|
759
|
+
} else {
|
|
760
|
+
otherIssues.push(issue);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
issues.length = 0;
|
|
765
|
+
issues.push(...prioritizedIssues, ...otherIssues);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Summary
|
|
769
|
+
console.log();
|
|
770
|
+
if (issues.length === 0) {
|
|
771
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} No issues found - initialization is complete`);
|
|
772
|
+
// Clear previous state on successful repair
|
|
773
|
+
if (!opts.dryRun) {
|
|
774
|
+
const statePath = path.join(targetDir, ".vibecheck", ".init-state.json");
|
|
775
|
+
if (fs.existsSync(statePath)) {
|
|
776
|
+
fs.unlinkSync(statePath);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
return 0;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} Found ${issues.length} issue(s)`);
|
|
783
|
+
if (previousState && previousState.errors && previousState.errors.length > 0) {
|
|
784
|
+
console.log(` ${c.dim}(${previousState.errors.length} from previous attempt)${c.reset}`);
|
|
785
|
+
}
|
|
786
|
+
console.log();
|
|
787
|
+
for (const issue of issues) {
|
|
788
|
+
console.log(` ${c.dim}•${c.reset} ${issue}`);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (fixes.length > 0) {
|
|
792
|
+
console.log();
|
|
793
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} Applied ${fixes.length} fix(es)`);
|
|
794
|
+
for (const fix of fixes) {
|
|
795
|
+
console.log(` ${c.dim}•${c.reset} ${fix}`);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
console.log();
|
|
800
|
+
return issues.length > 0 ? (opts.dryRun ? 0 : 1) : 0;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
804
|
+
// ENHANCED DETECTION DISPLAY
|
|
805
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
806
|
+
|
|
807
|
+
function printEnhancedDetection(detection, verbose = false) {
|
|
808
|
+
const frameworks = Object.keys(detection.frameworks || {}).filter(k => detection.frameworks[k].detected);
|
|
809
|
+
const databases = Object.keys(detection.databases || {}).filter(k => detection.databases[k].detected);
|
|
810
|
+
const authProviders = Object.keys(detection.auth || {}).filter(k => detection.auth[k].detected);
|
|
811
|
+
const paymentProviders = Object.keys(detection.payments || {}).filter(k => detection.payments[k].detected);
|
|
812
|
+
|
|
813
|
+
if (frameworks.length > 0) {
|
|
814
|
+
console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}Detected Stack:${c.reset}`);
|
|
815
|
+
console.log(` ${ICONS.framework} Frameworks: ${frameworks.map(f => detection.frameworks[f].name).join(', ')}`);
|
|
816
|
+
|
|
817
|
+
if (databases.length > 0) {
|
|
818
|
+
console.log(` ${ICONS.database} Databases: ${databases.map(d => detection.databases[d].name).join(', ')}`);
|
|
819
|
+
}
|
|
820
|
+
if (authProviders.length > 0) {
|
|
821
|
+
console.log(` ${ICONS.auth} Auth: ${authProviders.map(a => detection.auth[a].name).join(', ')}`);
|
|
822
|
+
}
|
|
823
|
+
if (paymentProviders.length > 0) {
|
|
824
|
+
console.log(` ${ICONS.payment} Payments: ${paymentProviders.map(p => detection.payments[p].name).join(', ')}`);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (verbose) {
|
|
828
|
+
console.log();
|
|
829
|
+
console.log(` ${c.dim}Detection Details:${c.reset}`);
|
|
830
|
+
if (detection.packageManager) {
|
|
831
|
+
console.log(` Package Manager: ${detection.packageManager}`);
|
|
832
|
+
}
|
|
833
|
+
if (detection.nodeVersion) {
|
|
834
|
+
console.log(` Node Version: ${detection.nodeVersion}`);
|
|
835
|
+
}
|
|
836
|
+
const checks = detection.checks || [];
|
|
837
|
+
if (checks.length > 0) {
|
|
838
|
+
console.log(` Recommended Checks: ${checks.join(', ')}`);
|
|
839
|
+
}
|
|
840
|
+
const invariants = detection.invariants || [];
|
|
841
|
+
if (invariants.length > 0) {
|
|
842
|
+
console.log(` Invariants: ${invariants.join(', ')}`);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
console.log();
|
|
846
|
+
} else {
|
|
847
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} No framework detected - using default Node.js configuration`);
|
|
848
|
+
console.log();
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
853
|
+
// DETECTION DISPLAY
|
|
854
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
855
|
+
|
|
856
|
+
function printDetectionResults(detection) {
|
|
857
|
+
printSection('PROJECT DETECTION', ICONS.detect);
|
|
858
|
+
console.log();
|
|
859
|
+
|
|
860
|
+
const categories = [
|
|
861
|
+
{ key: 'frameworks', label: 'Frameworks', icon: ICONS.framework, color: colors.framework },
|
|
862
|
+
{ key: 'databases', label: 'Databases', icon: ICONS.database, color: colors.database },
|
|
863
|
+
{ key: 'auth', label: 'Authentication', icon: ICONS.auth, color: colors.auth },
|
|
864
|
+
{ key: 'payments', label: 'Payments', icon: ICONS.payment, color: colors.payment },
|
|
865
|
+
{ key: 'ci', label: 'CI/CD', icon: ICONS.ci, color: colors.ci },
|
|
866
|
+
{ key: 'deploy', label: 'Deployment', icon: ICONS.deploy, color: colors.deploy },
|
|
867
|
+
{ key: 'testing', label: 'Testing', icon: ICONS.testing, color: colors.testing },
|
|
868
|
+
];
|
|
869
|
+
|
|
870
|
+
for (const cat of categories) {
|
|
871
|
+
const itemsObj = detection[cat.key] || {};
|
|
872
|
+
// Handle both object and array formats
|
|
873
|
+
const items = Array.isArray(itemsObj)
|
|
874
|
+
? itemsObj
|
|
875
|
+
: Object.entries(itemsObj)
|
|
876
|
+
.filter(([key, value]) => value && (value.detected || value === true))
|
|
877
|
+
.map(([key, value]) => typeof value === 'object' ? value.name || key : key);
|
|
878
|
+
|
|
879
|
+
if (items.length === 0) continue;
|
|
880
|
+
|
|
881
|
+
const itemList = items.slice(0, 4).join(', ');
|
|
882
|
+
const more = items.length > 4 ? ` +${items.length - 4} more` : '';
|
|
883
|
+
|
|
884
|
+
console.log(` ${cat.color}${cat.icon}${c.reset} ${c.bold}${cat.label.padEnd(16)}${c.reset} ${itemList}${c.dim}${more}${c.reset}`);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// Show detected package manager
|
|
888
|
+
if (detection.packageManager) {
|
|
889
|
+
console.log();
|
|
890
|
+
console.log(` ${c.dim}Package manager:${c.reset} ${colors.info}${detection.packageManager}${c.reset}`);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// Show Node version if detected
|
|
894
|
+
if (detection.nodeVersion) {
|
|
895
|
+
console.log(` ${c.dim}Node version:${c.reset} ${colors.info}${detection.nodeVersion}${c.reset}`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
900
|
+
// SETUP PROGRESS DISPLAY
|
|
901
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
902
|
+
|
|
903
|
+
function printSetupStep(step, status, detail = null) {
|
|
904
|
+
let icon, color;
|
|
905
|
+
|
|
906
|
+
switch (status) {
|
|
907
|
+
case 'dry-run':
|
|
908
|
+
icon = ICONS.info;
|
|
909
|
+
color = colors.warning;
|
|
910
|
+
break;
|
|
911
|
+
case 'creating':
|
|
912
|
+
icon = ICONS.create;
|
|
913
|
+
color = colors.accent;
|
|
914
|
+
break;
|
|
915
|
+
case 'updating':
|
|
916
|
+
icon = ICONS.update;
|
|
917
|
+
color = colors.info;
|
|
918
|
+
break;
|
|
919
|
+
case 'success':
|
|
920
|
+
icon = ICONS.check;
|
|
921
|
+
color = colors.success;
|
|
922
|
+
break;
|
|
923
|
+
case 'skipped':
|
|
924
|
+
icon = ICONS.skip;
|
|
925
|
+
color = colors.muted;
|
|
926
|
+
break;
|
|
927
|
+
case 'exists':
|
|
928
|
+
icon = ICONS.warning;
|
|
929
|
+
color = colors.warning;
|
|
930
|
+
break;
|
|
931
|
+
case 'error':
|
|
932
|
+
icon = ICONS.cross;
|
|
933
|
+
color = colors.error;
|
|
934
|
+
break;
|
|
935
|
+
default:
|
|
936
|
+
icon = ICONS.bullet;
|
|
937
|
+
color = colors.muted;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
let line = ` ${color}${icon}${c.reset} ${step}`;
|
|
941
|
+
if (detail) {
|
|
942
|
+
line += ` ${c.dim}${detail}${c.reset}`;
|
|
943
|
+
}
|
|
944
|
+
console.log(line);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
948
|
+
// FILES CREATED DISPLAY
|
|
949
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
950
|
+
|
|
951
|
+
function printFilesCreated(files) {
|
|
952
|
+
printSection('FILES CREATED', ICONS.file);
|
|
953
|
+
console.log();
|
|
954
|
+
|
|
955
|
+
const fileIcons = {
|
|
956
|
+
'config.json': ICONS.config,
|
|
957
|
+
'invariants.yml': ICONS.shield,
|
|
958
|
+
'security-policy.json': ICONS.lock,
|
|
959
|
+
'team.json': ICONS.team,
|
|
960
|
+
'mcp.json': ICONS.mcp,
|
|
961
|
+
'.vibecheckrc': ICONS.config,
|
|
962
|
+
'vibecheck.yml': ICONS.ci,
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
for (const file of files) {
|
|
966
|
+
const basename = path.basename(file);
|
|
967
|
+
const icon = fileIcons[basename] || ICONS.file;
|
|
968
|
+
const displayPath = file.startsWith('.vibecheck/') ? file : `.vibecheck/${file}`;
|
|
969
|
+
console.log(` ${colors.success}${icon}${c.reset} ${c.dim}${displayPath}${c.reset}`);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
974
|
+
// SUCCESS CARD
|
|
975
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
976
|
+
|
|
977
|
+
function printSuccessCard(projectName, mode, filesCreated) {
|
|
978
|
+
const w = 68;
|
|
979
|
+
|
|
980
|
+
console.log();
|
|
981
|
+
console.log();
|
|
982
|
+
|
|
983
|
+
// Top border
|
|
984
|
+
console.log(` ${colors.success}${BOX.dTopLeft}${BOX.dHorizontal.repeat(w)}${BOX.dTopRight}${c.reset}`);
|
|
985
|
+
|
|
986
|
+
// Empty line
|
|
987
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${' '.repeat(w)}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
988
|
+
|
|
989
|
+
// Headline
|
|
990
|
+
const headline = `${ICONS.sparkle} VIBECHECK INITIALIZED`;
|
|
991
|
+
const headlinePadded = padCenter(headline, w);
|
|
992
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${colors.success}${c.bold}${headlinePadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
993
|
+
|
|
994
|
+
// Project name
|
|
995
|
+
const projectLine = `Project: ${projectName}`;
|
|
996
|
+
const projectPadded = padCenter(projectLine, w);
|
|
997
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${c.dim}${projectPadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
998
|
+
|
|
999
|
+
// Mode
|
|
1000
|
+
const modeLine = `Mode: ${mode}`;
|
|
1001
|
+
const modePadded = padCenter(modeLine, w);
|
|
1002
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${c.dim}${modePadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
1003
|
+
|
|
1004
|
+
// Empty line
|
|
1005
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${' '.repeat(w)}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
1006
|
+
|
|
1007
|
+
// Files created count
|
|
1008
|
+
const filesLine = `${filesCreated} files configured`;
|
|
1009
|
+
const filesPadded = padCenter(filesLine, w);
|
|
1010
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${colors.accent}${filesPadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
1011
|
+
|
|
1012
|
+
// Empty line
|
|
1013
|
+
console.log(` ${colors.success}${BOX.dVertical}${c.reset}${' '.repeat(w)}${colors.success}${BOX.dVertical}${c.reset}`);
|
|
1014
|
+
|
|
1015
|
+
// Bottom border
|
|
1016
|
+
console.log(` ${colors.success}${BOX.dBottomLeft}${BOX.dHorizontal.repeat(w)}${BOX.dBottomRight}${c.reset}`);
|
|
1017
|
+
|
|
1018
|
+
console.log();
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1022
|
+
// NEXT STEPS DISPLAY
|
|
1023
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1024
|
+
|
|
1025
|
+
function printNextSteps(options = {}) {
|
|
1026
|
+
printSection('NEXT STEPS', ICONS.arrow);
|
|
1027
|
+
console.log();
|
|
1028
|
+
|
|
1029
|
+
const steps = [];
|
|
1030
|
+
|
|
1031
|
+
if (options.mode === 'connect') {
|
|
1032
|
+
steps.push(
|
|
1033
|
+
{ num: 1, cmd: 'vibecheck scan', desc: 'Run baseline scan' },
|
|
1034
|
+
{ num: 2, cmd: 'vibecheck checkpoint --save', desc: 'Save baseline for comparison' },
|
|
1035
|
+
{ num: 3, cmd: 'git push', desc: 'CI will run automatically' },
|
|
1036
|
+
);
|
|
1037
|
+
} else {
|
|
1038
|
+
steps.push(
|
|
1039
|
+
{ num: 1, cmd: 'vibecheck scan', desc: 'Run your first scan' },
|
|
1040
|
+
{ num: 2, cmd: 'vibecheck ship', desc: 'Check if ready to ship' },
|
|
1041
|
+
);
|
|
1042
|
+
|
|
1043
|
+
if (options.hasCI) {
|
|
1044
|
+
steps.push({ num: 3, cmd: 'git push', desc: 'CI will run automatically' });
|
|
1045
|
+
} else {
|
|
1046
|
+
steps.push({ num: 3, cmd: 'vibecheck init --connect', desc: 'Add GitHub integration [STARTER]' });
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
for (const step of steps) {
|
|
1051
|
+
console.log(` ${colors.accent}${step.num}.${c.reset} ${c.bold}${step.cmd}${c.reset}`);
|
|
1052
|
+
console.log(` ${c.dim}${step.desc}${c.reset}`);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
console.log();
|
|
1056
|
+
console.log(` ${c.dim}Full docs:${c.reset} ${colors.info}https://docs.vibecheckai.dev${c.reset}`);
|
|
1057
|
+
console.log();
|
|
1058
|
+
|
|
1059
|
+
// Upsell box
|
|
1060
|
+
console.log(` ${c.dim}╭────────────────────────────────────────────────────────────╮${c.reset}`);
|
|
1061
|
+
console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
|
|
1062
|
+
console.log(` ${c.dim}│${c.reset} ${colors.accent}⚡ STARTER${c.reset} ${c.dim}•${c.reset} AI-powered fixes, GitHub CI, MCP tools ${c.dim}│${c.reset}`);
|
|
1063
|
+
console.log(` ${c.dim}│${c.reset} ${colors.accent}🏆 PRO${c.reset} ${c.dim}•${c.reset} Runtime proof, verified badges, AI testing ${c.dim}│${c.reset}`);
|
|
1064
|
+
console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
|
|
1065
|
+
console.log(` ${c.dim}│${c.reset} ${colors.info}vibecheck login${c.reset} ${c.dim}to upgrade • vibecheck.dev/pricing${c.reset} ${c.dim}│${c.reset}`);
|
|
1066
|
+
console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
|
|
1067
|
+
console.log(` ${c.dim}╰────────────────────────────────────────────────────────────╯${c.reset}`);
|
|
1068
|
+
console.log();
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1072
|
+
// ENTERPRISE MODE HEADER
|
|
1073
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1074
|
+
|
|
1075
|
+
function printEnterpriseHeader(options) {
|
|
1076
|
+
console.log();
|
|
1077
|
+
console.log(` ${bgRgb(60, 40, 100)}${c.bold} ${ICONS.enterprise} ENTERPRISE MODE ${c.reset}`);
|
|
1078
|
+
console.log();
|
|
1079
|
+
|
|
1080
|
+
const features = [];
|
|
1081
|
+
if (options.ci) features.push(`${ICONS.ci} CI/CD`);
|
|
1082
|
+
if (options.compliance) features.push(`${ICONS.compliance} Compliance`);
|
|
1083
|
+
if (options.team) features.push(`${ICONS.team} Team`);
|
|
1084
|
+
if (options.mcp) features.push(`${ICONS.mcp} MCP`);
|
|
1085
|
+
if (options.strict) features.push(`${ICONS.shield} Strict`);
|
|
1086
|
+
|
|
1087
|
+
if (features.length > 0) {
|
|
1088
|
+
console.log(` ${c.dim}Features:${c.reset} ${features.join(' ')}`);
|
|
1089
|
+
console.log();
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1094
|
+
// COMPLIANCE DISPLAY
|
|
1095
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1096
|
+
|
|
1097
|
+
function printComplianceInfo(complianceType) {
|
|
1098
|
+
const complianceInfo = {
|
|
1099
|
+
soc2: { name: 'SOC 2 Type II', icon: '🔐', color: colors.compliance },
|
|
1100
|
+
hipaa: { name: 'HIPAA', icon: '🏥', color: rgb(255, 100, 100) },
|
|
1101
|
+
gdpr: { name: 'GDPR', icon: '🇪🇺', color: rgb(100, 150, 255) },
|
|
1102
|
+
pci: { name: 'PCI-DSS', icon: '💳', color: rgb(255, 200, 100) },
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1105
|
+
const info = complianceInfo[complianceType] || { name: complianceType, icon: ICONS.compliance, color: colors.compliance };
|
|
1106
|
+
|
|
1107
|
+
console.log();
|
|
1108
|
+
console.log(` ${info.color}${info.icon}${c.reset} ${c.bold}${info.name} Compliance${c.reset}`);
|
|
1109
|
+
console.log(` ${c.dim}Generating baseline templates...${c.reset}`);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1113
|
+
// HELP DISPLAY
|
|
1114
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1115
|
+
|
|
1116
|
+
function printHelp(showBanner = true) {
|
|
1117
|
+
if (showBanner && shouldShowBanner({})) {
|
|
1118
|
+
console.log(BANNER_FULL);
|
|
1119
|
+
}
|
|
1120
|
+
console.log(`
|
|
1121
|
+
${c.bold}Usage:${c.reset} vibecheck init [mode] [options]
|
|
1122
|
+
|
|
1123
|
+
${c.bold}MODES${c.reset}
|
|
1124
|
+
${colors.success}--local${c.reset} ${c.green}[FREE]${c.reset} Full local setup (default)
|
|
1125
|
+
Creates truthpack, contracts, MDC/IDE rules
|
|
1126
|
+
${colors.accent}--connect${c.reset} ${c.cyan}[STARTER]${c.reset} + GitHub Actions, PR comments, dashboard sync
|
|
1127
|
+
|
|
1128
|
+
${c.bold}Basic Options:${c.reset}
|
|
1129
|
+
${colors.accent}--path, -p <dir>${c.reset} Project path ${c.dim}(default: current directory)${c.reset}
|
|
1130
|
+
${colors.accent}--quick, -q${c.reset} Skip wizard, use defaults
|
|
1131
|
+
${colors.accent}--wizard, -i${c.reset} Interactive setup wizard
|
|
1132
|
+
${colors.accent}--dry-run${c.reset} Preview changes without applying
|
|
1133
|
+
${colors.accent}--repair${c.reset} Fix partial init state
|
|
1134
|
+
${colors.accent}--verify${c.reset} Verify setup after init
|
|
1135
|
+
${colors.accent}--verbose, -v${c.reset} Show detailed output
|
|
1136
|
+
${colors.accent}--git-hooks${c.reset} Install git pre-push hook
|
|
1137
|
+
${colors.accent}--json${c.reset} Output results as JSON
|
|
1138
|
+
${colors.accent}--help, -h${c.reset} Show this help
|
|
1139
|
+
|
|
1140
|
+
${colors.enterprise}${c.bold}Enterprise Options:${c.reset}
|
|
1141
|
+
${colors.accent}--enterprise, -e${c.reset} Enable enterprise mode
|
|
1142
|
+
${colors.accent}--full${c.reset} All features: CI + team + MCP
|
|
1143
|
+
${colors.accent}--detect${c.reset} Detection only (JSON output)
|
|
1144
|
+
|
|
1145
|
+
${colors.ci}${c.bold}CI/CD Integration:${c.reset}
|
|
1146
|
+
${colors.accent}--ci [provider]${c.reset} Setup CI/CD (auto-detects)
|
|
1147
|
+
${colors.accent}--gha${c.reset} GitHub Actions workflow
|
|
1148
|
+
${colors.accent}--gitlab${c.reset} GitLab CI configuration
|
|
1149
|
+
${colors.accent}--fail-on-warn${c.reset} CI fails on WARN
|
|
1150
|
+
|
|
1151
|
+
${colors.compliance}${c.bold}Compliance Templates:${c.reset}
|
|
1152
|
+
${colors.accent}--compliance [type]${c.reset} Generate compliance templates
|
|
1153
|
+
${colors.accent}--soc2${c.reset} SOC 2 Type II baseline
|
|
1154
|
+
${colors.accent}--hipaa${c.reset} HIPAA compliance baseline
|
|
1155
|
+
${colors.accent}--gdpr${c.reset} GDPR compliance baseline
|
|
1156
|
+
${colors.accent}--pci${c.reset} PCI-DSS compliance baseline
|
|
1157
|
+
|
|
1158
|
+
${colors.team}${c.bold}Team & Security:${c.reset}
|
|
1159
|
+
${colors.accent}--team${c.reset} Generate team config (multi-env)
|
|
1160
|
+
${colors.accent}--mcp${c.reset} Generate MCP server config
|
|
1161
|
+
${colors.accent}--strict${c.reset} Enable strict mode
|
|
1162
|
+
|
|
1163
|
+
${c.bold}Created Files (--local):${c.reset}
|
|
1164
|
+
${c.dim}.vibecheck/config.json${c.reset} Main configuration
|
|
1165
|
+
${c.dim}.vibecheck/truthpack.json${c.reset} Routes, env, auth, billing truth
|
|
1166
|
+
${c.dim}.vibecheck/contracts/${c.reset} Contract definitions
|
|
1167
|
+
${c.dim}.cursor/rules/*.mdc${c.reset} Cursor IDE rules
|
|
1168
|
+
${c.dim}.windsurf/rules.md${c.reset} Windsurf IDE rules
|
|
1169
|
+
|
|
1170
|
+
${c.bold}Additional Files (--connect):${c.reset}
|
|
1171
|
+
${c.dim}.github/workflows/vibecheck.yml${c.reset} GitHub Actions workflow
|
|
1172
|
+
${c.dim}.github/workflows/vibecheck-pr.yml${c.reset} PR check workflow
|
|
1173
|
+
|
|
1174
|
+
${c.bold}Examples:${c.reset}
|
|
1175
|
+
${c.dim}# Full local setup (default)${c.reset}
|
|
1176
|
+
vibecheck init --local
|
|
1177
|
+
|
|
1178
|
+
${c.dim}# Local + GitHub integration${c.reset}
|
|
1179
|
+
vibecheck init --connect
|
|
1180
|
+
|
|
1181
|
+
${c.dim}# Quick setup${c.reset}
|
|
1182
|
+
vibecheck init --quick
|
|
1183
|
+
|
|
1184
|
+
${c.dim}# Enterprise with compliance${c.reset}
|
|
1185
|
+
vibecheck init --enterprise --soc2
|
|
1186
|
+
`);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1190
|
+
// ARGS PARSER
|
|
1191
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1192
|
+
|
|
1193
|
+
function parseArgs(args) {
|
|
1194
|
+
// Parse global flags first
|
|
1195
|
+
const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
|
|
1196
|
+
|
|
1197
|
+
const out = {
|
|
1198
|
+
path: globalFlags.path || ".",
|
|
1199
|
+
gitHooks: false,
|
|
1200
|
+
help: globalFlags.help || false,
|
|
1201
|
+
quick: false,
|
|
1202
|
+
json: globalFlags.json || false,
|
|
1203
|
+
verbose: globalFlags.verbose || false,
|
|
1204
|
+
noBanner: globalFlags.noBanner || false,
|
|
1205
|
+
ci: globalFlags.ci || false,
|
|
1206
|
+
quiet: globalFlags.quiet || false,
|
|
1207
|
+
// Mode flags (--local is default, --connect requires STARTER)
|
|
1208
|
+
local: false,
|
|
1209
|
+
connect: false,
|
|
1210
|
+
// Enhancement flags
|
|
1211
|
+
wizard: false,
|
|
1212
|
+
interactive: false,
|
|
1213
|
+
dryRun: false,
|
|
1214
|
+
repair: false,
|
|
1215
|
+
verify: false,
|
|
1216
|
+
// Enterprise options
|
|
1217
|
+
enterprise: false,
|
|
1218
|
+
compliance: false,
|
|
1219
|
+
team: false,
|
|
1220
|
+
mcp: false,
|
|
1221
|
+
strict: globalFlags.strict || false,
|
|
1222
|
+
failOnWarn: false,
|
|
1223
|
+
detect: false,
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
for (let i = 0; i < cleanArgs.length; i++) {
|
|
1227
|
+
const a = cleanArgs[i];
|
|
1228
|
+
if (a.startsWith("--path=")) out.path = a.split("=")[1];
|
|
1229
|
+
if (a === "--path" || a === "-p") out.path = cleanArgs[++i];
|
|
1230
|
+
if (a === "--git-hooks") out.gitHooks = true;
|
|
1231
|
+
if (a === "--quick" || a === "-q") out.quick = true;
|
|
1232
|
+
if (a === "--verify") out.verify = true;
|
|
1233
|
+
|
|
1234
|
+
// Enhancement flags
|
|
1235
|
+
if (a === "--wizard" || a === "--interactive" || a === "-i") {
|
|
1236
|
+
out.wizard = true;
|
|
1237
|
+
out.interactive = true;
|
|
1238
|
+
}
|
|
1239
|
+
if (a === "--dry-run" || a === "--dryrun") out.dryRun = true;
|
|
1240
|
+
if (a === "--repair") out.repair = true;
|
|
1241
|
+
|
|
1242
|
+
// Mode flags
|
|
1243
|
+
if (a === "--local" || a === "-l") out.local = true;
|
|
1244
|
+
if (a === "--connect" || a === "-c") out.connect = true;
|
|
1245
|
+
|
|
1246
|
+
// Enterprise flags
|
|
1247
|
+
if (a === "--enterprise" || a === "-e") out.enterprise = true;
|
|
1248
|
+
if (a === "--ci") {
|
|
1249
|
+
const next = args[i + 1];
|
|
1250
|
+
if (next && !next.startsWith("-")) {
|
|
1251
|
+
out.ci = args[++i];
|
|
1252
|
+
} else {
|
|
1253
|
+
out.ci = true;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (a === "--gha" || a === "--github-actions") out.ci = "github";
|
|
1257
|
+
if (a === "--gitlab") out.ci = "gitlab";
|
|
1258
|
+
if (a === "--compliance") {
|
|
1259
|
+
const next = args[i + 1];
|
|
1260
|
+
if (next && !next.startsWith("-")) {
|
|
1261
|
+
out.compliance = args[++i];
|
|
1262
|
+
} else {
|
|
1263
|
+
out.compliance = true;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
if (a === "--soc2") out.compliance = "soc2";
|
|
1267
|
+
if (a === "--hipaa") out.compliance = "hipaa";
|
|
1268
|
+
if (a === "--gdpr") out.compliance = "gdpr";
|
|
1269
|
+
if (a === "--pci") out.compliance = "pci";
|
|
1270
|
+
if (a === "--team") out.team = true;
|
|
1271
|
+
if (a === "--mcp") out.mcp = true;
|
|
1272
|
+
if (a === "--strict") out.strict = true;
|
|
1273
|
+
if (a === "--fail-on-warn") out.failOnWarn = true;
|
|
1274
|
+
if (a === "--detect") out.detect = true;
|
|
1275
|
+
if (a === "--full") {
|
|
1276
|
+
out.enterprise = true;
|
|
1277
|
+
out.ci = true;
|
|
1278
|
+
out.team = true;
|
|
1279
|
+
out.mcp = true;
|
|
1280
|
+
out.connect = true;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// Default to --local if neither mode specified
|
|
1285
|
+
if (!out.local && !out.connect) {
|
|
1286
|
+
out.local = true;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
return out;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1293
|
+
// MAIN INIT FUNCTION
|
|
1294
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1295
|
+
|
|
1296
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1297
|
+
// LOCAL MODE SETUP - Full local initialization
|
|
1298
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1299
|
+
|
|
1300
|
+
async function runLocalSetup(targetDir, projectName, opts, filesCreated) {
|
|
1301
|
+
printSection('LOCAL SETUP', ICONS.setup);
|
|
1302
|
+
console.log();
|
|
1303
|
+
|
|
1304
|
+
const totalSteps = 7; // Approximate number of major steps
|
|
1305
|
+
let currentStep = 0;
|
|
1306
|
+
|
|
1307
|
+
function logStep(stepName) {
|
|
1308
|
+
currentStep++;
|
|
1309
|
+
if (opts.verbose && !opts.json) {
|
|
1310
|
+
console.log(` ${c.dim}[${currentStep}/${totalSteps}]${c.reset} ${stepName}`);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// Detect framework for framework-specific templates
|
|
1315
|
+
let detection = null;
|
|
1316
|
+
if (!opts.dryRun) {
|
|
1317
|
+
try {
|
|
1318
|
+
const { detectAll } = require("./lib/enterprise-detect");
|
|
1319
|
+
detection = detectAll(targetDir);
|
|
1320
|
+
if (!opts.json) {
|
|
1321
|
+
printEnhancedDetection(detection, opts.verbose);
|
|
1322
|
+
}
|
|
1323
|
+
} catch (e) {
|
|
1324
|
+
if (!opts.json) {
|
|
1325
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} Detection failed: ${e.message}`);
|
|
1326
|
+
if (opts.verbose) {
|
|
1327
|
+
console.log(` ${c.dim}Stack: ${e.stack}${c.reset}`);
|
|
1328
|
+
}
|
|
1329
|
+
console.log(` ${c.dim}Using default configuration${c.reset}`);
|
|
1330
|
+
console.log();
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
const vibecheckDir = path.join(targetDir, ".vibecheck");
|
|
1336
|
+
|
|
1337
|
+
// 1. Create .vibecheck/ directory structure
|
|
1338
|
+
logStep('Creating directory structure');
|
|
1339
|
+
const dirs = [
|
|
1340
|
+
vibecheckDir,
|
|
1341
|
+
path.join(vibecheckDir, "results"),
|
|
1342
|
+
path.join(vibecheckDir, "reports"),
|
|
1343
|
+
path.join(vibecheckDir, "contracts"),
|
|
1344
|
+
path.join(vibecheckDir, "missions"),
|
|
1345
|
+
path.join(vibecheckDir, "checkpoints"),
|
|
1346
|
+
path.join(vibecheckDir, "runs"),
|
|
1347
|
+
];
|
|
1348
|
+
|
|
1349
|
+
for (const dir of dirs) {
|
|
1350
|
+
if (!fs.existsSync(dir)) {
|
|
1351
|
+
if (opts.dryRun) {
|
|
1352
|
+
printSetupStep(path.relative(targetDir, dir), 'dry-run', 'would create');
|
|
1353
|
+
} else {
|
|
1354
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (!opts.dryRun) {
|
|
1359
|
+
printSetupStep('.vibecheck/', 'success', 'directory structure created');
|
|
1360
|
+
filesCreated.push('.vibecheck/');
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// 2. Create config.json with framework-specific settings
|
|
1364
|
+
logStep('Creating configuration');
|
|
1365
|
+
const configPath = path.join(vibecheckDir, "config.json");
|
|
1366
|
+
if (!fs.existsSync(configPath) || opts.dryRun) {
|
|
1367
|
+
const frameworkConfig = getFrameworkConfig(detection);
|
|
1368
|
+
const config = {
|
|
1369
|
+
version: "2.0.0",
|
|
1370
|
+
project: projectName,
|
|
1371
|
+
createdAt: new Date().toISOString(),
|
|
1372
|
+
framework: frameworkConfig.framework || "node",
|
|
1373
|
+
checks: frameworkConfig.checks || ["routes", "env", "auth", "security"],
|
|
1374
|
+
output: ".vibecheck",
|
|
1375
|
+
policy: {
|
|
1376
|
+
allowlist: { domains: [], packages: [] },
|
|
1377
|
+
ignore: {
|
|
1378
|
+
paths: [
|
|
1379
|
+
"node_modules",
|
|
1380
|
+
"__tests__",
|
|
1381
|
+
"*.test.*",
|
|
1382
|
+
"*.spec.*",
|
|
1383
|
+
...(frameworkConfig.ignorePaths || [])
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
},
|
|
1387
|
+
thresholds: {
|
|
1388
|
+
minScore: 70,
|
|
1389
|
+
maxBlockers: 0,
|
|
1390
|
+
maxWarnings: 10,
|
|
1391
|
+
},
|
|
1392
|
+
...(frameworkConfig.extra || {}),
|
|
1393
|
+
};
|
|
1394
|
+
|
|
1395
|
+
if (opts.dryRun) {
|
|
1396
|
+
printSetupStep('config.json', 'dry-run', `would create (framework: ${config.framework})`);
|
|
1397
|
+
console.log(` ${c.dim}Config preview:${c.reset}`);
|
|
1398
|
+
console.log(JSON.stringify(config, null, 2));
|
|
1399
|
+
} else {
|
|
1400
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1401
|
+
printSetupStep('config.json', 'success', `configuration created (framework: ${config.framework})`);
|
|
1402
|
+
filesCreated.push('.vibecheck/config.json');
|
|
1403
|
+
}
|
|
1404
|
+
} else {
|
|
1405
|
+
printSetupStep('config.json', 'exists', 'already exists');
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// 3. Generate truthpack
|
|
1409
|
+
logStep('Generating truthpack');
|
|
1410
|
+
if (!opts.dryRun) {
|
|
1411
|
+
startSpinner('Building truthpack...', colors.accent);
|
|
1412
|
+
try {
|
|
1413
|
+
const { runContext } = require("./runContext");
|
|
1414
|
+
await runContext(["--path", targetDir, "--quiet"]);
|
|
1415
|
+
stopSpinner('Truthpack generated', true);
|
|
1416
|
+
filesCreated.push('.vibecheck/truthpack.json');
|
|
1417
|
+
} catch (e) {
|
|
1418
|
+
stopSpinner('Truthpack generation failed', false);
|
|
1419
|
+
// Don't throw - truthpack generation is optional for init
|
|
1420
|
+
if (!opts.json) {
|
|
1421
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${e.message}`);
|
|
1422
|
+
console.log(` ${c.dim}Run 'vibecheck context' manually to generate truthpack${c.reset}`);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
} else {
|
|
1426
|
+
printSetupStep('truthpack.json', 'dry-run', 'would generate via vibecheck ctx build');
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// 4. Generate contracts
|
|
1430
|
+
logStep('Creating contracts');
|
|
1431
|
+
const contractsDir = path.join(vibecheckDir, "contracts");
|
|
1432
|
+
|
|
1433
|
+
// Routes contract
|
|
1434
|
+
const routeContractPath = path.join(contractsDir, "routes.contract.json");
|
|
1435
|
+
if (!fs.existsSync(routeContractPath)) {
|
|
1436
|
+
const routeContract = {
|
|
1437
|
+
version: "1.0.0",
|
|
1438
|
+
generatedAt: new Date().toISOString(),
|
|
1439
|
+
routes: [],
|
|
1440
|
+
description: "Route contract - populated by scan",
|
|
1441
|
+
};
|
|
1442
|
+
if (opts.dryRun) {
|
|
1443
|
+
printSetupStep('routes.contract.json', 'dry-run', 'would create');
|
|
1444
|
+
} else {
|
|
1445
|
+
fs.writeFileSync(routeContractPath, JSON.stringify(routeContract, null, 2));
|
|
1446
|
+
printSetupStep('routes.contract.json', 'success', 'route contract created');
|
|
1447
|
+
filesCreated.push('.vibecheck/contracts/routes.contract.json');
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
// Env contract
|
|
1452
|
+
const envContractPath = path.join(contractsDir, "env.contract.json");
|
|
1453
|
+
if (!fs.existsSync(envContractPath)) {
|
|
1454
|
+
const envContract = {
|
|
1455
|
+
version: "1.0.0",
|
|
1456
|
+
generatedAt: new Date().toISOString(),
|
|
1457
|
+
required: [],
|
|
1458
|
+
optional: [],
|
|
1459
|
+
description: "Environment contract - populated by scan",
|
|
1460
|
+
};
|
|
1461
|
+
if (opts.dryRun) {
|
|
1462
|
+
printSetupStep('env.contract.json', 'dry-run', 'would create');
|
|
1463
|
+
} else {
|
|
1464
|
+
fs.writeFileSync(envContractPath, JSON.stringify(envContract, null, 2));
|
|
1465
|
+
printSetupStep('env.contract.json', 'success', 'env contract created');
|
|
1466
|
+
filesCreated.push('.vibecheck/contracts/env.contract.json');
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
// 5. Generate IDE rules (MDC for Cursor, rules for others)
|
|
1471
|
+
logStep('Generating IDE rules');
|
|
1472
|
+
if (!opts.dryRun) {
|
|
1473
|
+
startSpinner('Generating IDE rules...', colors.accent);
|
|
1474
|
+
try {
|
|
1475
|
+
const { runContext } = require("./runContext");
|
|
1476
|
+
await runContext(["--path", targetDir, "--quiet"]);
|
|
1477
|
+
stopSpinner('IDE rules generated', true);
|
|
1478
|
+
filesCreated.push('.cursor/rules/', '.windsurf/', '.github/copilot-instructions.md');
|
|
1479
|
+
} catch (e) {
|
|
1480
|
+
stopSpinner('IDE rules generation failed', false);
|
|
1481
|
+
if (!opts.json) {
|
|
1482
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${e.message}`);
|
|
1483
|
+
console.log(` ${c.dim}Run 'vibecheck context' manually to generate IDE rules${c.reset}`);
|
|
1484
|
+
}
|
|
1485
|
+
// Don't throw - IDE rules are optional
|
|
1486
|
+
}
|
|
1487
|
+
} else {
|
|
1488
|
+
printSetupStep('IDE rules', 'dry-run', 'would generate via vibecheck context');
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
// 6. Create .vibecheckrc at project root (create both for compatibility)
|
|
1492
|
+
logStep('Creating root config');
|
|
1493
|
+
const rcPathJson = path.join(targetDir, ".vibecheckrc.json");
|
|
1494
|
+
const rcPath = path.join(targetDir, ".vibecheckrc");
|
|
1495
|
+
const rc = {
|
|
1496
|
+
extends: ".vibecheck/config.json",
|
|
1497
|
+
tier: "free",
|
|
1498
|
+
};
|
|
1499
|
+
|
|
1500
|
+
if (!fs.existsSync(rcPathJson) && !fs.existsSync(rcPath)) {
|
|
1501
|
+
if (opts.dryRun) {
|
|
1502
|
+
printSetupStep('.vibecheckrc', 'dry-run', 'would create');
|
|
1503
|
+
printSetupStep('.vibecheckrc.json', 'dry-run', 'would create');
|
|
1504
|
+
} else {
|
|
1505
|
+
// Create .vibecheckrc (without .json) for compatibility with tests/expectations
|
|
1506
|
+
fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2));
|
|
1507
|
+
printSetupStep('.vibecheckrc', 'success', 'root config created');
|
|
1508
|
+
filesCreated.push('.vibecheckrc');
|
|
1509
|
+
|
|
1510
|
+
// Also create .vibecheckrc.json for backward compatibility
|
|
1511
|
+
fs.writeFileSync(rcPathJson, JSON.stringify(rc, null, 2));
|
|
1512
|
+
filesCreated.push('.vibecheckrc.json');
|
|
1513
|
+
}
|
|
1514
|
+
} else if (fs.existsSync(rcPathJson) && !fs.existsSync(rcPath)) {
|
|
1515
|
+
// If only .vibecheckrc.json exists, create .vibecheckrc for compatibility
|
|
1516
|
+
if (!opts.dryRun) {
|
|
1517
|
+
fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2));
|
|
1518
|
+
printSetupStep('.vibecheckrc', 'success', 'root config created (compatibility)');
|
|
1519
|
+
filesCreated.push('.vibecheckrc');
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// 7. Update .gitignore
|
|
1524
|
+
logStep('Updating .gitignore');
|
|
1525
|
+
const gitignorePath = path.join(targetDir, ".gitignore");
|
|
1526
|
+
if (fs.existsSync(gitignorePath)) {
|
|
1527
|
+
let gitignore = fs.readFileSync(gitignorePath, "utf-8");
|
|
1528
|
+
const additions = [];
|
|
1529
|
+
if (!gitignore.includes(".vibecheck/results/")) additions.push(".vibecheck/results/");
|
|
1530
|
+
if (!gitignore.includes(".vibecheck/runs/")) additions.push(".vibecheck/runs/");
|
|
1531
|
+
if (!gitignore.includes(".vibecheck/checkpoints/")) additions.push(".vibecheck/checkpoints/");
|
|
1532
|
+
|
|
1533
|
+
if (additions.length > 0) {
|
|
1534
|
+
if (opts.dryRun) {
|
|
1535
|
+
printSetupStep('.gitignore', 'dry-run', `would add: ${additions.join(', ')}`);
|
|
1536
|
+
} else {
|
|
1537
|
+
gitignore += `\n# vibecheck (generated outputs)\n${additions.join("\n")}\n`;
|
|
1538
|
+
fs.writeFileSync(gitignorePath, gitignore);
|
|
1539
|
+
printSetupStep('.gitignore', 'success', 'updated with vibecheck paths');
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// Return both filesCreated and detection for use in main function
|
|
1545
|
+
return { filesCreated, detection };
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1549
|
+
// CONNECT MODE SETUP - GitHub integration
|
|
1550
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1551
|
+
|
|
1552
|
+
async function runConnectSetup(targetDir, projectName, opts, filesCreated) {
|
|
1553
|
+
// Check entitlement
|
|
1554
|
+
const entitlements = require("./lib/entitlements-v2");
|
|
1555
|
+
const access = await entitlements.enforce("init.connect", { silent: true });
|
|
1556
|
+
|
|
1557
|
+
if (!access.allowed) {
|
|
1558
|
+
console.log();
|
|
1559
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}--connect requires STARTER plan${c.reset}`);
|
|
1560
|
+
console.log(` ${c.dim}Upgrade at: https://vibecheckai.dev/pricing${c.reset}`);
|
|
1561
|
+
console.log();
|
|
1562
|
+
console.log(` ${c.dim}Local setup completed. Run 'vibecheck init --connect' after upgrading.${c.reset}`);
|
|
1563
|
+
return filesCreated;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
printSection('GITHUB INTEGRATION', ICONS.ci);
|
|
1567
|
+
console.log();
|
|
1568
|
+
|
|
1569
|
+
// 1. Create GitHub workflows directory
|
|
1570
|
+
const workflowsDir = path.join(targetDir, ".github", "workflows");
|
|
1571
|
+
if (!fs.existsSync(workflowsDir)) {
|
|
1572
|
+
fs.mkdirSync(workflowsDir, { recursive: true });
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// 2. Copy main workflow template
|
|
1576
|
+
const mainWorkflowPath = path.join(workflowsDir, "vibecheck.yml");
|
|
1577
|
+
if (!fs.existsSync(mainWorkflowPath)) {
|
|
1578
|
+
// Read template
|
|
1579
|
+
const templatePath = path.join(__dirname, "..", "..", "templates", "github-actions", "vibecheck.yml");
|
|
1580
|
+
if (fs.existsSync(templatePath)) {
|
|
1581
|
+
fs.copyFileSync(templatePath, mainWorkflowPath);
|
|
1582
|
+
printSetupStep('vibecheck.yml', 'success', 'main workflow created');
|
|
1583
|
+
filesCreated.push('.github/workflows/vibecheck.yml');
|
|
1584
|
+
} else {
|
|
1585
|
+
// Inline template as fallback
|
|
1586
|
+
const workflow = `# Vibecheck CI/CD Workflow
|
|
1587
|
+
name: Vibecheck
|
|
1588
|
+
on:
|
|
1589
|
+
push:
|
|
1590
|
+
branches: [main, master]
|
|
1591
|
+
pull_request:
|
|
1592
|
+
|
|
1593
|
+
jobs:
|
|
1594
|
+
vibecheck:
|
|
1595
|
+
runs-on: ubuntu-latest
|
|
1596
|
+
steps:
|
|
1597
|
+
- uses: actions/checkout@v4
|
|
1598
|
+
- uses: actions/setup-node@v4
|
|
1599
|
+
with:
|
|
1600
|
+
node-version: '20'
|
|
1601
|
+
- run: npm ci
|
|
1602
|
+
- run: npx vibecheck scan --json > .vibecheck/results/scan.json
|
|
1603
|
+
- run: npx vibecheck ship --ci
|
|
1604
|
+
`;
|
|
1605
|
+
fs.writeFileSync(mainWorkflowPath, workflow);
|
|
1606
|
+
printSetupStep('vibecheck.yml', 'success', 'main workflow created');
|
|
1607
|
+
filesCreated.push('.github/workflows/vibecheck.yml');
|
|
1608
|
+
}
|
|
1609
|
+
} else {
|
|
1610
|
+
printSetupStep('vibecheck.yml', 'exists', 'already exists');
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// 3. Copy PR workflow template
|
|
1614
|
+
const prWorkflowPath = path.join(workflowsDir, "vibecheck-pr.yml");
|
|
1615
|
+
if (!fs.existsSync(prWorkflowPath)) {
|
|
1616
|
+
const templatePath = path.join(__dirname, "..", "..", "templates", "github-actions", "vibecheck-pr.yml");
|
|
1617
|
+
if (fs.existsSync(templatePath)) {
|
|
1618
|
+
fs.copyFileSync(templatePath, prWorkflowPath);
|
|
1619
|
+
printSetupStep('vibecheck-pr.yml', 'success', 'PR workflow created');
|
|
1620
|
+
filesCreated.push('.github/workflows/vibecheck-pr.yml');
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// 4. Provide setup instructions
|
|
1625
|
+
console.log();
|
|
1626
|
+
console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}GitHub Setup Required:${c.reset}`);
|
|
1627
|
+
console.log(` 1. Add ${c.cyan}VIBECHECK_API_KEY${c.reset} to repository secrets`);
|
|
1628
|
+
console.log(` 2. Push to trigger first workflow run`);
|
|
1629
|
+
console.log();
|
|
1630
|
+
|
|
1631
|
+
return filesCreated;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1635
|
+
// MAIN INIT FUNCTION
|
|
1636
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1637
|
+
|
|
1638
|
+
async function runInit(args) {
|
|
1639
|
+
const opts = parseArgs(args);
|
|
1640
|
+
|
|
1641
|
+
if (opts.help) {
|
|
1642
|
+
printHelp(shouldShowBanner(opts));
|
|
1643
|
+
return 0;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// --quick mode runs local setup with non-interactive defaults
|
|
1647
|
+
if (opts.quick) {
|
|
1648
|
+
opts.local = true;
|
|
1649
|
+
opts.nonInteractive = true;
|
|
1650
|
+
// Continue with normal init flow below
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
const targetDir = path.resolve(opts.path);
|
|
1654
|
+
const projectName = path.basename(targetDir);
|
|
1655
|
+
let bannerPrinted = false;
|
|
1656
|
+
|
|
1657
|
+
// Enterprise mode - comprehensive setup
|
|
1658
|
+
const useEnterprise = opts.enterprise || opts.ci || opts.compliance ||
|
|
1659
|
+
opts.team || opts.mcp || opts.detect;
|
|
1660
|
+
|
|
1661
|
+
if (EnterpriseInit && useEnterprise && !opts.local && !opts.connect) {
|
|
1662
|
+
if (shouldShowBanner(opts)) {
|
|
1663
|
+
printBanner();
|
|
1664
|
+
bannerPrinted = true;
|
|
1665
|
+
printEnterpriseHeader(opts);
|
|
1666
|
+
|
|
1667
|
+
console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
|
|
1668
|
+
console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
|
|
1669
|
+
console.log();
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
const enterprise = new EnterpriseInit(targetDir, opts);
|
|
1673
|
+
return await enterprise.run();
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// Detect-only mode (quick detection report)
|
|
1677
|
+
if (opts.detect) {
|
|
1678
|
+
if (shouldShowBanner(opts)) {
|
|
1679
|
+
printBanner();
|
|
1680
|
+
bannerPrinted = true;
|
|
1681
|
+
console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
|
|
1682
|
+
console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
startSpinner('Detecting project configuration...', colors.accent);
|
|
1686
|
+
|
|
1687
|
+
try {
|
|
1688
|
+
const { detectAll } = require("./lib/enterprise-detect");
|
|
1689
|
+
const detection = detectAll(targetDir);
|
|
1690
|
+
stopSpinner('Detection complete', true);
|
|
1691
|
+
if (!opts.json) {
|
|
1692
|
+
printDetectionResults(detection);
|
|
1693
|
+
console.log();
|
|
1694
|
+
console.log(` ${c.dim}Full JSON output:${c.reset}`);
|
|
1695
|
+
}
|
|
1696
|
+
console.log(JSON.stringify(detection, null, 2));
|
|
1697
|
+
} catch (e) {
|
|
1698
|
+
stopSpinner('Detection failed', false);
|
|
1699
|
+
console.log(` ${colors.error}Error:${c.reset} ${e.message}`);
|
|
1700
|
+
}
|
|
1701
|
+
return 0;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1705
|
+
// NEW: --local and --connect modes
|
|
1706
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1707
|
+
|
|
1708
|
+
// Interactive wizard mode
|
|
1709
|
+
if (opts.wizard && InitWizard) {
|
|
1710
|
+
if (shouldShowBanner(opts) && !bannerPrinted) {
|
|
1711
|
+
printBanner();
|
|
1712
|
+
bannerPrinted = true;
|
|
1713
|
+
}
|
|
1714
|
+
const wizard = new InitWizard(targetDir, opts);
|
|
1715
|
+
return await wizard.run();
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
// Repair mode - fix partial state
|
|
1719
|
+
if (opts.repair) {
|
|
1720
|
+
if (shouldShowBanner(opts) && !bannerPrinted) {
|
|
1721
|
+
printBanner();
|
|
1722
|
+
bannerPrinted = true;
|
|
1723
|
+
console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
|
|
1724
|
+
console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
|
|
1725
|
+
console.log(` ${c.dim}Mode:${c.reset} ${colors.accent}Repair${c.reset}`);
|
|
1726
|
+
console.log();
|
|
1727
|
+
}
|
|
1728
|
+
return await runRepairMode(targetDir, projectName, opts);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// Print banner only once (not already printed in enterprise/detect modes)
|
|
1732
|
+
if (shouldShowBanner(opts) && !bannerPrinted) {
|
|
1733
|
+
printBanner();
|
|
1734
|
+
bannerPrinted = true;
|
|
1735
|
+
|
|
1736
|
+
const mode = opts.connect ? 'Local + Connect' : 'Local';
|
|
1737
|
+
const tierBadge = opts.connect ? `${c.cyan}[STARTER]${c.reset}` : `${c.green}[FREE]${c.reset}`;
|
|
1738
|
+
|
|
1739
|
+
console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
|
|
1740
|
+
console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
|
|
1741
|
+
console.log(` ${c.dim}Mode:${c.reset} ${colors.accent}${mode}${c.reset} ${tierBadge}`);
|
|
1742
|
+
if (opts.dryRun) {
|
|
1743
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}DRY-RUN MODE${c.reset} - No files will be created`);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
let filesCreated = [];
|
|
1748
|
+
let detection = null; // Declare detection in main function scope
|
|
1749
|
+
const result = {
|
|
1750
|
+
success: true,
|
|
1751
|
+
project: projectName,
|
|
1752
|
+
path: targetDir,
|
|
1753
|
+
mode: opts.connect ? 'connect' : 'local',
|
|
1754
|
+
filesCreated: [],
|
|
1755
|
+
errors: [],
|
|
1756
|
+
dryRun: opts.dryRun,
|
|
1757
|
+
};
|
|
1758
|
+
|
|
1759
|
+
// Always run local setup first
|
|
1760
|
+
if (opts.local || opts.connect) {
|
|
1761
|
+
try {
|
|
1762
|
+
// runLocalSetup returns both filesCreated and detection
|
|
1763
|
+
const setupResult = await runLocalSetup(targetDir, projectName, opts, filesCreated);
|
|
1764
|
+
if (setupResult && typeof setupResult === 'object' && 'filesCreated' in setupResult) {
|
|
1765
|
+
filesCreated = setupResult.filesCreated;
|
|
1766
|
+
detection = setupResult.detection || null;
|
|
1767
|
+
} else {
|
|
1768
|
+
// Backward compatibility: if it returns just an array, use it
|
|
1769
|
+
filesCreated = Array.isArray(setupResult) ? setupResult : filesCreated;
|
|
1770
|
+
}
|
|
1771
|
+
} catch (e) {
|
|
1772
|
+
result.errors.push({ step: 'local', error: e.message, stack: e.stack });
|
|
1773
|
+
if (!opts.json) {
|
|
1774
|
+
console.log(` ${colors.error}${ICONS.cross}${c.reset} Local setup error: ${e.message}`);
|
|
1775
|
+
if (opts.verbose) {
|
|
1776
|
+
console.log(` ${c.dim}Stack: ${e.stack}${c.reset}`);
|
|
1777
|
+
}
|
|
1778
|
+
console.log(` ${colors.info}${ICONS.info}${c.reset} Run ${c.cyan}vibecheck init --repair${c.reset} to fix partial state`);
|
|
1779
|
+
}
|
|
1780
|
+
// Don't exit on error - continue and report errors in result
|
|
1781
|
+
// Only exit if critical setup failed AND we're not in dry-run mode
|
|
1782
|
+
if (!opts.dryRun && result.errors.length > 0 && filesCreated.length === 0) {
|
|
1783
|
+
// Only exit if NO files were created at all (complete failure)
|
|
1784
|
+
return EXIT.INTERNAL_ERROR;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
// Run connect setup if requested
|
|
1790
|
+
if (opts.connect) {
|
|
1791
|
+
try {
|
|
1792
|
+
filesCreated = await runConnectSetup(targetDir, projectName, opts, filesCreated);
|
|
1793
|
+
} catch (e) {
|
|
1794
|
+
result.errors.push({ step: 'connect', error: e.message, stack: e.stack });
|
|
1795
|
+
if (!opts.json) {
|
|
1796
|
+
console.log(` ${colors.error}${ICONS.cross}${c.reset} Connect setup error: ${e.message}`);
|
|
1797
|
+
if (opts.verbose) {
|
|
1798
|
+
console.log(` ${c.dim}Stack: ${e.stack}${c.reset}`);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
if (!opts.dryRun) {
|
|
1802
|
+
return EXIT.INTERNAL_ERROR;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// Git hooks if requested
|
|
1808
|
+
if (opts.gitHooks) {
|
|
1809
|
+
const huskyDir = path.join(targetDir, ".husky");
|
|
1810
|
+
if (!fs.existsSync(huskyDir)) {
|
|
1811
|
+
fs.mkdirSync(huskyDir, { recursive: true });
|
|
1812
|
+
}
|
|
1813
|
+
const prePushHook = `#!/usr/bin/env sh
|
|
1814
|
+
. "$(dirname -- "$0")/_/husky.sh"
|
|
1815
|
+
|
|
1816
|
+
echo "🚦 Running vibecheck gate..."
|
|
1817
|
+
npx vibecheck ship --ci
|
|
1818
|
+
|
|
1819
|
+
if [ $? -ne 0 ]; then
|
|
1820
|
+
echo "❌ Push blocked: Gate failed!"
|
|
1821
|
+
exit 1
|
|
1822
|
+
fi
|
|
1823
|
+
`;
|
|
1824
|
+
fs.writeFileSync(path.join(huskyDir, "pre-push"), prePushHook, { mode: 0o755 });
|
|
1825
|
+
if (!opts.json) {
|
|
1826
|
+
printSetupStep('.husky/pre-push', 'success', 'git hook installed');
|
|
1827
|
+
}
|
|
1828
|
+
filesCreated.push('.husky/pre-push');
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
result.filesCreated = filesCreated;
|
|
1832
|
+
|
|
1833
|
+
// JSON output
|
|
1834
|
+
if (opts.json) {
|
|
1835
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1836
|
+
return result.errors.length > 0 ? 1 : 0;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// Success card
|
|
1840
|
+
const mode = opts.connect ? 'Local + Connect' : 'Local Setup';
|
|
1841
|
+
printSuccessCard(projectName, mode, filesCreated.length);
|
|
1842
|
+
|
|
1843
|
+
// Generate dependency graph
|
|
1844
|
+
if (!opts.dryRun) {
|
|
1845
|
+
if (!opts.json) {
|
|
1846
|
+
startSpinner('Generating dependency graph...', colors.accent);
|
|
1847
|
+
}
|
|
1848
|
+
try {
|
|
1849
|
+
const { buildDependencyGraph, generateHtmlVisualization } = require("./context/dependency-graph");
|
|
1850
|
+
const depGraph = buildDependencyGraph(targetDir);
|
|
1851
|
+
const htmlViz = generateHtmlVisualization(depGraph, { maxNodes: 200 });
|
|
1852
|
+
const graphPath = path.join(targetDir, ".vibecheck", "dependency-graph.html");
|
|
1853
|
+
fs.writeFileSync(graphPath, htmlViz);
|
|
1854
|
+
filesCreated.push('.vibecheck/dependency-graph.html');
|
|
1855
|
+
if (!opts.json) {
|
|
1856
|
+
stopSpinner('Dependency graph generated', true);
|
|
1857
|
+
}
|
|
1858
|
+
} catch (e) {
|
|
1859
|
+
if (!opts.json) {
|
|
1860
|
+
stopSpinner('Dependency graph skipped', false);
|
|
1861
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${e.message}`);
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
} else {
|
|
1865
|
+
printSetupStep('dependency-graph.html', 'dry-run', 'would generate');
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
// Init summary
|
|
1869
|
+
printSection('INIT SUMMARY', ICONS.check);
|
|
1870
|
+
console.log();
|
|
1871
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} .vibecheck/ structure created`);
|
|
1872
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} Truthpack generated`);
|
|
1873
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} Contracts initialized`);
|
|
1874
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} IDE rules generated`);
|
|
1875
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} Dependency graph generated`);
|
|
1876
|
+
if (opts.connect) {
|
|
1877
|
+
console.log(` ${colors.success}${ICONS.check}${c.reset} GitHub Actions workflows installed`);
|
|
1878
|
+
}
|
|
1879
|
+
console.log();
|
|
1880
|
+
|
|
1881
|
+
// Show dependency graph location
|
|
1882
|
+
const graphPath = path.join(targetDir, ".vibecheck", "dependency-graph.html");
|
|
1883
|
+
if (fs.existsSync(graphPath)) {
|
|
1884
|
+
console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}Dependency Graph:${c.reset}`);
|
|
1885
|
+
console.log(` ${c.cyan}file://${graphPath.replace(/\\/g, '/')}${c.reset}`);
|
|
1886
|
+
console.log();
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
// Save init state for repair mode
|
|
1890
|
+
if (!opts.dryRun) {
|
|
1891
|
+
saveInitState(targetDir, {
|
|
1892
|
+
timestamp: new Date().toISOString(),
|
|
1893
|
+
mode: opts.connect ? 'connect' : 'local',
|
|
1894
|
+
filesCreated,
|
|
1895
|
+
errors: result.errors,
|
|
1896
|
+
detection: detection ? {
|
|
1897
|
+
frameworks: Object.keys(detection.frameworks || {}).filter(k => detection.frameworks[k].detected),
|
|
1898
|
+
checks: detection.checks || [],
|
|
1899
|
+
} : null,
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
// Post-init validation
|
|
1904
|
+
if (opts.verify && !opts.dryRun) {
|
|
1905
|
+
const validationResult = await verifyInitSetup(targetDir, opts);
|
|
1906
|
+
if (!validationResult.success && !opts.json) {
|
|
1907
|
+
console.log();
|
|
1908
|
+
console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}Validation Issues Found:${c.reset}`);
|
|
1909
|
+
for (const issue of validationResult.issues) {
|
|
1910
|
+
console.log(` ${c.dim}•${c.reset} ${issue}`);
|
|
1911
|
+
}
|
|
1912
|
+
console.log();
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// Framework-specific recommendations
|
|
1917
|
+
if (detection && !opts.json && !opts.dryRun) {
|
|
1918
|
+
printFrameworkRecommendations(detection, opts);
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// Next steps
|
|
1922
|
+
printNextSteps({ hasCI: opts.connect, mode: opts.connect ? 'connect' : 'local' });
|
|
1923
|
+
|
|
1924
|
+
return 0;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
module.exports = { runInit };
|