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,2089 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibecheck packs - Unified Artifact Factory V2
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* ENTERPRISE-GRADE ARTIFACT BUNDLING
|
|
6
|
+
* "One command to produce a ZIP bundle + manifest + HTML index"
|
|
7
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
8
|
+
*
|
|
9
|
+
* Consolidates all artifact generation into a single command:
|
|
10
|
+
*
|
|
11
|
+
* • EVIDENCE - Videos, traces, screenshots, HAR files
|
|
12
|
+
* • PERMISSIONS - AuthZ matrix, role-based permission mapping
|
|
13
|
+
* • PROOF-GRAPH - Verification coverage and proof chains
|
|
14
|
+
* • REPORTS - HTML, Markdown, SARIF, CSV, PDF
|
|
15
|
+
* • BUNDLE - All-in-one shareable evidence bundle (V2)
|
|
16
|
+
*
|
|
17
|
+
* V2 Features:
|
|
18
|
+
* - Stable naming scheme, reproducible builds
|
|
19
|
+
* - Cross-links to ship/reality/shield receipts
|
|
20
|
+
* - Unified manifest schema with build fingerprints
|
|
21
|
+
* - HTML index for all packs
|
|
22
|
+
*
|
|
23
|
+
* @module runPacks
|
|
24
|
+
* @version 5.0.0
|
|
25
|
+
* @license MIT
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
"use strict";
|
|
29
|
+
|
|
30
|
+
const path = require("path");
|
|
31
|
+
const fs = require("fs");
|
|
32
|
+
const crypto = require("crypto");
|
|
33
|
+
|
|
34
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
35
|
+
// LAZY IMPORTS
|
|
36
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
37
|
+
|
|
38
|
+
let _globalFlags = null;
|
|
39
|
+
let _exitCodes = null;
|
|
40
|
+
let _cliOutput = null;
|
|
41
|
+
|
|
42
|
+
function getGlobalFlags() {
|
|
43
|
+
if (!_globalFlags) {
|
|
44
|
+
_globalFlags = require("./lib/global-flags");
|
|
45
|
+
}
|
|
46
|
+
return _globalFlags;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getExitCodes() {
|
|
50
|
+
if (!_exitCodes) {
|
|
51
|
+
_exitCodes = require("./lib/exit-codes");
|
|
52
|
+
}
|
|
53
|
+
return _exitCodes;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getCliOutput() {
|
|
57
|
+
if (!_cliOutput) {
|
|
58
|
+
_cliOutput = require("./lib/unified-cli-output");
|
|
59
|
+
}
|
|
60
|
+
return _cliOutput;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
64
|
+
// UNDERLYING IMPLEMENTATIONS
|
|
65
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
66
|
+
|
|
67
|
+
const implementations = {
|
|
68
|
+
evidencePack: null,
|
|
69
|
+
report: null,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
function loadImplementation(name) {
|
|
73
|
+
if (implementations[name] !== null) return implementations[name];
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
switch (name) {
|
|
77
|
+
case "evidencePack":
|
|
78
|
+
implementations[name] = require("./runEvidencePack").runEvidencePack;
|
|
79
|
+
break;
|
|
80
|
+
case "report":
|
|
81
|
+
implementations[name] = require("./runReport").runReport;
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
implementations[name] = false;
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
implementations[name] = false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return implementations[name];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
94
|
+
// V2 PACKS MODULES (Lazy Loaded)
|
|
95
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
96
|
+
|
|
97
|
+
let _packFactory = null;
|
|
98
|
+
let _permissionsPack = null;
|
|
99
|
+
let _proofGraphPack = null;
|
|
100
|
+
let _evidencePackV2 = null;
|
|
101
|
+
let _bundlePack = null;
|
|
102
|
+
|
|
103
|
+
function getPackFactory() {
|
|
104
|
+
if (!_packFactory) {
|
|
105
|
+
try {
|
|
106
|
+
_packFactory = require("./lib/packs/pack-factory");
|
|
107
|
+
} catch (e) {
|
|
108
|
+
_packFactory = false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return _packFactory;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getPermissionsPack() {
|
|
115
|
+
if (!_permissionsPack) {
|
|
116
|
+
try {
|
|
117
|
+
_permissionsPack = require("./lib/packs/permissions-pack");
|
|
118
|
+
} catch (e) {
|
|
119
|
+
_permissionsPack = false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return _permissionsPack;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getProofGraphPack() {
|
|
126
|
+
if (!_proofGraphPack) {
|
|
127
|
+
try {
|
|
128
|
+
_proofGraphPack = require("./lib/packs/proof-graph-pack");
|
|
129
|
+
} catch (e) {
|
|
130
|
+
_proofGraphPack = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return _proofGraphPack;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getEvidencePackV2() {
|
|
137
|
+
if (!_evidencePackV2) {
|
|
138
|
+
try {
|
|
139
|
+
_evidencePackV2 = require("./lib/packs/evidence-pack");
|
|
140
|
+
} catch (e) {
|
|
141
|
+
_evidencePackV2 = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return _evidencePackV2;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getBundlePack() {
|
|
148
|
+
if (!_bundlePack) {
|
|
149
|
+
try {
|
|
150
|
+
_bundlePack = require("./lib/packs/bundle");
|
|
151
|
+
} catch (e) {
|
|
152
|
+
_bundlePack = false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return _bundlePack;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
159
|
+
// CONSTANTS
|
|
160
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
161
|
+
|
|
162
|
+
const PACKS_VERSION = "5.0.0";
|
|
163
|
+
|
|
164
|
+
const SUBCOMMANDS = {
|
|
165
|
+
bundle: {
|
|
166
|
+
description: "All-in-one ZIP bundle + manifest + HTML index (V2)",
|
|
167
|
+
pro: false,
|
|
168
|
+
formats: ["zip", "dir"],
|
|
169
|
+
},
|
|
170
|
+
evidence: {
|
|
171
|
+
description: "Bundle videos, traces, screenshots, HAR files",
|
|
172
|
+
pro: false,
|
|
173
|
+
formats: ["pack", "zip"],
|
|
174
|
+
},
|
|
175
|
+
permissions: {
|
|
176
|
+
description: "AuthZ matrix, roles, protected routes",
|
|
177
|
+
pro: false,
|
|
178
|
+
formats: ["json", "html", "md"],
|
|
179
|
+
},
|
|
180
|
+
graph: {
|
|
181
|
+
description: "Proof graph with receipt cross-links",
|
|
182
|
+
pro: false,
|
|
183
|
+
formats: ["json", "dot", "mermaid", "html"],
|
|
184
|
+
},
|
|
185
|
+
report: {
|
|
186
|
+
description: "Generate HTML/MD/SARIF/CSV/PDF reports",
|
|
187
|
+
pro: false,
|
|
188
|
+
formats: ["html", "md", "json", "sarif", "csv", "pdf"],
|
|
189
|
+
},
|
|
190
|
+
manifest: {
|
|
191
|
+
description: "List all available artifacts",
|
|
192
|
+
pro: false,
|
|
193
|
+
formats: ["json", "table"],
|
|
194
|
+
},
|
|
195
|
+
launch: {
|
|
196
|
+
description: "Bundle launch validation results for team sharing",
|
|
197
|
+
pro: false,
|
|
198
|
+
formats: ["zip", "json", "md"],
|
|
199
|
+
},
|
|
200
|
+
list: {
|
|
201
|
+
description: "List existing packs and bundles",
|
|
202
|
+
pro: false,
|
|
203
|
+
formats: ["json", "table"],
|
|
204
|
+
},
|
|
205
|
+
cleanup: {
|
|
206
|
+
description: "Remove old packs (keeps 5 most recent)",
|
|
207
|
+
pro: false,
|
|
208
|
+
formats: ["json"],
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const GRAPH_QUERIES = {
|
|
213
|
+
all: "All nodes and edges",
|
|
214
|
+
unexecuted: "Nodes never executed at runtime",
|
|
215
|
+
"unhit-routes": "Routes never called",
|
|
216
|
+
"dead-ui": "UI elements with no handlers",
|
|
217
|
+
gaps: "Missing connections (proof gaps)",
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
221
|
+
// HELP SYSTEM
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
223
|
+
|
|
224
|
+
function printHelp(detailed = false) {
|
|
225
|
+
const cli = getCliOutput();
|
|
226
|
+
const { ansi, renderMinimalHeader } = cli;
|
|
227
|
+
|
|
228
|
+
// Print unified header
|
|
229
|
+
renderMinimalHeader("packs", "free");
|
|
230
|
+
|
|
231
|
+
console.log(` ${ansi.bold}ARTIFACT PACKS V2${ansi.reset}
|
|
232
|
+
${ansi.dim}One command to produce ZIP bundle + manifest + HTML index${ansi.reset}
|
|
233
|
+
|
|
234
|
+
${ansi.bold}USAGE${ansi.reset}
|
|
235
|
+
${ansi.cyan}vibecheck packs${ansi.reset} [subcommand] [options]
|
|
236
|
+
|
|
237
|
+
${ansi.dim}Generate shareable evidence bundles with stable naming and reproducible builds.
|
|
238
|
+
Cross-links to ship/reality/shield receipts for complete audit trails.${ansi.reset}
|
|
239
|
+
|
|
240
|
+
${ansi.bold}SUBCOMMANDS${ansi.reset}`);
|
|
241
|
+
|
|
242
|
+
const maxLen = Math.max(...Object.keys(SUBCOMMANDS).map(k => k.length));
|
|
243
|
+
for (const [name, info] of Object.entries(SUBCOMMANDS)) {
|
|
244
|
+
const proTag = info.pro ? `${ansi.magenta}PRO${ansi.reset} ` : " ";
|
|
245
|
+
console.log(` ${ansi.cyan}${name.padEnd(maxLen + 2)}${ansi.reset}${proTag}${info.description}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
console.log(`
|
|
249
|
+
${ansi.bold}BUNDLE OPTIONS (V2)${ansi.reset}
|
|
250
|
+
${ansi.cyan}--output, -o <path>${ansi.reset} Output directory
|
|
251
|
+
${ansi.cyan}--no-zip${ansi.reset} Create directory instead of ZIP
|
|
252
|
+
${ansi.cyan}--no-evidence${ansi.reset} Exclude evidence pack
|
|
253
|
+
${ansi.cyan}--no-permissions${ansi.reset} Exclude permissions pack
|
|
254
|
+
${ansi.cyan}--no-graph${ansi.reset} Exclude proof graph pack
|
|
255
|
+
${ansi.cyan}--no-report${ansi.reset} Exclude report pack
|
|
256
|
+
|
|
257
|
+
${ansi.bold}EVIDENCE OPTIONS${ansi.reset}
|
|
258
|
+
${ansi.cyan}--output, -o <path>${ansi.reset} Output directory
|
|
259
|
+
${ansi.cyan}--run-id <id>${ansi.reset} Bundle specific run
|
|
260
|
+
${ansi.cyan}--zip${ansi.reset} Create ZIP bundle
|
|
261
|
+
|
|
262
|
+
${ansi.bold}PERMISSIONS OPTIONS${ansi.reset}
|
|
263
|
+
${ansi.cyan}--output, -o <path>${ansi.reset} Output directory
|
|
264
|
+
${ansi.cyan}--zip${ansi.reset} Create ZIP bundle
|
|
265
|
+
|
|
266
|
+
${ansi.bold}GRAPH OPTIONS${ansi.reset}
|
|
267
|
+
${ansi.cyan}--output, -o <path>${ansi.reset} Output directory
|
|
268
|
+
${ansi.cyan}--zip${ansi.reset} Create ZIP bundle
|
|
269
|
+
|
|
270
|
+
${ansi.bold}REPORT OPTIONS${ansi.reset}
|
|
271
|
+
${ansi.cyan}--format <fmt>${ansi.reset} Output format: html, md, json, sarif, csv, pdf
|
|
272
|
+
${ansi.cyan}--type <type>${ansi.reset} Report type: executive, technical, compliance
|
|
273
|
+
${ansi.cyan}--output, -o <path>${ansi.reset} Output file path
|
|
274
|
+
${ansi.cyan}--open${ansi.reset} Open report in browser
|
|
275
|
+
|
|
276
|
+
${ansi.bold}CLEANUP OPTIONS${ansi.reset}
|
|
277
|
+
${ansi.cyan}--keep <n>${ansi.reset} Number of bundles to keep (default: 5)
|
|
278
|
+
${ansi.cyan}--max-age <days>${ansi.reset} Max age in days (default: 30)
|
|
279
|
+
|
|
280
|
+
${ansi.bold}GENERAL OPTIONS${ansi.reset}
|
|
281
|
+
${ansi.cyan}--json${ansi.reset} Output as JSON (CI integration)
|
|
282
|
+
${ansi.cyan}--quiet, -q${ansi.reset} Suppress non-essential output
|
|
283
|
+
${ansi.cyan}--verbose, -v${ansi.reset} Show detailed output
|
|
284
|
+
${ansi.cyan}--help, -h${ansi.reset} Show this help
|
|
285
|
+
|
|
286
|
+
${ansi.bold}EXAMPLES${ansi.reset}
|
|
287
|
+
${ansi.dim}# Create all-in-one evidence bundle (default)${ansi.reset}
|
|
288
|
+
vibecheck packs
|
|
289
|
+
|
|
290
|
+
${ansi.dim}# Create bundle with specific components${ansi.reset}
|
|
291
|
+
vibecheck packs bundle --no-report
|
|
292
|
+
|
|
293
|
+
${ansi.dim}# Generate permissions/AuthZ matrix${ansi.reset}
|
|
294
|
+
vibecheck packs permissions
|
|
295
|
+
|
|
296
|
+
${ansi.dim}# Generate proof graph with visualizations${ansi.reset}
|
|
297
|
+
vibecheck packs graph
|
|
298
|
+
|
|
299
|
+
${ansi.dim}# Bundle evidence with ZIP${ansi.reset}
|
|
300
|
+
vibecheck packs evidence --zip
|
|
301
|
+
|
|
302
|
+
${ansi.dim}# Generate HTML report${ansi.reset}
|
|
303
|
+
vibecheck packs report --format html --open
|
|
304
|
+
|
|
305
|
+
${ansi.dim}# List existing packs${ansi.reset}
|
|
306
|
+
vibecheck packs list
|
|
307
|
+
|
|
308
|
+
${ansi.dim}# Clean up old packs${ansi.reset}
|
|
309
|
+
vibecheck packs cleanup`);
|
|
310
|
+
|
|
311
|
+
if (detailed) {
|
|
312
|
+
console.log(`
|
|
313
|
+
${ansi.bold}GRAPH QUERIES${ansi.reset}`);
|
|
314
|
+
for (const [query, desc] of Object.entries(GRAPH_QUERIES)) {
|
|
315
|
+
console.log(` ${ansi.cyan}${query.padEnd(16)}${ansi.reset} ${desc}`);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
console.log(`
|
|
319
|
+
${ansi.bold}OUTPUT LOCATIONS${ansi.reset}
|
|
320
|
+
${ansi.dim}Evidence Packs:${ansi.reset} .vibecheck/evidence-packs/<pack-id>/
|
|
321
|
+
${ansi.dim}Reports:${ansi.reset} .vibecheck/reports/
|
|
322
|
+
${ansi.dim}Graphs:${ansi.reset} .vibecheck/graphs/
|
|
323
|
+
${ansi.dim}Manifests:${ansi.reset} .vibecheck/manifests/`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
console.log(`
|
|
327
|
+
${ansi.bold}EXIT CODES${ansi.reset}
|
|
328
|
+
${ansi.green}0${ansi.reset} Success
|
|
329
|
+
${ansi.yellow}1${ansi.reset} No data found
|
|
330
|
+
${ansi.red}2${ansi.reset} Generation failed
|
|
331
|
+
${ansi.red}4${ansi.reset} Invalid arguments
|
|
332
|
+
|
|
333
|
+
${ansi.dim}────────────────────────────────────────────────────────────────────${ansi.reset}
|
|
334
|
+
${ansi.dim}Documentation: https://docs.vibecheckai.dev/cli/packs${ansi.reset}
|
|
335
|
+
${ansi.dim}Version: ${PACKS_VERSION}${ansi.reset}
|
|
336
|
+
`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
340
|
+
// MAIN ENTRY POINT
|
|
341
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Main packs command handler
|
|
345
|
+
*
|
|
346
|
+
* @param {string[]} args - Command arguments
|
|
347
|
+
* @param {Object} context - Execution context
|
|
348
|
+
* @returns {Promise<number>} Exit code
|
|
349
|
+
*/
|
|
350
|
+
async function runPacks(args = [], context = {}) {
|
|
351
|
+
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = getGlobalFlags();
|
|
352
|
+
const { EXIT } = getExitCodes();
|
|
353
|
+
|
|
354
|
+
const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
|
|
355
|
+
const quiet = shouldSuppressOutput(globalFlags);
|
|
356
|
+
const json = isJsonMode(globalFlags) || args.includes("--json");
|
|
357
|
+
const verbose = args.includes("--verbose") || args.includes("-v");
|
|
358
|
+
const projectRoot = context.repoRoot || globalFlags.path || process.cwd();
|
|
359
|
+
|
|
360
|
+
// Parse subcommand
|
|
361
|
+
const subcommand = cleanArgs[0];
|
|
362
|
+
const subArgs = cleanArgs.slice(1);
|
|
363
|
+
|
|
364
|
+
// Handle help
|
|
365
|
+
if (globalFlags.help || args.includes("--help") || args.includes("-h")) {
|
|
366
|
+
if (!subcommand || ["--help", "-h"].includes(subcommand)) {
|
|
367
|
+
printHelp(verbose);
|
|
368
|
+
return EXIT.SUCCESS;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Create execution context
|
|
373
|
+
const execContext = {
|
|
374
|
+
projectRoot,
|
|
375
|
+
json,
|
|
376
|
+
quiet,
|
|
377
|
+
verbose,
|
|
378
|
+
args: subArgs,
|
|
379
|
+
originalArgs: args,
|
|
380
|
+
startTime: Date.now(),
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
// Route to appropriate handler
|
|
385
|
+
switch (subcommand) {
|
|
386
|
+
case "bundle":
|
|
387
|
+
return await handleBundle(execContext);
|
|
388
|
+
|
|
389
|
+
case "evidence":
|
|
390
|
+
return await handleEvidenceV2(execContext);
|
|
391
|
+
|
|
392
|
+
case "permissions":
|
|
393
|
+
return await handlePermissionsV2(execContext);
|
|
394
|
+
|
|
395
|
+
case "graph":
|
|
396
|
+
return await handleGraphV2(execContext);
|
|
397
|
+
|
|
398
|
+
case "report":
|
|
399
|
+
return await handleReport(execContext);
|
|
400
|
+
|
|
401
|
+
case "manifest":
|
|
402
|
+
return await handleManifest(execContext);
|
|
403
|
+
|
|
404
|
+
case "launch":
|
|
405
|
+
return await handleLaunch(execContext);
|
|
406
|
+
|
|
407
|
+
case "list":
|
|
408
|
+
return await handleList(execContext);
|
|
409
|
+
|
|
410
|
+
case "cleanup":
|
|
411
|
+
return await handleCleanup(execContext);
|
|
412
|
+
|
|
413
|
+
default:
|
|
414
|
+
// Default to bundle if no subcommand
|
|
415
|
+
if (!subcommand) {
|
|
416
|
+
return await handleBundle({ ...execContext, args: cleanArgs });
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// If it looks like a flag, pass to bundle
|
|
420
|
+
if (subcommand.startsWith("--")) {
|
|
421
|
+
return await handleBundle({ ...execContext, args: cleanArgs });
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return handleUnknownSubcommand(subcommand, execContext);
|
|
425
|
+
}
|
|
426
|
+
} catch (error) {
|
|
427
|
+
return handleError(error, execContext);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
432
|
+
// SUBCOMMAND HANDLERS
|
|
433
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Handle evidence subcommand
|
|
437
|
+
*/
|
|
438
|
+
async function handleEvidence(ctx) {
|
|
439
|
+
const { EXIT } = getExitCodes();
|
|
440
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, renderSuccess, renderWarning, sym, Spinner } = getCliOutput();
|
|
441
|
+
|
|
442
|
+
const runEvidencePack = loadImplementation("evidencePack");
|
|
443
|
+
|
|
444
|
+
if (!ctx.json && !ctx.quiet) {
|
|
445
|
+
renderMinimalHeader("packs", "free");
|
|
446
|
+
renderSectionHeader("Evidence Pack Generation", sym.pack);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (runEvidencePack) {
|
|
450
|
+
// Delegate to existing implementation
|
|
451
|
+
return await runEvidencePack(ctx.originalArgs);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Fallback implementation
|
|
455
|
+
const spinner = !ctx.quiet && !ctx.json ? new Spinner("Collecting evidence artifacts").start() : null;
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
const packId = `pack-${Date.now()}-${crypto.randomBytes(4).toString("hex")}`;
|
|
459
|
+
const outputDir = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o") ||
|
|
460
|
+
path.join(ctx.projectRoot, ".vibecheck", "evidence-packs", packId);
|
|
461
|
+
|
|
462
|
+
// Collect artifacts
|
|
463
|
+
const artifacts = await collectArtifacts(ctx.projectRoot, ctx.args);
|
|
464
|
+
|
|
465
|
+
if (artifacts.count === 0) {
|
|
466
|
+
spinner?.warn("No artifacts found");
|
|
467
|
+
|
|
468
|
+
if (ctx.json) {
|
|
469
|
+
console.log(JSON.stringify({ success: false, packId, artifacts: [], message: "No artifacts found" }));
|
|
470
|
+
} else if (!ctx.quiet) {
|
|
471
|
+
renderWarning("No evidence artifacts found");
|
|
472
|
+
console.log(`
|
|
473
|
+
${ansi.dim}Run verification commands first to generate artifacts:${ansi.reset}
|
|
474
|
+
${ansi.cyan}vibecheck prove --url http://localhost:3000${ansi.reset}
|
|
475
|
+
${ansi.cyan}vibecheck reality --url http://localhost:3000${ansi.reset}
|
|
476
|
+
`);
|
|
477
|
+
}
|
|
478
|
+
return EXIT.NOT_FOUND;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Create pack directory
|
|
482
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
483
|
+
|
|
484
|
+
// Copy artifacts
|
|
485
|
+
for (const artifact of artifacts.items) {
|
|
486
|
+
const destPath = path.join(outputDir, artifact.type, artifact.name);
|
|
487
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
488
|
+
fs.copyFileSync(artifact.source, destPath);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Generate manifest
|
|
492
|
+
const manifest = {
|
|
493
|
+
id: packId,
|
|
494
|
+
version: PACKS_VERSION,
|
|
495
|
+
generated: new Date().toISOString(),
|
|
496
|
+
projectRoot: ctx.projectRoot,
|
|
497
|
+
artifacts: artifacts.items.map(a => ({
|
|
498
|
+
type: a.type,
|
|
499
|
+
name: a.name,
|
|
500
|
+
size: a.size,
|
|
501
|
+
hash: a.hash,
|
|
502
|
+
})),
|
|
503
|
+
summary: artifacts.summary,
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
// Add signature if requested
|
|
507
|
+
if (ctx.args.includes("--sign")) {
|
|
508
|
+
manifest.signature = {
|
|
509
|
+
algorithm: "sha256",
|
|
510
|
+
hash: crypto.createHash("sha256").update(JSON.stringify(manifest)).digest("hex"),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
fs.writeFileSync(path.join(outputDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
515
|
+
|
|
516
|
+
// Generate HTML viewer
|
|
517
|
+
const htmlViewer = generateHtmlViewer(manifest);
|
|
518
|
+
fs.writeFileSync(path.join(outputDir, "index.html"), htmlViewer);
|
|
519
|
+
|
|
520
|
+
spinner?.succeed(`Evidence pack created: ${packId}`);
|
|
521
|
+
|
|
522
|
+
if (ctx.json) {
|
|
523
|
+
console.log(JSON.stringify({
|
|
524
|
+
success: true,
|
|
525
|
+
packId,
|
|
526
|
+
outputDir,
|
|
527
|
+
manifest,
|
|
528
|
+
}, null, 2));
|
|
529
|
+
} else if (!ctx.quiet) {
|
|
530
|
+
console.log(`
|
|
531
|
+
${ansi.bold}Pack Contents${ansi.reset}
|
|
532
|
+
${ansi.dim}Videos:${ansi.reset} ${artifacts.summary.videos || 0}
|
|
533
|
+
${ansi.dim}Traces:${ansi.reset} ${artifacts.summary.traces || 0}
|
|
534
|
+
${ansi.dim}Screenshots:${ansi.reset} ${artifacts.summary.screenshots || 0}
|
|
535
|
+
${ansi.dim}HAR Files:${ansi.reset} ${artifacts.summary.har || 0}
|
|
536
|
+
${ansi.dim}Reports:${ansi.reset} ${artifacts.summary.reports || 0}
|
|
537
|
+
|
|
538
|
+
${ansi.bold}Output${ansi.reset}
|
|
539
|
+
${ansi.dim}Directory:${ansi.reset} ${outputDir}
|
|
540
|
+
${ansi.dim}Viewer:${ansi.reset} ${path.join(outputDir, "index.html")}
|
|
541
|
+
`);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return EXIT.SUCCESS;
|
|
545
|
+
} catch (error) {
|
|
546
|
+
spinner?.fail("Failed to create evidence pack");
|
|
547
|
+
throw error;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Handle report subcommand
|
|
553
|
+
*/
|
|
554
|
+
async function handleReport(ctx) {
|
|
555
|
+
const { EXIT } = getExitCodes();
|
|
556
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
557
|
+
|
|
558
|
+
const runReport = loadImplementation("report");
|
|
559
|
+
|
|
560
|
+
if (!ctx.json && !ctx.quiet) {
|
|
561
|
+
renderMinimalHeader("packs", "free");
|
|
562
|
+
renderSectionHeader("Report Generation", sym.file);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (runReport) {
|
|
566
|
+
// Delegate to existing implementation
|
|
567
|
+
return await runReport(ctx.originalArgs);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Fallback: basic report generation
|
|
571
|
+
const format = getArgValue(ctx.args, "--format") || "html";
|
|
572
|
+
const output = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
573
|
+
const reportType = getArgValue(ctx.args, "--type") || "technical";
|
|
574
|
+
|
|
575
|
+
// Load scan data
|
|
576
|
+
const scanPath = path.join(ctx.projectRoot, ".vibecheck", "scan", "last_scan.json");
|
|
577
|
+
let scanData = { findings: [], summary: {} };
|
|
578
|
+
|
|
579
|
+
if (fs.existsSync(scanPath)) {
|
|
580
|
+
try {
|
|
581
|
+
scanData = JSON.parse(fs.readFileSync(scanPath, "utf-8"));
|
|
582
|
+
} catch {
|
|
583
|
+
// Use defaults
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const report = {
|
|
588
|
+
type: reportType,
|
|
589
|
+
format,
|
|
590
|
+
generated: new Date().toISOString(),
|
|
591
|
+
version: PACKS_VERSION,
|
|
592
|
+
summary: {
|
|
593
|
+
total: scanData.findings?.length || 0,
|
|
594
|
+
critical: scanData.findings?.filter(f => f.severity === "critical").length || 0,
|
|
595
|
+
high: scanData.findings?.filter(f => f.severity === "high").length || 0,
|
|
596
|
+
medium: scanData.findings?.filter(f => f.severity === "medium").length || 0,
|
|
597
|
+
low: scanData.findings?.filter(f => f.severity === "low").length || 0,
|
|
598
|
+
},
|
|
599
|
+
findings: scanData.findings || [],
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
let outputContent;
|
|
603
|
+
switch (format) {
|
|
604
|
+
case "json":
|
|
605
|
+
outputContent = JSON.stringify(report, null, 2);
|
|
606
|
+
break;
|
|
607
|
+
case "sarif":
|
|
608
|
+
outputContent = generateSarif(report);
|
|
609
|
+
break;
|
|
610
|
+
case "md":
|
|
611
|
+
outputContent = generateMarkdownReport(report);
|
|
612
|
+
break;
|
|
613
|
+
case "html":
|
|
614
|
+
default:
|
|
615
|
+
outputContent = generateHtmlReport(report);
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (output) {
|
|
620
|
+
const outputPath = path.isAbsolute(output) ? output : path.join(ctx.projectRoot, output);
|
|
621
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
622
|
+
fs.writeFileSync(outputPath, outputContent);
|
|
623
|
+
|
|
624
|
+
if (ctx.json) {
|
|
625
|
+
console.log(JSON.stringify({ success: true, path: outputPath, format, type: reportType }));
|
|
626
|
+
} else if (!ctx.quiet) {
|
|
627
|
+
console.log(`
|
|
628
|
+
${ansi.green}✓${ansi.reset} Report generated: ${outputPath}
|
|
629
|
+
|
|
630
|
+
${ansi.dim}Format: ${format} | Type: ${reportType}${ansi.reset}
|
|
631
|
+
${ansi.dim}Findings: ${report.summary.total} (${report.summary.critical} critical, ${report.summary.high} high)${ansi.reset}
|
|
632
|
+
`);
|
|
633
|
+
|
|
634
|
+
if (ctx.args.includes("--open")) {
|
|
635
|
+
const open = require("open");
|
|
636
|
+
open(outputPath);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
} else {
|
|
640
|
+
console.log(outputContent);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return EXIT.SUCCESS;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Handle graph subcommand
|
|
648
|
+
*/
|
|
649
|
+
async function handleGraph(ctx) {
|
|
650
|
+
const { EXIT } = getExitCodes();
|
|
651
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, renderWarning, sym, Spinner } = getCliOutput();
|
|
652
|
+
|
|
653
|
+
const format = getArgValue(ctx.args, "--format") || "json";
|
|
654
|
+
const output = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
655
|
+
const query = getArgValue(ctx.args, "--query");
|
|
656
|
+
const depth = parseInt(getArgValue(ctx.args, "--depth") || "0", 10);
|
|
657
|
+
|
|
658
|
+
if (!ctx.json && !ctx.quiet) {
|
|
659
|
+
renderMinimalHeader("packs", "pro");
|
|
660
|
+
renderSectionHeader("Proof Graph Generation", sym.chart);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const spinner = !ctx.quiet && !ctx.json ? new Spinner("Building proof graph").start() : null;
|
|
664
|
+
|
|
665
|
+
try {
|
|
666
|
+
// Load graph data from various sources
|
|
667
|
+
let graphData = await loadGraphData(ctx.projectRoot);
|
|
668
|
+
|
|
669
|
+
if (!graphData || (graphData.nodes?.length === 0 && graphData.edges?.length === 0)) {
|
|
670
|
+
spinner?.warn("No graph data found");
|
|
671
|
+
|
|
672
|
+
if (ctx.json) {
|
|
673
|
+
console.log(JSON.stringify({
|
|
674
|
+
success: false,
|
|
675
|
+
error: "No proof graph data found",
|
|
676
|
+
hint: "Run vibecheck prove or vibecheck reality first",
|
|
677
|
+
}));
|
|
678
|
+
} else if (!ctx.quiet) {
|
|
679
|
+
renderWarning("No proof graph data found");
|
|
680
|
+
console.log(`
|
|
681
|
+
${ansi.dim}Run verification commands to generate graph data:${ansi.reset}
|
|
682
|
+
${ansi.cyan}vibecheck prove --url http://localhost:3000${ansi.reset}
|
|
683
|
+
${ansi.cyan}vibecheck reality --url http://localhost:3000${ansi.reset}
|
|
684
|
+
`);
|
|
685
|
+
}
|
|
686
|
+
return EXIT.NOT_FOUND;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Apply query filter
|
|
690
|
+
if (query && GRAPH_QUERIES[query]) {
|
|
691
|
+
graphData = filterGraphByQuery(graphData, query);
|
|
692
|
+
if (spinner) spinner.text = `Filtering: ${GRAPH_QUERIES[query]}`;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Apply depth limit
|
|
696
|
+
if (depth > 0) {
|
|
697
|
+
graphData = limitGraphDepth(graphData, depth);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Add metadata
|
|
701
|
+
graphData.metadata = {
|
|
702
|
+
version: PACKS_VERSION,
|
|
703
|
+
generated: new Date().toISOString(),
|
|
704
|
+
query: query || "all",
|
|
705
|
+
depth: depth || "unlimited",
|
|
706
|
+
stats: {
|
|
707
|
+
nodes: graphData.nodes?.length || 0,
|
|
708
|
+
edges: graphData.edges?.length || 0,
|
|
709
|
+
gaps: graphData.gaps?.length || 0,
|
|
710
|
+
},
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// Format output
|
|
714
|
+
let outputContent;
|
|
715
|
+
switch (format) {
|
|
716
|
+
case "dot":
|
|
717
|
+
outputContent = graphToDot(graphData);
|
|
718
|
+
break;
|
|
719
|
+
case "mermaid":
|
|
720
|
+
outputContent = graphToMermaid(graphData);
|
|
721
|
+
break;
|
|
722
|
+
case "html":
|
|
723
|
+
outputContent = graphToHtml(graphData);
|
|
724
|
+
break;
|
|
725
|
+
case "json":
|
|
726
|
+
default:
|
|
727
|
+
outputContent = JSON.stringify(graphData, null, 2);
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
spinner?.succeed(`Graph generated (${graphData.metadata.stats.nodes} nodes, ${graphData.metadata.stats.edges} edges)`);
|
|
732
|
+
|
|
733
|
+
// Write or print output
|
|
734
|
+
if (output) {
|
|
735
|
+
const outputPath = path.isAbsolute(output) ? output : path.join(ctx.projectRoot, output);
|
|
736
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
737
|
+
fs.writeFileSync(outputPath, outputContent);
|
|
738
|
+
|
|
739
|
+
if (ctx.json) {
|
|
740
|
+
console.log(JSON.stringify({
|
|
741
|
+
success: true,
|
|
742
|
+
path: outputPath,
|
|
743
|
+
format,
|
|
744
|
+
stats: graphData.metadata.stats,
|
|
745
|
+
}));
|
|
746
|
+
} else if (!ctx.quiet) {
|
|
747
|
+
console.log(`
|
|
748
|
+
${ansi.bold}Graph Statistics${ansi.reset}
|
|
749
|
+
${ansi.dim}Nodes:${ansi.reset} ${graphData.metadata.stats.nodes}
|
|
750
|
+
${ansi.dim}Edges:${ansi.reset} ${graphData.metadata.stats.edges}
|
|
751
|
+
${ansi.dim}Gaps:${ansi.reset} ${graphData.metadata.stats.gaps}
|
|
752
|
+
|
|
753
|
+
${ansi.bold}Output${ansi.reset}
|
|
754
|
+
${ansi.dim}Path:${ansi.reset} ${outputPath}
|
|
755
|
+
${ansi.dim}Format:${ansi.reset} ${format}
|
|
756
|
+
`);
|
|
757
|
+
}
|
|
758
|
+
} else {
|
|
759
|
+
console.log(outputContent);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
return EXIT.SUCCESS;
|
|
763
|
+
} catch (error) {
|
|
764
|
+
spinner?.fail("Graph generation failed");
|
|
765
|
+
throw error;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Handle permissions subcommand (placeholder - legacy)
|
|
771
|
+
*/
|
|
772
|
+
async function handlePermissions(ctx) {
|
|
773
|
+
// Redirect to V2
|
|
774
|
+
return handlePermissionsV2(ctx);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
778
|
+
// V2 HANDLERS
|
|
779
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Handle bundle subcommand - All-in-one ZIP bundle + manifest + HTML index
|
|
783
|
+
*/
|
|
784
|
+
async function handleBundle(ctx) {
|
|
785
|
+
const { EXIT } = getExitCodes();
|
|
786
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
787
|
+
|
|
788
|
+
const bundlePack = getBundlePack();
|
|
789
|
+
|
|
790
|
+
if (!ctx.json && !ctx.quiet) {
|
|
791
|
+
renderMinimalHeader("packs", "free");
|
|
792
|
+
renderSectionHeader("Unified Bundle Generation (V2)", "📦");
|
|
793
|
+
console.log();
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if (!bundlePack) {
|
|
797
|
+
if (ctx.json) {
|
|
798
|
+
console.log(JSON.stringify({ success: false, error: "Bundle pack module not available" }));
|
|
799
|
+
} else if (!ctx.quiet) {
|
|
800
|
+
console.log(`${ansi.red}✗${ansi.reset} Bundle pack module not available\n`);
|
|
801
|
+
}
|
|
802
|
+
return EXIT.INTERNAL_ERROR;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
try {
|
|
806
|
+
const outputDir = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
807
|
+
const noZip = ctx.args.includes("--no-zip");
|
|
808
|
+
const noEvidence = ctx.args.includes("--no-evidence");
|
|
809
|
+
const noPermissions = ctx.args.includes("--no-permissions");
|
|
810
|
+
const noGraph = ctx.args.includes("--no-graph");
|
|
811
|
+
const noReport = ctx.args.includes("--no-report");
|
|
812
|
+
|
|
813
|
+
const result = await bundlePack.buildBundle(ctx.projectRoot, {
|
|
814
|
+
outputDir,
|
|
815
|
+
createZip: !noZip,
|
|
816
|
+
includeEvidence: !noEvidence,
|
|
817
|
+
includePermissions: !noPermissions,
|
|
818
|
+
includeProofGraph: !noGraph,
|
|
819
|
+
includeReport: !noReport,
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
if (ctx.json) {
|
|
823
|
+
console.log(JSON.stringify({
|
|
824
|
+
success: true,
|
|
825
|
+
bundleId: result.bundleId,
|
|
826
|
+
bundleDir: result.bundleDir,
|
|
827
|
+
zipPath: result.zipPath,
|
|
828
|
+
components: Object.keys(result.components).filter(k => result.components[k]),
|
|
829
|
+
manifest: result.manifest,
|
|
830
|
+
}, null, 2));
|
|
831
|
+
} else if (!ctx.quiet) {
|
|
832
|
+
console.log(`\n${ansi.green}✓${ansi.reset} ${ansi.bold}Bundle created successfully!${ansi.reset}\n`);
|
|
833
|
+
console.log(` ${ansi.bold}Bundle ID:${ansi.reset} ${result.bundleId}`);
|
|
834
|
+
console.log(` ${ansi.bold}Directory:${ansi.reset} ${result.bundleDir}`);
|
|
835
|
+
if (result.zipPath) {
|
|
836
|
+
console.log(` ${ansi.bold}ZIP File:${ansi.reset} ${result.zipPath}`);
|
|
837
|
+
}
|
|
838
|
+
console.log(` ${ansi.bold}Index:${ansi.reset} ${path.join(result.bundleDir, "index.html")}`);
|
|
839
|
+
|
|
840
|
+
console.log(`\n ${ansi.bold}Components${ansi.reset}`);
|
|
841
|
+
for (const [name, comp] of Object.entries(result.components)) {
|
|
842
|
+
if (comp) {
|
|
843
|
+
const icon = { evidence: "📸", permissions: "🔐", "proof-graph": "🕸️", report: "📊" }[name] || "📦";
|
|
844
|
+
console.log(` ${icon} ${name}`);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
if (result.manifest.receipts?.ship) {
|
|
849
|
+
console.log(`\n ${ansi.bold}Cross-References${ansi.reset}`);
|
|
850
|
+
console.log(` Ship: ${result.manifest.receipts.ship.verdict || "N/A"}`);
|
|
851
|
+
}
|
|
852
|
+
if (result.manifest.receipts?.reality) {
|
|
853
|
+
console.log(` Reality: ${result.manifest.receipts.reality.verdict || "N/A"}`);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
console.log(`\n ${ansi.dim}Open index.html in a browser to view the bundle${ansi.reset}\n`);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return EXIT.SUCCESS;
|
|
860
|
+
} catch (error) {
|
|
861
|
+
if (ctx.json) {
|
|
862
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
863
|
+
} else if (!ctx.quiet) {
|
|
864
|
+
console.log(`\n${ansi.red}✗${ansi.reset} Bundle creation failed: ${error.message}\n`);
|
|
865
|
+
}
|
|
866
|
+
return EXIT.INTERNAL_ERROR;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Handle evidence subcommand V2 - Enhanced with pack factory
|
|
872
|
+
*/
|
|
873
|
+
async function handleEvidenceV2(ctx) {
|
|
874
|
+
const { EXIT } = getExitCodes();
|
|
875
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
876
|
+
|
|
877
|
+
const evidencePack = getEvidencePackV2();
|
|
878
|
+
|
|
879
|
+
if (!ctx.json && !ctx.quiet) {
|
|
880
|
+
renderMinimalHeader("packs", "free");
|
|
881
|
+
renderSectionHeader("Evidence Pack Generation", sym.pack);
|
|
882
|
+
console.log();
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (!evidencePack) {
|
|
886
|
+
// Fall back to legacy handler
|
|
887
|
+
return await handleEvidence(ctx);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
try {
|
|
891
|
+
const outputDir = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
892
|
+
const createZip = ctx.args.includes("--zip");
|
|
893
|
+
const runId = getArgValue(ctx.args, "--run-id");
|
|
894
|
+
|
|
895
|
+
const result = await evidencePack.buildEvidencePack(ctx.projectRoot, {
|
|
896
|
+
outputDir,
|
|
897
|
+
createZip,
|
|
898
|
+
runId,
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
if (ctx.json) {
|
|
902
|
+
console.log(JSON.stringify({
|
|
903
|
+
success: true,
|
|
904
|
+
packId: result.packId,
|
|
905
|
+
outputDir: result.outputDir,
|
|
906
|
+
artifactCount: result.artifactCount,
|
|
907
|
+
manifest: result.manifest,
|
|
908
|
+
}, null, 2));
|
|
909
|
+
} else if (!ctx.quiet) {
|
|
910
|
+
console.log(`${ansi.green}✓${ansi.reset} Evidence pack created: ${result.packId}\n`);
|
|
911
|
+
console.log(` ${ansi.bold}Artifacts${ansi.reset}`);
|
|
912
|
+
console.log(` Screenshots: ${result.manifest.metadata.screenshotCount}`);
|
|
913
|
+
console.log(` Videos: ${result.manifest.metadata.videoCount}`);
|
|
914
|
+
console.log(` Traces: ${result.manifest.metadata.traceCount}`);
|
|
915
|
+
console.log(` Findings: ${result.manifest.metadata.findingCount}`);
|
|
916
|
+
console.log(`\n ${ansi.bold}Output${ansi.reset}`);
|
|
917
|
+
console.log(` Directory: ${result.outputDir}`);
|
|
918
|
+
console.log(` Gallery: ${path.join(result.outputDir, "gallery.html")}\n`);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
return EXIT.SUCCESS;
|
|
922
|
+
} catch (error) {
|
|
923
|
+
if (ctx.json) {
|
|
924
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
925
|
+
} else if (!ctx.quiet) {
|
|
926
|
+
console.log(`\n${ansi.red}✗${ansi.reset} Evidence pack failed: ${error.message}\n`);
|
|
927
|
+
}
|
|
928
|
+
return EXIT.INTERNAL_ERROR;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Handle permissions subcommand V2 - AuthZ matrix extraction
|
|
934
|
+
*/
|
|
935
|
+
async function handlePermissionsV2(ctx) {
|
|
936
|
+
const { EXIT } = getExitCodes();
|
|
937
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym, Spinner } = getCliOutput();
|
|
938
|
+
|
|
939
|
+
const permissionsPack = getPermissionsPack();
|
|
940
|
+
|
|
941
|
+
if (!ctx.json && !ctx.quiet) {
|
|
942
|
+
renderMinimalHeader("packs", "free");
|
|
943
|
+
renderSectionHeader("Permissions Pack Generation", "🔐");
|
|
944
|
+
console.log();
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (!permissionsPack) {
|
|
948
|
+
if (ctx.json) {
|
|
949
|
+
console.log(JSON.stringify({ success: false, error: "Permissions pack module not available" }));
|
|
950
|
+
} else if (!ctx.quiet) {
|
|
951
|
+
console.log(`${ansi.red}✗${ansi.reset} Permissions pack module not available\n`);
|
|
952
|
+
}
|
|
953
|
+
return EXIT.INTERNAL_ERROR;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
const spinner = !ctx.quiet && !ctx.json ? new Spinner("Scanning codebase for permissions").start() : null;
|
|
957
|
+
|
|
958
|
+
try {
|
|
959
|
+
const outputDir = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
960
|
+
const createZip = ctx.args.includes("--zip");
|
|
961
|
+
|
|
962
|
+
const result = await permissionsPack.buildPermissionsPack(ctx.projectRoot, {
|
|
963
|
+
outputDir,
|
|
964
|
+
createZip,
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
spinner?.succeed("Permissions pack created");
|
|
968
|
+
|
|
969
|
+
if (ctx.json) {
|
|
970
|
+
console.log(JSON.stringify({
|
|
971
|
+
success: true,
|
|
972
|
+
packId: result.packId,
|
|
973
|
+
outputDir: result.outputDir,
|
|
974
|
+
metadata: result.manifest.metadata,
|
|
975
|
+
}, null, 2));
|
|
976
|
+
} else if (!ctx.quiet) {
|
|
977
|
+
console.log(`\n ${ansi.bold}AuthZ Matrix${ansi.reset}`);
|
|
978
|
+
console.log(` Roles: ${result.manifest.metadata.rolesCount}`);
|
|
979
|
+
console.log(` Permissions: ${result.manifest.metadata.permissionsCount}`);
|
|
980
|
+
console.log(` Protected Routes: ${result.manifest.metadata.protectedRoutesCount}`);
|
|
981
|
+
console.log(` Entitlements: ${result.manifest.metadata.entitlementsCount}`);
|
|
982
|
+
console.log(` Files Scanned: ${result.manifest.metadata.filesScanned}`);
|
|
983
|
+
console.log(`\n ${ansi.bold}Output${ansi.reset}`);
|
|
984
|
+
console.log(` Directory: ${result.outputDir}`);
|
|
985
|
+
console.log(` Matrix: ${path.join(result.outputDir, "matrix.html")}`);
|
|
986
|
+
console.log(` Report: ${path.join(result.outputDir, "permissions-report.md")}\n`);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
return EXIT.SUCCESS;
|
|
990
|
+
} catch (error) {
|
|
991
|
+
spinner?.fail("Permissions pack failed");
|
|
992
|
+
if (ctx.json) {
|
|
993
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
994
|
+
} else if (!ctx.quiet) {
|
|
995
|
+
console.log(`\n${ansi.red}✗${ansi.reset} Permissions pack failed: ${error.message}\n`);
|
|
996
|
+
}
|
|
997
|
+
return EXIT.INTERNAL_ERROR;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Handle graph subcommand V2 - Proof graph with receipt cross-links
|
|
1003
|
+
*/
|
|
1004
|
+
async function handleGraphV2(ctx) {
|
|
1005
|
+
const { EXIT } = getExitCodes();
|
|
1006
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym, Spinner } = getCliOutput();
|
|
1007
|
+
|
|
1008
|
+
const proofGraphPack = getProofGraphPack();
|
|
1009
|
+
|
|
1010
|
+
if (!ctx.json && !ctx.quiet) {
|
|
1011
|
+
renderMinimalHeader("packs", "free");
|
|
1012
|
+
renderSectionHeader("Proof Graph Pack Generation", "🕸️");
|
|
1013
|
+
console.log();
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (!proofGraphPack) {
|
|
1017
|
+
// Fall back to legacy handler
|
|
1018
|
+
return await handleGraph(ctx);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const spinner = !ctx.quiet && !ctx.json ? new Spinner("Building proof graph").start() : null;
|
|
1022
|
+
|
|
1023
|
+
try {
|
|
1024
|
+
const outputDir = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
1025
|
+
const createZip = ctx.args.includes("--zip");
|
|
1026
|
+
|
|
1027
|
+
const result = await proofGraphPack.buildProofGraphPack(ctx.projectRoot, {
|
|
1028
|
+
outputDir,
|
|
1029
|
+
createZip,
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
spinner?.succeed("Proof graph pack created");
|
|
1033
|
+
|
|
1034
|
+
if (ctx.json) {
|
|
1035
|
+
console.log(JSON.stringify({
|
|
1036
|
+
success: true,
|
|
1037
|
+
packId: result.packId,
|
|
1038
|
+
outputDir: result.outputDir,
|
|
1039
|
+
metadata: result.manifest.metadata,
|
|
1040
|
+
}, null, 2));
|
|
1041
|
+
} else if (!ctx.quiet) {
|
|
1042
|
+
console.log(`\n ${ansi.bold}Graph Statistics${ansi.reset}`);
|
|
1043
|
+
console.log(` Nodes: ${result.manifest.metadata.nodeCount}`);
|
|
1044
|
+
console.log(` Edges: ${result.manifest.metadata.edgeCount}`);
|
|
1045
|
+
console.log(`\n ${ansi.bold}Receipt Cross-Links${ansi.reset}`);
|
|
1046
|
+
console.log(` Ship Receipt: ${result.manifest.metadata.hasShipReceipt ? "✓" : "✗"}`);
|
|
1047
|
+
console.log(` Reality Receipt: ${result.manifest.metadata.hasRealityReceipt ? "✓" : "✗"}`);
|
|
1048
|
+
console.log(` Scan Receipt: ${result.manifest.metadata.hasScanReceipt ? "✓" : "✗"}`);
|
|
1049
|
+
console.log(` Proof Runs: ${result.manifest.metadata.proofRunCount}`);
|
|
1050
|
+
console.log(`\n ${ansi.bold}Output${ansi.reset}`);
|
|
1051
|
+
console.log(` Directory: ${result.outputDir}`);
|
|
1052
|
+
console.log(` Visualization: ${path.join(result.outputDir, "visualization.html")}`);
|
|
1053
|
+
console.log(` DOT Format: ${path.join(result.outputDir, "proof-graph.dot")}`);
|
|
1054
|
+
console.log(` Mermaid: ${path.join(result.outputDir, "proof-graph.mmd")}\n`);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
return EXIT.SUCCESS;
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
spinner?.fail("Proof graph pack failed");
|
|
1060
|
+
if (ctx.json) {
|
|
1061
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
1062
|
+
} else if (!ctx.quiet) {
|
|
1063
|
+
console.log(`\n${ansi.red}✗${ansi.reset} Proof graph pack failed: ${error.message}\n`);
|
|
1064
|
+
}
|
|
1065
|
+
return EXIT.INTERNAL_ERROR;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Handle list subcommand - List existing packs and bundles
|
|
1071
|
+
*/
|
|
1072
|
+
async function handleList(ctx) {
|
|
1073
|
+
const { EXIT } = getExitCodes();
|
|
1074
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
1075
|
+
|
|
1076
|
+
const bundlePack = getBundlePack();
|
|
1077
|
+
const packFactory = getPackFactory();
|
|
1078
|
+
|
|
1079
|
+
if (!ctx.json && !ctx.quiet) {
|
|
1080
|
+
renderMinimalHeader("packs", "free");
|
|
1081
|
+
renderSectionHeader("Available Packs", sym.list);
|
|
1082
|
+
console.log();
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
const result = {
|
|
1086
|
+
bundles: [],
|
|
1087
|
+
packs: [],
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
// List bundles
|
|
1091
|
+
if (bundlePack && bundlePack.listBundles) {
|
|
1092
|
+
result.bundles = bundlePack.listBundles(ctx.projectRoot);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// List individual packs
|
|
1096
|
+
const packsDir = path.join(ctx.projectRoot, ".vibecheck/packs");
|
|
1097
|
+
if (fs.existsSync(packsDir)) {
|
|
1098
|
+
const dirs = fs.readdirSync(packsDir, { withFileTypes: true })
|
|
1099
|
+
.filter(d => d.isDirectory())
|
|
1100
|
+
.map(d => d.name);
|
|
1101
|
+
|
|
1102
|
+
for (const dir of dirs) {
|
|
1103
|
+
const manifestPath = path.join(packsDir, dir, "manifest.json");
|
|
1104
|
+
if (fs.existsSync(manifestPath)) {
|
|
1105
|
+
try {
|
|
1106
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
1107
|
+
result.packs.push({
|
|
1108
|
+
id: manifest.id,
|
|
1109
|
+
type: manifest.type,
|
|
1110
|
+
generatedAt: manifest.generatedAt,
|
|
1111
|
+
artifactCount: manifest.summary?.artifactCount || 0,
|
|
1112
|
+
});
|
|
1113
|
+
} catch (e) {
|
|
1114
|
+
// Skip invalid
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (ctx.json) {
|
|
1121
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1122
|
+
} else if (!ctx.quiet) {
|
|
1123
|
+
console.log(` ${ansi.bold}Bundles${ansi.reset} (${result.bundles.length})`);
|
|
1124
|
+
if (result.bundles.length === 0) {
|
|
1125
|
+
console.log(` ${ansi.dim}No bundles found${ansi.reset}`);
|
|
1126
|
+
} else {
|
|
1127
|
+
for (const bundle of result.bundles.slice(0, 5)) {
|
|
1128
|
+
const time = bundle.generatedAt ? new Date(bundle.generatedAt).toLocaleString() : "?";
|
|
1129
|
+
const verdict = bundle.verdict ? ` [${bundle.verdict}]` : "";
|
|
1130
|
+
console.log(` ${ansi.cyan}${bundle.id}${ansi.reset}${verdict}`);
|
|
1131
|
+
console.log(` ${ansi.dim}${time} • ${bundle.componentCount} components${ansi.reset}`);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
console.log(`\n ${ansi.bold}Packs${ansi.reset} (${result.packs.length})`);
|
|
1136
|
+
if (result.packs.length === 0) {
|
|
1137
|
+
console.log(` ${ansi.dim}No packs found${ansi.reset}`);
|
|
1138
|
+
} else {
|
|
1139
|
+
for (const pack of result.packs.slice(0, 10)) {
|
|
1140
|
+
const time = pack.generatedAt ? new Date(pack.generatedAt).toLocaleString() : "?";
|
|
1141
|
+
console.log(` ${ansi.cyan}${pack.id}${ansi.reset} [${pack.type}]`);
|
|
1142
|
+
console.log(` ${ansi.dim}${time} • ${pack.artifactCount} artifacts${ansi.reset}`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
console.log();
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
return EXIT.SUCCESS;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Handle cleanup subcommand - Remove old packs
|
|
1153
|
+
*/
|
|
1154
|
+
async function handleCleanup(ctx) {
|
|
1155
|
+
const { EXIT } = getExitCodes();
|
|
1156
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
1157
|
+
|
|
1158
|
+
const bundlePack = getBundlePack();
|
|
1159
|
+
|
|
1160
|
+
if (!ctx.json && !ctx.quiet) {
|
|
1161
|
+
renderMinimalHeader("packs", "free");
|
|
1162
|
+
renderSectionHeader("Cleanup Old Packs", "🧹");
|
|
1163
|
+
console.log();
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
let removed = 0;
|
|
1167
|
+
|
|
1168
|
+
// Cleanup bundles
|
|
1169
|
+
if (bundlePack && bundlePack.cleanupBundles) {
|
|
1170
|
+
const maxCount = parseInt(getArgValue(ctx.args, "--keep") || "5", 10);
|
|
1171
|
+
const maxAgeDays = parseInt(getArgValue(ctx.args, "--max-age") || "30", 10);
|
|
1172
|
+
|
|
1173
|
+
removed = bundlePack.cleanupBundles(ctx.projectRoot, { maxCount, maxAgeDays });
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Cleanup individual packs
|
|
1177
|
+
const packsDir = path.join(ctx.projectRoot, ".vibecheck/packs");
|
|
1178
|
+
if (fs.existsSync(packsDir)) {
|
|
1179
|
+
const dirs = fs.readdirSync(packsDir, { withFileTypes: true })
|
|
1180
|
+
.filter(d => d.isDirectory())
|
|
1181
|
+
.map(d => d.name)
|
|
1182
|
+
.sort()
|
|
1183
|
+
.reverse();
|
|
1184
|
+
|
|
1185
|
+
// Keep 10 most recent
|
|
1186
|
+
for (const dir of dirs.slice(10)) {
|
|
1187
|
+
try {
|
|
1188
|
+
fs.rmSync(path.join(packsDir, dir), { recursive: true, force: true });
|
|
1189
|
+
removed++;
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
// Skip
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
if (ctx.json) {
|
|
1197
|
+
console.log(JSON.stringify({ success: true, removed }));
|
|
1198
|
+
} else if (!ctx.quiet) {
|
|
1199
|
+
if (removed > 0) {
|
|
1200
|
+
console.log(` ${ansi.green}✓${ansi.reset} Removed ${removed} old packs\n`);
|
|
1201
|
+
} else {
|
|
1202
|
+
console.log(` ${ansi.dim}No packs to clean up${ansi.reset}\n`);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
return EXIT.SUCCESS;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Handle manifest subcommand - list all artifacts
|
|
1211
|
+
*/
|
|
1212
|
+
async function handleManifest(ctx) {
|
|
1213
|
+
const { EXIT } = getExitCodes();
|
|
1214
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
1215
|
+
|
|
1216
|
+
if (!ctx.json && !ctx.quiet) {
|
|
1217
|
+
renderMinimalHeader("packs", "free");
|
|
1218
|
+
renderSectionHeader("Artifact Manifest", sym.list);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
const artifacts = {
|
|
1222
|
+
scans: [],
|
|
1223
|
+
evidence: [],
|
|
1224
|
+
reports: [],
|
|
1225
|
+
graphs: [],
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
// Collect scans
|
|
1229
|
+
const scansDir = path.join(ctx.projectRoot, ".vibecheck", "scan");
|
|
1230
|
+
if (fs.existsSync(scansDir)) {
|
|
1231
|
+
const files = fs.readdirSync(scansDir).filter(f => f.endsWith(".json"));
|
|
1232
|
+
artifacts.scans = files.map(f => ({
|
|
1233
|
+
name: f,
|
|
1234
|
+
path: path.join(scansDir, f),
|
|
1235
|
+
modified: fs.statSync(path.join(scansDir, f)).mtime,
|
|
1236
|
+
}));
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// Collect evidence packs
|
|
1240
|
+
const packsDir = path.join(ctx.projectRoot, ".vibecheck", "evidence-packs");
|
|
1241
|
+
if (fs.existsSync(packsDir)) {
|
|
1242
|
+
const dirs = fs.readdirSync(packsDir).filter(d =>
|
|
1243
|
+
fs.statSync(path.join(packsDir, d)).isDirectory()
|
|
1244
|
+
);
|
|
1245
|
+
artifacts.evidence = dirs.map(d => {
|
|
1246
|
+
const manifestPath = path.join(packsDir, d, "manifest.json");
|
|
1247
|
+
let manifest = null;
|
|
1248
|
+
if (fs.existsSync(manifestPath)) {
|
|
1249
|
+
try {
|
|
1250
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
1251
|
+
} catch {
|
|
1252
|
+
// Skip invalid manifests
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
return {
|
|
1256
|
+
id: d,
|
|
1257
|
+
path: path.join(packsDir, d),
|
|
1258
|
+
manifest,
|
|
1259
|
+
};
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// Collect reports
|
|
1264
|
+
const reportsDir = path.join(ctx.projectRoot, ".vibecheck", "reports");
|
|
1265
|
+
if (fs.existsSync(reportsDir)) {
|
|
1266
|
+
const files = fs.readdirSync(reportsDir);
|
|
1267
|
+
artifacts.reports = files.map(f => ({
|
|
1268
|
+
name: f,
|
|
1269
|
+
path: path.join(reportsDir, f),
|
|
1270
|
+
modified: fs.statSync(path.join(reportsDir, f)).mtime,
|
|
1271
|
+
}));
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
const manifest = {
|
|
1275
|
+
version: PACKS_VERSION,
|
|
1276
|
+
generated: new Date().toISOString(),
|
|
1277
|
+
projectRoot: ctx.projectRoot,
|
|
1278
|
+
artifacts,
|
|
1279
|
+
summary: {
|
|
1280
|
+
scans: artifacts.scans.length,
|
|
1281
|
+
evidence: artifacts.evidence.length,
|
|
1282
|
+
reports: artifacts.reports.length,
|
|
1283
|
+
graphs: artifacts.graphs.length,
|
|
1284
|
+
total: artifacts.scans.length + artifacts.evidence.length + artifacts.reports.length + artifacts.graphs.length,
|
|
1285
|
+
},
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1288
|
+
if (ctx.json) {
|
|
1289
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
1290
|
+
} else if (!ctx.quiet) {
|
|
1291
|
+
console.log(`
|
|
1292
|
+
${ansi.bold}Artifact Summary${ansi.reset}
|
|
1293
|
+
${ansi.dim}Scans:${ansi.reset} ${manifest.summary.scans}
|
|
1294
|
+
${ansi.dim}Evidence Packs:${ansi.reset} ${manifest.summary.evidence}
|
|
1295
|
+
${ansi.dim}Reports:${ansi.reset} ${manifest.summary.reports}
|
|
1296
|
+
${ansi.dim}Graphs:${ansi.reset} ${manifest.summary.graphs}
|
|
1297
|
+
${ansi.dim}Total:${ansi.reset} ${manifest.summary.total}
|
|
1298
|
+
`);
|
|
1299
|
+
|
|
1300
|
+
if (artifacts.evidence.length > 0) {
|
|
1301
|
+
console.log(` ${ansi.bold}Recent Evidence Packs${ansi.reset}`);
|
|
1302
|
+
for (const pack of artifacts.evidence.slice(-5)) {
|
|
1303
|
+
const time = pack.manifest?.generated ? new Date(pack.manifest.generated).toLocaleString() : "?";
|
|
1304
|
+
console.log(` ${ansi.dim}${pack.id}${ansi.reset} - ${time}`);
|
|
1305
|
+
}
|
|
1306
|
+
console.log();
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
if (artifacts.scans.length > 0) {
|
|
1310
|
+
console.log(` ${ansi.bold}Recent Scans${ansi.reset}`);
|
|
1311
|
+
for (const scan of artifacts.scans.slice(-5)) {
|
|
1312
|
+
const time = scan.modified ? new Date(scan.modified).toLocaleString() : "?";
|
|
1313
|
+
console.log(` ${ansi.dim}${scan.name}${ansi.reset} - ${time}`);
|
|
1314
|
+
}
|
|
1315
|
+
console.log();
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
return EXIT.SUCCESS;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Handle launch subcommand - bundle launch validation results
|
|
1324
|
+
*/
|
|
1325
|
+
async function handleLaunch(ctx) {
|
|
1326
|
+
const { EXIT } = getExitCodes();
|
|
1327
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
1328
|
+
|
|
1329
|
+
if (!ctx.json && !ctx.quiet) {
|
|
1330
|
+
renderMinimalHeader("packs", "free");
|
|
1331
|
+
renderSectionHeader("Launch Pack Bundle", "🚀");
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
const launchDir = path.join(ctx.projectRoot, ".vibecheck", "launch");
|
|
1335
|
+
|
|
1336
|
+
if (!fs.existsSync(launchDir)) {
|
|
1337
|
+
if (ctx.json) {
|
|
1338
|
+
console.log(JSON.stringify({
|
|
1339
|
+
success: false,
|
|
1340
|
+
error: "No launch results found. Run 'vibecheck launch' first."
|
|
1341
|
+
}));
|
|
1342
|
+
} else if (!ctx.quiet) {
|
|
1343
|
+
console.log(`\n ${ansi.yellow}No launch results found.${ansi.reset}`);
|
|
1344
|
+
console.log(` Run ${ansi.cyan}vibecheck launch${ansi.reset} first to generate results.\n`);
|
|
1345
|
+
}
|
|
1346
|
+
return EXIT.NOT_FOUND;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// Find the most recent launch results
|
|
1350
|
+
const files = fs.readdirSync(launchDir)
|
|
1351
|
+
.filter(f => f.startsWith("launch-") && f.endsWith(".json"))
|
|
1352
|
+
.sort()
|
|
1353
|
+
.reverse();
|
|
1354
|
+
|
|
1355
|
+
if (files.length === 0) {
|
|
1356
|
+
if (ctx.json) {
|
|
1357
|
+
console.log(JSON.stringify({
|
|
1358
|
+
success: false,
|
|
1359
|
+
error: "No launch results found."
|
|
1360
|
+
}));
|
|
1361
|
+
} else if (!ctx.quiet) {
|
|
1362
|
+
console.log(`\n ${ansi.yellow}No launch results found.${ansi.reset}\n`);
|
|
1363
|
+
}
|
|
1364
|
+
return EXIT.NOT_FOUND;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
const latestFile = files[0];
|
|
1368
|
+
const format = getArgValue(ctx.args, "--format") || "zip";
|
|
1369
|
+
const outputPath = getArgValue(ctx.args, "--output") || getArgValue(ctx.args, "-o");
|
|
1370
|
+
|
|
1371
|
+
// Collect all launch artifacts
|
|
1372
|
+
const artifacts = [
|
|
1373
|
+
{ name: latestFile, path: path.join(launchDir, latestFile), type: "results" },
|
|
1374
|
+
];
|
|
1375
|
+
|
|
1376
|
+
// Add other standard launch files if they exist
|
|
1377
|
+
const standardFiles = ["blockers.json", "checklist.md", "audit-trail.json", "manifest.json"];
|
|
1378
|
+
for (const file of standardFiles) {
|
|
1379
|
+
const filePath = path.join(launchDir, file);
|
|
1380
|
+
if (fs.existsSync(filePath)) {
|
|
1381
|
+
artifacts.push({ name: file, path: filePath, type: file.replace(/\.[^.]+$/, "") });
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
if (format === "json") {
|
|
1386
|
+
// Output as JSON listing
|
|
1387
|
+
const result = {
|
|
1388
|
+
success: true,
|
|
1389
|
+
packId: latestFile.replace(/\.json$/, ""),
|
|
1390
|
+
artifacts: artifacts.map(a => ({ name: a.name, type: a.type })),
|
|
1391
|
+
launchDir,
|
|
1392
|
+
};
|
|
1393
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1394
|
+
return EXIT.SUCCESS;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
if (format === "md") {
|
|
1398
|
+
// Output the checklist markdown
|
|
1399
|
+
const checklistPath = path.join(launchDir, "checklist.md");
|
|
1400
|
+
if (fs.existsSync(checklistPath)) {
|
|
1401
|
+
console.log(fs.readFileSync(checklistPath, "utf-8"));
|
|
1402
|
+
} else {
|
|
1403
|
+
console.log("# Launch Checklist\n\nNo checklist generated yet.");
|
|
1404
|
+
}
|
|
1405
|
+
return EXIT.SUCCESS;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// Default: ZIP bundle
|
|
1409
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
1410
|
+
const zipName = outputPath || `launch-pack-${timestamp}.zip`;
|
|
1411
|
+
const zipPath = path.resolve(ctx.projectRoot, zipName);
|
|
1412
|
+
|
|
1413
|
+
try {
|
|
1414
|
+
// Create a simple zip using Node.js (no external deps)
|
|
1415
|
+
const archiver = require("archiver");
|
|
1416
|
+
const output = fs.createWriteStream(zipPath);
|
|
1417
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
1418
|
+
|
|
1419
|
+
archive.pipe(output);
|
|
1420
|
+
|
|
1421
|
+
for (const artifact of artifacts) {
|
|
1422
|
+
archive.file(artifact.path, { name: artifact.name });
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
await archive.finalize();
|
|
1426
|
+
|
|
1427
|
+
if (!ctx.quiet) {
|
|
1428
|
+
console.log(`\n ${ansi.green}✓${ansi.reset} Created: ${ansi.cyan}${zipName}${ansi.reset}`);
|
|
1429
|
+
console.log(` • ${artifacts.length} files bundled`);
|
|
1430
|
+
console.log(` • ${artifacts.map(a => a.name).join(", ")}`);
|
|
1431
|
+
console.log();
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
if (ctx.json) {
|
|
1435
|
+
console.log(JSON.stringify({
|
|
1436
|
+
success: true,
|
|
1437
|
+
path: zipPath,
|
|
1438
|
+
artifacts: artifacts.length,
|
|
1439
|
+
files: artifacts.map(a => a.name),
|
|
1440
|
+
}));
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
return EXIT.SUCCESS;
|
|
1444
|
+
} catch (err) {
|
|
1445
|
+
// Fallback: just copy files to a directory if archiver not available
|
|
1446
|
+
const bundleDir = outputPath || path.join(ctx.projectRoot, `launch-pack-${timestamp}`);
|
|
1447
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
1448
|
+
|
|
1449
|
+
for (const artifact of artifacts) {
|
|
1450
|
+
fs.copyFileSync(artifact.path, path.join(bundleDir, artifact.name));
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
if (!ctx.quiet) {
|
|
1454
|
+
console.log(`\n ${ansi.green}✓${ansi.reset} Created bundle directory: ${ansi.cyan}${bundleDir}${ansi.reset}`);
|
|
1455
|
+
console.log(` • ${artifacts.length} files copied`);
|
|
1456
|
+
console.log();
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
return EXIT.SUCCESS;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1464
|
+
// ERROR HANDLING
|
|
1465
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1466
|
+
|
|
1467
|
+
function handleUnknownSubcommand(subcommand, ctx) {
|
|
1468
|
+
const { EXIT } = getExitCodes();
|
|
1469
|
+
const { ansi } = getCliOutput();
|
|
1470
|
+
|
|
1471
|
+
if (ctx.json) {
|
|
1472
|
+
console.log(JSON.stringify({
|
|
1473
|
+
success: false,
|
|
1474
|
+
error: `Unknown subcommand: ${subcommand}`,
|
|
1475
|
+
available: Object.keys(SUBCOMMANDS),
|
|
1476
|
+
}));
|
|
1477
|
+
} else {
|
|
1478
|
+
console.log(`
|
|
1479
|
+
${ansi.red}Error: Unknown subcommand '${subcommand}'${ansi.reset}
|
|
1480
|
+
|
|
1481
|
+
${ansi.dim}Available subcommands:${ansi.reset}
|
|
1482
|
+
${Object.keys(SUBCOMMANDS).map(s => ` ${ansi.cyan}${s}${ansi.reset}`).join("\n")}
|
|
1483
|
+
|
|
1484
|
+
Run ${ansi.cyan}vibecheck packs --help${ansi.reset} for usage.
|
|
1485
|
+
`);
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
return EXIT.USER_ERROR;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
function handleError(error, ctx) {
|
|
1492
|
+
const { EXIT } = getExitCodes();
|
|
1493
|
+
const { ansi, renderError } = getCliOutput();
|
|
1494
|
+
|
|
1495
|
+
if (ctx.json) {
|
|
1496
|
+
console.log(JSON.stringify({
|
|
1497
|
+
success: false,
|
|
1498
|
+
error: error.message,
|
|
1499
|
+
stack: ctx.verbose ? error.stack : undefined,
|
|
1500
|
+
}));
|
|
1501
|
+
} else {
|
|
1502
|
+
renderError(`Packs error: ${error.message}`);
|
|
1503
|
+
if (ctx.verbose) {
|
|
1504
|
+
console.log(`\n${ansi.dim}${error.stack}${ansi.reset}\n`);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
return EXIT.INTERNAL_ERROR;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1512
|
+
// UTILITY FUNCTIONS
|
|
1513
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1514
|
+
|
|
1515
|
+
function getArgValue(args, flag) {
|
|
1516
|
+
const index = args.indexOf(flag);
|
|
1517
|
+
if (index !== -1 && args[index + 1] && !args[index + 1].startsWith("--")) {
|
|
1518
|
+
return args[index + 1];
|
|
1519
|
+
}
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
async function collectArtifacts(projectRoot, args) {
|
|
1524
|
+
const artifacts = { items: [], summary: {}, count: 0 };
|
|
1525
|
+
const includeVideos = !args.includes("--no-videos");
|
|
1526
|
+
const includeTraces = !args.includes("--no-traces");
|
|
1527
|
+
const includeHar = !args.includes("--no-har");
|
|
1528
|
+
|
|
1529
|
+
// Common artifact locations
|
|
1530
|
+
const locations = [
|
|
1531
|
+
{ type: "videos", dir: ".vibecheck/prove/videos", enabled: includeVideos },
|
|
1532
|
+
{ type: "traces", dir: ".vibecheck/prove/traces", enabled: includeTraces },
|
|
1533
|
+
{ type: "screenshots", dir: ".vibecheck/prove/screenshots", enabled: true },
|
|
1534
|
+
{ type: "har", dir: ".vibecheck/prove/har", enabled: includeHar },
|
|
1535
|
+
{ type: "reports", dir: ".vibecheck/scan", enabled: true },
|
|
1536
|
+
];
|
|
1537
|
+
|
|
1538
|
+
for (const loc of locations) {
|
|
1539
|
+
if (!loc.enabled) continue;
|
|
1540
|
+
|
|
1541
|
+
const dirPath = path.join(projectRoot, loc.dir);
|
|
1542
|
+
if (!fs.existsSync(dirPath)) continue;
|
|
1543
|
+
|
|
1544
|
+
const files = fs.readdirSync(dirPath);
|
|
1545
|
+
artifacts.summary[loc.type] = files.length;
|
|
1546
|
+
|
|
1547
|
+
for (const file of files) {
|
|
1548
|
+
const filePath = path.join(dirPath, file);
|
|
1549
|
+
const stats = fs.statSync(filePath);
|
|
1550
|
+
if (stats.isFile()) {
|
|
1551
|
+
const hash = crypto.createHash("md5")
|
|
1552
|
+
.update(fs.readFileSync(filePath))
|
|
1553
|
+
.digest("hex")
|
|
1554
|
+
.slice(0, 8);
|
|
1555
|
+
|
|
1556
|
+
artifacts.items.push({
|
|
1557
|
+
type: loc.type,
|
|
1558
|
+
name: file,
|
|
1559
|
+
source: filePath,
|
|
1560
|
+
size: stats.size,
|
|
1561
|
+
hash,
|
|
1562
|
+
});
|
|
1563
|
+
artifacts.count++;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
return artifacts;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
async function loadGraphData(projectRoot) {
|
|
1572
|
+
// Try various sources in order of preference
|
|
1573
|
+
const sources = [
|
|
1574
|
+
".vibecheck/proof-graph.json",
|
|
1575
|
+
".vibecheck/reality/last_reality.json",
|
|
1576
|
+
".vibecheck/prove/last_prove.json",
|
|
1577
|
+
".vibecheck/scan/last_scan.json",
|
|
1578
|
+
];
|
|
1579
|
+
|
|
1580
|
+
for (const source of sources) {
|
|
1581
|
+
const sourcePath = path.join(projectRoot, source);
|
|
1582
|
+
if (fs.existsSync(sourcePath)) {
|
|
1583
|
+
try {
|
|
1584
|
+
const data = JSON.parse(fs.readFileSync(sourcePath, "utf-8"));
|
|
1585
|
+
if (data.proofGraph) return data.proofGraph;
|
|
1586
|
+
if (data.nodes && data.edges) return data;
|
|
1587
|
+
|
|
1588
|
+
// Build from scan data
|
|
1589
|
+
if (data.findings) {
|
|
1590
|
+
return buildGraphFromScan(data);
|
|
1591
|
+
}
|
|
1592
|
+
} catch {
|
|
1593
|
+
continue;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
return null;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
function buildGraphFromScan(scanData) {
|
|
1602
|
+
const nodes = [];
|
|
1603
|
+
const edges = [];
|
|
1604
|
+
const gaps = [];
|
|
1605
|
+
const nodeIds = new Set();
|
|
1606
|
+
|
|
1607
|
+
for (const finding of (scanData.findings || [])) {
|
|
1608
|
+
if (finding.file && !nodeIds.has(`file:${finding.file}`)) {
|
|
1609
|
+
nodeIds.add(`file:${finding.file}`);
|
|
1610
|
+
nodes.push({
|
|
1611
|
+
id: `file:${finding.file}`,
|
|
1612
|
+
type: "file",
|
|
1613
|
+
label: path.basename(finding.file),
|
|
1614
|
+
path: finding.file,
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
if (finding.ruleId?.includes("ROUTE") || finding.ruleId?.includes("GHOST")) {
|
|
1619
|
+
gaps.push({
|
|
1620
|
+
type: "finding",
|
|
1621
|
+
ruleId: finding.ruleId,
|
|
1622
|
+
evidence: finding,
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
return { nodes, edges, gaps, generatedFrom: "scan" };
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
function filterGraphByQuery(graph, query) {
|
|
1631
|
+
switch (query) {
|
|
1632
|
+
case "unexecuted":
|
|
1633
|
+
return {
|
|
1634
|
+
...graph,
|
|
1635
|
+
nodes: graph.nodes?.filter(n => !n.executed) || [],
|
|
1636
|
+
edges: graph.edges?.filter(e => {
|
|
1637
|
+
const nodes = graph.nodes?.filter(n => !n.executed).map(n => n.id) || [];
|
|
1638
|
+
return nodes.includes(e.source) || nodes.includes(e.target);
|
|
1639
|
+
}) || [],
|
|
1640
|
+
};
|
|
1641
|
+
case "unhit-routes":
|
|
1642
|
+
return {
|
|
1643
|
+
...graph,
|
|
1644
|
+
nodes: graph.nodes?.filter(n => n.type === "route" && !n.hit) || [],
|
|
1645
|
+
};
|
|
1646
|
+
case "dead-ui":
|
|
1647
|
+
return {
|
|
1648
|
+
...graph,
|
|
1649
|
+
nodes: graph.nodes?.filter(n => n.type === "ui" && n.dead) || [],
|
|
1650
|
+
};
|
|
1651
|
+
case "gaps":
|
|
1652
|
+
return {
|
|
1653
|
+
...graph,
|
|
1654
|
+
nodes: graph.nodes?.filter(n => n.gap) || [],
|
|
1655
|
+
gaps: graph.gaps || [],
|
|
1656
|
+
};
|
|
1657
|
+
default:
|
|
1658
|
+
return graph;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
function limitGraphDepth(graph, depth) {
|
|
1663
|
+
// Simple depth limiting - could be more sophisticated
|
|
1664
|
+
return {
|
|
1665
|
+
...graph,
|
|
1666
|
+
nodes: graph.nodes?.slice(0, depth * 10) || [],
|
|
1667
|
+
edges: graph.edges?.slice(0, depth * 15) || [],
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1672
|
+
// OUTPUT FORMATTERS
|
|
1673
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1674
|
+
|
|
1675
|
+
function graphToDot(graph) {
|
|
1676
|
+
let dot = `digraph ProofGraph {
|
|
1677
|
+
rankdir=LR;
|
|
1678
|
+
node [shape=box, style="rounded,filled", fillcolor="#f8f9fa", fontname="Arial"];
|
|
1679
|
+
edge [color="#6c757d"];
|
|
1680
|
+
|
|
1681
|
+
// Graph metadata
|
|
1682
|
+
label="Proof Graph - ${graph.metadata?.generated || new Date().toISOString()}";
|
|
1683
|
+
labelloc=t;
|
|
1684
|
+
fontname="Arial Bold";
|
|
1685
|
+
|
|
1686
|
+
`;
|
|
1687
|
+
|
|
1688
|
+
// Group nodes by type
|
|
1689
|
+
const nodesByType = {};
|
|
1690
|
+
for (const node of (graph.nodes || [])) {
|
|
1691
|
+
const type = node.type || "unknown";
|
|
1692
|
+
if (!nodesByType[type]) nodesByType[type] = [];
|
|
1693
|
+
nodesByType[type].push(node);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
// Add subgraphs for each type
|
|
1697
|
+
for (const [type, nodes] of Object.entries(nodesByType)) {
|
|
1698
|
+
dot += ` subgraph cluster_${type} {\n`;
|
|
1699
|
+
dot += ` label="${type.toUpperCase()}";\n`;
|
|
1700
|
+
dot += ` style=dashed;\n`;
|
|
1701
|
+
|
|
1702
|
+
for (const node of nodes) {
|
|
1703
|
+
const label = (node.label || node.id).replace(/"/g, '\\"');
|
|
1704
|
+
const color = node.gap ? "#dc3545" : node.executed ? "#28a745" : "#ffc107";
|
|
1705
|
+
dot += ` "${node.id}" [label="${label}", fillcolor="${color}"];\n`;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
dot += ` }\n\n`;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// Add edges
|
|
1712
|
+
dot += " // Edges\n";
|
|
1713
|
+
for (const edge of (graph.edges || [])) {
|
|
1714
|
+
const label = edge.label ? ` [label="${edge.label}"]` : "";
|
|
1715
|
+
dot += ` "${edge.source}" -> "${edge.target}"${label};\n`;
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
dot += "}\n";
|
|
1719
|
+
return dot;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
function graphToMermaid(graph) {
|
|
1723
|
+
let mermaid = `%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#00d4ff'}}}%%
|
|
1724
|
+
graph LR
|
|
1725
|
+
`;
|
|
1726
|
+
|
|
1727
|
+
// Add nodes with styling
|
|
1728
|
+
for (const node of (graph.nodes || [])) {
|
|
1729
|
+
const safeId = node.id.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1730
|
+
const label = (node.label || node.id).replace(/"/g, "'");
|
|
1731
|
+
|
|
1732
|
+
if (node.type === "route") {
|
|
1733
|
+
mermaid += ` ${safeId}[/"${label}"/]\n`;
|
|
1734
|
+
} else if (node.type === "ui") {
|
|
1735
|
+
mermaid += ` ${safeId}(("${label}"))\n`;
|
|
1736
|
+
} else {
|
|
1737
|
+
mermaid += ` ${safeId}["${label}"]\n`;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
mermaid += "\n";
|
|
1742
|
+
|
|
1743
|
+
// Add edges
|
|
1744
|
+
for (const edge of (graph.edges || [])) {
|
|
1745
|
+
const sourceId = edge.source.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1746
|
+
const targetId = edge.target.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1747
|
+
const label = edge.label ? `|"${edge.label}"|` : "";
|
|
1748
|
+
mermaid += ` ${sourceId} -->${label} ${targetId}\n`;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
// Add styles for gaps
|
|
1752
|
+
const gapNodes = (graph.nodes || []).filter(n => n.gap);
|
|
1753
|
+
if (gapNodes.length > 0) {
|
|
1754
|
+
mermaid += "\n %% Highlight gaps\n";
|
|
1755
|
+
for (const node of gapNodes) {
|
|
1756
|
+
const safeId = node.id.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1757
|
+
mermaid += ` style ${safeId} fill:#dc3545,color:#fff\n`;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
return mermaid;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
function graphToHtml(graph) {
|
|
1765
|
+
const mermaid = graphToMermaid(graph);
|
|
1766
|
+
const stats = graph.metadata?.stats || { nodes: 0, edges: 0, gaps: 0 };
|
|
1767
|
+
|
|
1768
|
+
return `<!DOCTYPE html>
|
|
1769
|
+
<html lang="en">
|
|
1770
|
+
<head>
|
|
1771
|
+
<meta charset="UTF-8">
|
|
1772
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1773
|
+
<title>Proof Graph - VibeCheck</title>
|
|
1774
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
1775
|
+
<style>
|
|
1776
|
+
:root {
|
|
1777
|
+
--bg-primary: #0a0a1a;
|
|
1778
|
+
--bg-secondary: #1a1a2e;
|
|
1779
|
+
--accent: #00d4ff;
|
|
1780
|
+
--text: #e0e0e0;
|
|
1781
|
+
--text-dim: #888;
|
|
1782
|
+
}
|
|
1783
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
1784
|
+
body {
|
|
1785
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1786
|
+
background: var(--bg-primary);
|
|
1787
|
+
color: var(--text);
|
|
1788
|
+
min-height: 100vh;
|
|
1789
|
+
padding: 20px;
|
|
1790
|
+
}
|
|
1791
|
+
.container { max-width: 1400px; margin: 0 auto; }
|
|
1792
|
+
header {
|
|
1793
|
+
display: flex;
|
|
1794
|
+
justify-content: space-between;
|
|
1795
|
+
align-items: center;
|
|
1796
|
+
padding: 20px;
|
|
1797
|
+
background: var(--bg-secondary);
|
|
1798
|
+
border-radius: 12px;
|
|
1799
|
+
margin-bottom: 20px;
|
|
1800
|
+
}
|
|
1801
|
+
h1 { font-size: 1.5rem; color: var(--accent); }
|
|
1802
|
+
.meta { color: var(--text-dim); font-size: 0.9rem; }
|
|
1803
|
+
.stats {
|
|
1804
|
+
display: flex;
|
|
1805
|
+
gap: 30px;
|
|
1806
|
+
padding: 20px;
|
|
1807
|
+
background: var(--bg-secondary);
|
|
1808
|
+
border-radius: 12px;
|
|
1809
|
+
margin-bottom: 20px;
|
|
1810
|
+
}
|
|
1811
|
+
.stat { text-align: center; }
|
|
1812
|
+
.stat-value { font-size: 2rem; font-weight: bold; color: var(--accent); }
|
|
1813
|
+
.stat-label { color: var(--text-dim); font-size: 0.85rem; text-transform: uppercase; }
|
|
1814
|
+
.graph-container {
|
|
1815
|
+
background: #fff;
|
|
1816
|
+
border-radius: 12px;
|
|
1817
|
+
padding: 30px;
|
|
1818
|
+
overflow: auto;
|
|
1819
|
+
}
|
|
1820
|
+
.mermaid { min-height: 400px; }
|
|
1821
|
+
footer {
|
|
1822
|
+
margin-top: 20px;
|
|
1823
|
+
padding: 15px;
|
|
1824
|
+
text-align: center;
|
|
1825
|
+
color: var(--text-dim);
|
|
1826
|
+
font-size: 0.85rem;
|
|
1827
|
+
}
|
|
1828
|
+
footer a { color: var(--accent); text-decoration: none; }
|
|
1829
|
+
</style>
|
|
1830
|
+
</head>
|
|
1831
|
+
<body>
|
|
1832
|
+
<div class="container">
|
|
1833
|
+
<header>
|
|
1834
|
+
<h1>Proof Graph</h1>
|
|
1835
|
+
<div class="meta">Generated: ${graph.metadata?.generated || new Date().toISOString()}</div>
|
|
1836
|
+
</header>
|
|
1837
|
+
|
|
1838
|
+
<div class="stats">
|
|
1839
|
+
<div class="stat">
|
|
1840
|
+
<div class="stat-value">${stats.nodes}</div>
|
|
1841
|
+
<div class="stat-label">Nodes</div>
|
|
1842
|
+
</div>
|
|
1843
|
+
<div class="stat">
|
|
1844
|
+
<div class="stat-value">${stats.edges}</div>
|
|
1845
|
+
<div class="stat-label">Edges</div>
|
|
1846
|
+
</div>
|
|
1847
|
+
<div class="stat">
|
|
1848
|
+
<div class="stat-value">${stats.gaps}</div>
|
|
1849
|
+
<div class="stat-label">Gaps</div>
|
|
1850
|
+
</div>
|
|
1851
|
+
</div>
|
|
1852
|
+
|
|
1853
|
+
<div class="graph-container">
|
|
1854
|
+
<pre class="mermaid">
|
|
1855
|
+
${mermaid}
|
|
1856
|
+
</pre>
|
|
1857
|
+
</div>
|
|
1858
|
+
|
|
1859
|
+
<footer>
|
|
1860
|
+
Powered by <a href="https://vibecheckai.dev">VibeCheck</a> v${PACKS_VERSION}
|
|
1861
|
+
</footer>
|
|
1862
|
+
</div>
|
|
1863
|
+
|
|
1864
|
+
<script>
|
|
1865
|
+
mermaid.initialize({
|
|
1866
|
+
startOnLoad: true,
|
|
1867
|
+
theme: 'default',
|
|
1868
|
+
securityLevel: 'loose',
|
|
1869
|
+
});
|
|
1870
|
+
</script>
|
|
1871
|
+
</body>
|
|
1872
|
+
</html>`;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
function generateHtmlViewer(manifest) {
|
|
1876
|
+
return `<!DOCTYPE html>
|
|
1877
|
+
<html lang="en">
|
|
1878
|
+
<head>
|
|
1879
|
+
<meta charset="UTF-8">
|
|
1880
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1881
|
+
<title>Evidence Pack - ${manifest.id}</title>
|
|
1882
|
+
<style>
|
|
1883
|
+
:root {
|
|
1884
|
+
--bg: #0a0a1a;
|
|
1885
|
+
--card: #1a1a2e;
|
|
1886
|
+
--accent: #00d4ff;
|
|
1887
|
+
--text: #e0e0e0;
|
|
1888
|
+
--dim: #666;
|
|
1889
|
+
}
|
|
1890
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
1891
|
+
body { font-family: system-ui, sans-serif; background: var(--bg); color: var(--text); padding: 20px; }
|
|
1892
|
+
.container { max-width: 1200px; margin: 0 auto; }
|
|
1893
|
+
header { text-align: center; padding: 40px 0; }
|
|
1894
|
+
h1 { color: var(--accent); margin-bottom: 10px; }
|
|
1895
|
+
.id { color: var(--dim); font-family: monospace; }
|
|
1896
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 30px; }
|
|
1897
|
+
.card { background: var(--card); border-radius: 12px; padding: 20px; }
|
|
1898
|
+
.card h3 { color: var(--accent); margin-bottom: 15px; }
|
|
1899
|
+
.artifact { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #333; }
|
|
1900
|
+
.artifact:last-child { border-bottom: none; }
|
|
1901
|
+
.artifact-name { font-family: monospace; }
|
|
1902
|
+
.artifact-size { color: var(--dim); }
|
|
1903
|
+
</style>
|
|
1904
|
+
</head>
|
|
1905
|
+
<body>
|
|
1906
|
+
<div class="container">
|
|
1907
|
+
<header>
|
|
1908
|
+
<h1>Evidence Pack</h1>
|
|
1909
|
+
<div class="id">${manifest.id}</div>
|
|
1910
|
+
<p style="color: var(--dim); margin-top: 10px;">Generated: ${manifest.generated}</p>
|
|
1911
|
+
</header>
|
|
1912
|
+
|
|
1913
|
+
<div class="grid">
|
|
1914
|
+
${Object.entries(manifest.summary || {}).map(([type, count]) => `
|
|
1915
|
+
<div class="card">
|
|
1916
|
+
<h3>${type.charAt(0).toUpperCase() + type.slice(1)}</h3>
|
|
1917
|
+
<p>${count} files</p>
|
|
1918
|
+
${(manifest.artifacts || []).filter(a => a.type === type).map(a => `
|
|
1919
|
+
<div class="artifact">
|
|
1920
|
+
<span class="artifact-name">${a.name}</span>
|
|
1921
|
+
<span class="artifact-size">${formatBytes(a.size)}</span>
|
|
1922
|
+
</div>
|
|
1923
|
+
`).join('')}
|
|
1924
|
+
</div>
|
|
1925
|
+
`).join('')}
|
|
1926
|
+
</div>
|
|
1927
|
+
</div>
|
|
1928
|
+
|
|
1929
|
+
<script>
|
|
1930
|
+
function formatBytes(bytes) {
|
|
1931
|
+
if (bytes === 0) return '0 B';
|
|
1932
|
+
const k = 1024;
|
|
1933
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
1934
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1935
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
1936
|
+
}
|
|
1937
|
+
</script>
|
|
1938
|
+
</body>
|
|
1939
|
+
</html>`;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
function formatBytes(bytes) {
|
|
1943
|
+
if (bytes === 0) return '0 B';
|
|
1944
|
+
const k = 1024;
|
|
1945
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
1946
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1947
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
function generateSarif(report) {
|
|
1951
|
+
return JSON.stringify({
|
|
1952
|
+
$schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
|
1953
|
+
version: "2.1.0",
|
|
1954
|
+
runs: [{
|
|
1955
|
+
tool: {
|
|
1956
|
+
driver: {
|
|
1957
|
+
name: "VibeCheck",
|
|
1958
|
+
version: PACKS_VERSION,
|
|
1959
|
+
informationUri: "https://vibecheckai.dev",
|
|
1960
|
+
rules: [],
|
|
1961
|
+
},
|
|
1962
|
+
},
|
|
1963
|
+
results: (report.findings || []).map(f => ({
|
|
1964
|
+
ruleId: f.ruleId || f.id || "unknown",
|
|
1965
|
+
message: { text: f.message || f.description },
|
|
1966
|
+
level: f.severity === "critical" ? "error" : f.severity === "high" ? "error" : "warning",
|
|
1967
|
+
locations: f.file ? [{
|
|
1968
|
+
physicalLocation: {
|
|
1969
|
+
artifactLocation: { uri: f.file },
|
|
1970
|
+
region: { startLine: f.line || 1 },
|
|
1971
|
+
},
|
|
1972
|
+
}] : [],
|
|
1973
|
+
})),
|
|
1974
|
+
}],
|
|
1975
|
+
}, null, 2);
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
function generateMarkdownReport(report) {
|
|
1979
|
+
return `# VibeCheck Report
|
|
1980
|
+
|
|
1981
|
+
Generated: ${report.generated}
|
|
1982
|
+
Type: ${report.type}
|
|
1983
|
+
|
|
1984
|
+
## Summary
|
|
1985
|
+
|
|
1986
|
+
| Severity | Count |
|
|
1987
|
+
|----------|-------|
|
|
1988
|
+
| Critical | ${report.summary.critical} |
|
|
1989
|
+
| High | ${report.summary.high} |
|
|
1990
|
+
| Medium | ${report.summary.medium} |
|
|
1991
|
+
| Low | ${report.summary.low} |
|
|
1992
|
+
| **Total** | **${report.summary.total}** |
|
|
1993
|
+
|
|
1994
|
+
## Findings
|
|
1995
|
+
|
|
1996
|
+
${(report.findings || []).map(f => `
|
|
1997
|
+
### ${f.ruleId || f.id}
|
|
1998
|
+
|
|
1999
|
+
- **Severity**: ${f.severity}
|
|
2000
|
+
- **File**: ${f.file || 'N/A'}
|
|
2001
|
+
- **Line**: ${f.line || 'N/A'}
|
|
2002
|
+
|
|
2003
|
+
${f.message || f.description}
|
|
2004
|
+
`).join('\n---\n')}
|
|
2005
|
+
|
|
2006
|
+
---
|
|
2007
|
+
*Generated by VibeCheck v${PACKS_VERSION}*
|
|
2008
|
+
`;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
function generateHtmlReport(report) {
|
|
2012
|
+
return `<!DOCTYPE html>
|
|
2013
|
+
<html lang="en">
|
|
2014
|
+
<head>
|
|
2015
|
+
<meta charset="UTF-8">
|
|
2016
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2017
|
+
<title>VibeCheck Report</title>
|
|
2018
|
+
<style>
|
|
2019
|
+
:root { --accent: #00d4ff; --bg: #0a0a1a; --card: #1a1a2e; --text: #e0e0e0; }
|
|
2020
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
2021
|
+
body { font-family: system-ui, sans-serif; background: var(--bg); color: var(--text); padding: 40px; }
|
|
2022
|
+
.container { max-width: 1000px; margin: 0 auto; }
|
|
2023
|
+
h1 { color: var(--accent); margin-bottom: 30px; }
|
|
2024
|
+
.summary { display: flex; gap: 20px; margin-bottom: 40px; }
|
|
2025
|
+
.stat { background: var(--card); padding: 20px; border-radius: 12px; text-align: center; flex: 1; }
|
|
2026
|
+
.stat-value { font-size: 2rem; font-weight: bold; }
|
|
2027
|
+
.stat-label { color: #888; font-size: 0.85rem; }
|
|
2028
|
+
.critical { color: #dc3545; }
|
|
2029
|
+
.high { color: #fd7e14; }
|
|
2030
|
+
.medium { color: #ffc107; }
|
|
2031
|
+
.low { color: #28a745; }
|
|
2032
|
+
.finding { background: var(--card); padding: 20px; border-radius: 12px; margin-bottom: 15px; }
|
|
2033
|
+
.finding-header { display: flex; justify-content: space-between; margin-bottom: 10px; }
|
|
2034
|
+
.finding-id { font-family: monospace; color: var(--accent); }
|
|
2035
|
+
.finding-file { color: #888; font-size: 0.9rem; }
|
|
2036
|
+
</style>
|
|
2037
|
+
</head>
|
|
2038
|
+
<body>
|
|
2039
|
+
<div class="container">
|
|
2040
|
+
<h1>VibeCheck Report</h1>
|
|
2041
|
+
|
|
2042
|
+
<div class="summary">
|
|
2043
|
+
<div class="stat"><div class="stat-value critical">${report.summary.critical}</div><div class="stat-label">Critical</div></div>
|
|
2044
|
+
<div class="stat"><div class="stat-value high">${report.summary.high}</div><div class="stat-label">High</div></div>
|
|
2045
|
+
<div class="stat"><div class="stat-value medium">${report.summary.medium}</div><div class="stat-label">Medium</div></div>
|
|
2046
|
+
<div class="stat"><div class="stat-value low">${report.summary.low}</div><div class="stat-label">Low</div></div>
|
|
2047
|
+
</div>
|
|
2048
|
+
|
|
2049
|
+
<h2 style="margin-bottom: 20px;">Findings</h2>
|
|
2050
|
+
|
|
2051
|
+
${(report.findings || []).map(f => `
|
|
2052
|
+
<div class="finding">
|
|
2053
|
+
<div class="finding-header">
|
|
2054
|
+
<span class="finding-id">${f.ruleId || f.id}</span>
|
|
2055
|
+
<span class="finding-severity ${f.severity}">${f.severity?.toUpperCase()}</span>
|
|
2056
|
+
</div>
|
|
2057
|
+
<p>${f.message || f.description}</p>
|
|
2058
|
+
${f.file ? `<div class="finding-file">${f.file}${f.line ? `:${f.line}` : ''}</div>` : ''}
|
|
2059
|
+
</div>
|
|
2060
|
+
`).join('')}
|
|
2061
|
+
</div>
|
|
2062
|
+
</body>
|
|
2063
|
+
</html>`;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2067
|
+
// EXPORTS
|
|
2068
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2069
|
+
|
|
2070
|
+
module.exports = {
|
|
2071
|
+
runPacks,
|
|
2072
|
+
// Export constants for testing
|
|
2073
|
+
PACKS_VERSION,
|
|
2074
|
+
SUBCOMMANDS,
|
|
2075
|
+
GRAPH_QUERIES,
|
|
2076
|
+
// Export individual handlers (V2)
|
|
2077
|
+
handleBundle,
|
|
2078
|
+
handleEvidenceV2,
|
|
2079
|
+
handlePermissionsV2,
|
|
2080
|
+
handleGraphV2,
|
|
2081
|
+
handleList,
|
|
2082
|
+
handleCleanup,
|
|
2083
|
+
// Legacy handlers
|
|
2084
|
+
handleEvidence,
|
|
2085
|
+
handleReport,
|
|
2086
|
+
handleGraph,
|
|
2087
|
+
handlePermissions,
|
|
2088
|
+
handleManifest,
|
|
2089
|
+
};
|