vibecheck-ai 2.0.2 → 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,1282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibecheck shield - Agent Firewall™
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* ENTERPRISE-GRADE AI ENFORCEMENT LAYER
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
*
|
|
8
|
+
* The Agent Firewall is the core enforcement primitive in VibeCheck.
|
|
9
|
+
* It intercepts AI actions at multiple levels:
|
|
10
|
+
*
|
|
11
|
+
* 1. PROMPT LEVEL - Injection detection before AI execution
|
|
12
|
+
* 2. FILE WRITE - Intercept IDE/AI file changes in real-time
|
|
13
|
+
* 3. CLAIM VALIDATION - Verify changes against truthpack evidence
|
|
14
|
+
* 4. VERDICT - ALLOW / WARN / BLOCK decision with proof chain
|
|
15
|
+
*
|
|
16
|
+
* Unlike advisory tools, Shield actually STOPS bad changes.
|
|
17
|
+
*
|
|
18
|
+
* Unifies: guard, firewall, agent, validate, prompt-firewall
|
|
19
|
+
*
|
|
20
|
+
* @module runShield
|
|
21
|
+
* @version 4.0.0
|
|
22
|
+
* @license MIT
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
"use strict";
|
|
26
|
+
|
|
27
|
+
const path = require("path");
|
|
28
|
+
const fs = require("fs");
|
|
29
|
+
|
|
30
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
31
|
+
// LAZY IMPORTS - Enterprise startup optimization
|
|
32
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
33
|
+
|
|
34
|
+
let _globalFlags = null;
|
|
35
|
+
let _exitCodes = null;
|
|
36
|
+
let _cliOutput = null;
|
|
37
|
+
|
|
38
|
+
function getGlobalFlags() {
|
|
39
|
+
if (!_globalFlags) {
|
|
40
|
+
_globalFlags = require("./lib/global-flags");
|
|
41
|
+
}
|
|
42
|
+
return _globalFlags;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getExitCodes() {
|
|
46
|
+
if (!_exitCodes) {
|
|
47
|
+
_exitCodes = require("./lib/exit-codes");
|
|
48
|
+
}
|
|
49
|
+
return _exitCodes;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getCliOutput() {
|
|
53
|
+
if (!_cliOutput) {
|
|
54
|
+
_cliOutput = require("./lib/unified-cli-output");
|
|
55
|
+
}
|
|
56
|
+
return _cliOutput;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
60
|
+
// UNDERLYING IMPLEMENTATIONS - Lazy loaded for performance
|
|
61
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
62
|
+
|
|
63
|
+
const implementations = {
|
|
64
|
+
firewall: null,
|
|
65
|
+
agent: null,
|
|
66
|
+
guard: null,
|
|
67
|
+
validate: null,
|
|
68
|
+
promptFirewall: null,
|
|
69
|
+
orchestrator: null,
|
|
70
|
+
intentStore: null,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function loadImplementation(name) {
|
|
74
|
+
if (implementations[name] !== null) return implementations[name];
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
switch (name) {
|
|
78
|
+
case "firewall":
|
|
79
|
+
implementations[name] = require("./runFirewall");
|
|
80
|
+
break;
|
|
81
|
+
case "agent":
|
|
82
|
+
implementations[name] = require("./runAgent");
|
|
83
|
+
break;
|
|
84
|
+
case "guard":
|
|
85
|
+
implementations[name] = require("./runGuard").runGuard;
|
|
86
|
+
break;
|
|
87
|
+
case "validate":
|
|
88
|
+
implementations[name] = require("./runValidate").runValidate;
|
|
89
|
+
break;
|
|
90
|
+
case "promptFirewall":
|
|
91
|
+
implementations[name] = require("./runPromptFirewall").runPromptFirewall;
|
|
92
|
+
break;
|
|
93
|
+
case "orchestrator":
|
|
94
|
+
implementations[name] = require("./lib/agent-firewall/enforcement").createOrchestrator;
|
|
95
|
+
break;
|
|
96
|
+
case "intentStore":
|
|
97
|
+
implementations[name] = require("./lib/agent-firewall/intent").IntentStore;
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
implementations[name] = false;
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
implementations[name] = false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return implementations[name];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
110
|
+
// CONSTANTS
|
|
111
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
112
|
+
|
|
113
|
+
const SHIELD_VERSION = "4.0.0";
|
|
114
|
+
|
|
115
|
+
const SUBCOMMANDS = {
|
|
116
|
+
status: { description: "Show firewall status and configuration", pro: false },
|
|
117
|
+
enforce: { description: "Enable enforcement mode (block violations)", pro: true },
|
|
118
|
+
observe: { description: "Enable observe-only mode (log only)", pro: false },
|
|
119
|
+
lock: { description: "Hard lockdown - all rules enforced", pro: true },
|
|
120
|
+
unlock: { description: "Release lock, return to observe mode", pro: true },
|
|
121
|
+
verify: { description: "Verify AI claims, prompts, hallucinations", pro: true },
|
|
122
|
+
check: { description: "Run v2 enforcement check on staged/recent changes", pro: true },
|
|
123
|
+
install: { description: "Install IDE hooks for interception", pro: true },
|
|
124
|
+
stats: { description: "Show firewall statistics and metrics", pro: false },
|
|
125
|
+
audit: { description: "Audit recent change packets", pro: true },
|
|
126
|
+
policy: { description: "View or edit policy configuration", pro: true },
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const ENFORCEMENT_RULES = [
|
|
130
|
+
{ id: "ghost_route", name: "Ghost Route", description: "Block undeclared routes", severity: "block" },
|
|
131
|
+
{ id: "ghost_env", name: "Ghost Env", description: "Block undeclared env vars", severity: "block" },
|
|
132
|
+
{ id: "auth_drift", name: "Auth Drift", description: "Detect auth pattern changes", severity: "block" },
|
|
133
|
+
{ id: "contract_drift", name: "Contract Drift", description: "Detect contract violations", severity: "block" },
|
|
134
|
+
{ id: "scope_explosion", name: "Scope Explosion", description: "Detect scope creep", severity: "warn" },
|
|
135
|
+
{ id: "unsafe_side_effect", name: "Unsafe Side Effect", description: "Block unsafe operations", severity: "block" },
|
|
136
|
+
{ id: "fake_success", name: "Fake Success", description: "Detect fake success UI", severity: "warn" },
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
140
|
+
// ENTERPRISE HELP SYSTEM
|
|
141
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
142
|
+
|
|
143
|
+
function printHelp(detailed = false) {
|
|
144
|
+
const { ansi } = getCliOutput();
|
|
145
|
+
|
|
146
|
+
const header = `
|
|
147
|
+
${ansi.bold}${ansi.cyan}╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
148
|
+
║ ║
|
|
149
|
+
║ ${ansi.reset}${ansi.bold}AGENT FIREWALL™${ansi.cyan} ║
|
|
150
|
+
║ ${ansi.reset}${ansi.dim}The AI Enforcement Layer${ansi.cyan} ║
|
|
151
|
+
║ ║
|
|
152
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝${ansi.reset}
|
|
153
|
+
|
|
154
|
+
${ansi.bold}USAGE${ansi.reset}
|
|
155
|
+
${ansi.cyan}vibecheck shield${ansi.reset} <subcommand> [options]
|
|
156
|
+
|
|
157
|
+
${ansi.dim}Intercept AI actions, validate claims against truthpack, and block
|
|
158
|
+
unauthorized changes in real-time. The core enforcement primitive.${ansi.reset}
|
|
159
|
+
|
|
160
|
+
${ansi.bold}SUBCOMMANDS${ansi.reset}`;
|
|
161
|
+
|
|
162
|
+
console.log(header);
|
|
163
|
+
|
|
164
|
+
// Print subcommands with alignment
|
|
165
|
+
const maxLen = Math.max(...Object.keys(SUBCOMMANDS).map(k => k.length));
|
|
166
|
+
for (const [name, info] of Object.entries(SUBCOMMANDS)) {
|
|
167
|
+
const proTag = info.pro ? `${ansi.magenta}PRO${ansi.reset} ` : " ";
|
|
168
|
+
console.log(` ${ansi.cyan}${name.padEnd(maxLen + 2)}${ansi.reset}${proTag}${info.description}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(`
|
|
172
|
+
${ansi.bold}VERIFY OPTIONS${ansi.reset}
|
|
173
|
+
${ansi.cyan}--claims${ansi.reset} Verify AI claims against truthpack
|
|
174
|
+
${ansi.cyan}--prompts${ansi.reset} Check for prompt injection attacks
|
|
175
|
+
${ansi.cyan}--hallucinations${ansi.reset} Detect hallucination patterns
|
|
176
|
+
${ansi.cyan}--file <path>${ansi.reset} Check specific file(s)
|
|
177
|
+
${ansi.cyan}--strict${ansi.reset} Fail on warnings (not just errors)
|
|
178
|
+
|
|
179
|
+
${ansi.bold}CHECK (v2) OPTIONS${ansi.reset}
|
|
180
|
+
${ansi.cyan}--staged${ansi.reset} Check only staged git changes
|
|
181
|
+
${ansi.cyan}--recent${ansi.reset} Check changes since last commit
|
|
182
|
+
|
|
183
|
+
${ansi.bold}GENERAL OPTIONS${ansi.reset}
|
|
184
|
+
${ansi.cyan}--json${ansi.reset} Output as JSON (CI integration)
|
|
185
|
+
${ansi.cyan}--quiet, -q${ansi.reset} Suppress non-essential output
|
|
186
|
+
${ansi.cyan}--verbose, -v${ansi.reset} Show detailed output
|
|
187
|
+
${ansi.cyan}--help, -h${ansi.reset} Show this help
|
|
188
|
+
|
|
189
|
+
${ansi.bold}EXAMPLES${ansi.reset}
|
|
190
|
+
${ansi.dim}# Check firewall status${ansi.reset}
|
|
191
|
+
vibecheck shield status
|
|
192
|
+
|
|
193
|
+
${ansi.dim}# Enable enforcement mode (blocks violations)${ansi.reset}
|
|
194
|
+
vibecheck shield enforce
|
|
195
|
+
|
|
196
|
+
${ansi.dim}# Full lockdown (all hard rules enforced)${ansi.reset}
|
|
197
|
+
vibecheck shield lock
|
|
198
|
+
|
|
199
|
+
${ansi.dim}# Verify AI claims${ansi.reset}
|
|
200
|
+
vibecheck shield verify --claims
|
|
201
|
+
|
|
202
|
+
${ansi.dim}# Install IDE hooks${ansi.reset}
|
|
203
|
+
vibecheck shield install
|
|
204
|
+
|
|
205
|
+
${ansi.dim}# CI integration (JSON output, strict mode)${ansi.reset}
|
|
206
|
+
vibecheck shield verify --claims --strict --json`);
|
|
207
|
+
|
|
208
|
+
if (detailed) {
|
|
209
|
+
console.log(`
|
|
210
|
+
${ansi.bold}INTERCEPTION ARCHITECTURE${ansi.reset}
|
|
211
|
+
${ansi.dim}┌─────────────────────────────────────────────────────────────────┐
|
|
212
|
+
│ 1. PROMPT LEVEL - Injection detection before AI execution │
|
|
213
|
+
│ 2. FILE WRITE - Intercept IDE/AI file changes │
|
|
214
|
+
│ 3. CLAIM VALIDATION - Verify changes against truthpack │
|
|
215
|
+
│ 4. VERDICT - ALLOW / WARN / BLOCK decision │
|
|
216
|
+
└─────────────────────────────────────────────────────────────────┘${ansi.reset}
|
|
217
|
+
|
|
218
|
+
${ansi.bold}ENFORCEMENT RULES${ansi.reset}`);
|
|
219
|
+
|
|
220
|
+
for (const rule of ENFORCEMENT_RULES) {
|
|
221
|
+
const severityColor = rule.severity === "block" ? ansi.red : ansi.yellow;
|
|
222
|
+
console.log(` ${ansi.dim}•${ansi.reset} ${ansi.cyan}${rule.id.padEnd(20)}${ansi.reset} ${severityColor}${rule.severity.toUpperCase().padEnd(5)}${ansi.reset} ${rule.description}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
console.log(`
|
|
227
|
+
${ansi.bold}EXIT CODES${ansi.reset}
|
|
228
|
+
${ansi.green}0${ansi.reset} All checks passed / operation successful
|
|
229
|
+
${ansi.yellow}1${ansi.reset} Warnings found (non-blocking)
|
|
230
|
+
${ansi.red}2${ansi.reset} Violations found (blocking issues)
|
|
231
|
+
${ansi.red}3${ansi.reset} Configuration error
|
|
232
|
+
${ansi.red}4${ansi.reset} Internal error
|
|
233
|
+
|
|
234
|
+
${ansi.dim}────────────────────────────────────────────────────────────────────${ansi.reset}
|
|
235
|
+
${ansi.dim}Documentation: https://docs.vibecheckai.dev/cli/shield${ansi.reset}
|
|
236
|
+
${ansi.dim}Version: ${SHIELD_VERSION}${ansi.reset}
|
|
237
|
+
`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
241
|
+
// MAIN ENTRY POINT
|
|
242
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Main shield command handler
|
|
246
|
+
*
|
|
247
|
+
* @param {string[]} args - Command arguments
|
|
248
|
+
* @param {Object} context - Execution context
|
|
249
|
+
* @param {string} context.repoRoot - Repository root path
|
|
250
|
+
* @returns {Promise<number>} Exit code
|
|
251
|
+
*/
|
|
252
|
+
async function runShield(args = [], context = {}) {
|
|
253
|
+
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = getGlobalFlags();
|
|
254
|
+
const { EXIT } = getExitCodes();
|
|
255
|
+
|
|
256
|
+
const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
|
|
257
|
+
const quiet = shouldSuppressOutput(globalFlags);
|
|
258
|
+
const json = isJsonMode(globalFlags) || args.includes("--json");
|
|
259
|
+
const verbose = args.includes("--verbose") || args.includes("-v");
|
|
260
|
+
const projectRoot = context.repoRoot || globalFlags.path || process.cwd();
|
|
261
|
+
|
|
262
|
+
// Parse subcommand
|
|
263
|
+
const subcommand = cleanArgs[0] || "status";
|
|
264
|
+
const subArgs = cleanArgs.slice(1);
|
|
265
|
+
|
|
266
|
+
// Handle help
|
|
267
|
+
if (globalFlags.help || args.includes("--help") || args.includes("-h")) {
|
|
268
|
+
if (!subcommand || ["--help", "-h"].includes(subcommand)) {
|
|
269
|
+
printHelp(verbose);
|
|
270
|
+
return EXIT.SUCCESS;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Create execution context
|
|
275
|
+
const execContext = {
|
|
276
|
+
projectRoot,
|
|
277
|
+
json,
|
|
278
|
+
quiet,
|
|
279
|
+
verbose,
|
|
280
|
+
args: subArgs,
|
|
281
|
+
originalArgs: args,
|
|
282
|
+
startTime: Date.now(),
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
// Route to appropriate handler
|
|
287
|
+
switch (subcommand) {
|
|
288
|
+
case "status":
|
|
289
|
+
return await handleStatus(execContext);
|
|
290
|
+
|
|
291
|
+
case "enforce":
|
|
292
|
+
return await handleSetMode("enforce", execContext);
|
|
293
|
+
|
|
294
|
+
case "observe":
|
|
295
|
+
return await handleSetMode("observe", execContext);
|
|
296
|
+
|
|
297
|
+
case "lock":
|
|
298
|
+
return await handleLock(execContext);
|
|
299
|
+
|
|
300
|
+
case "unlock":
|
|
301
|
+
return await handleUnlock(execContext);
|
|
302
|
+
|
|
303
|
+
case "verify":
|
|
304
|
+
return await handleVerify(execContext);
|
|
305
|
+
|
|
306
|
+
case "check":
|
|
307
|
+
return await handleCheck(execContext);
|
|
308
|
+
|
|
309
|
+
case "install":
|
|
310
|
+
return await handleInstall(execContext);
|
|
311
|
+
|
|
312
|
+
case "stats":
|
|
313
|
+
return await handleStats(execContext);
|
|
314
|
+
|
|
315
|
+
case "audit":
|
|
316
|
+
return await handleAudit(execContext);
|
|
317
|
+
|
|
318
|
+
case "policy":
|
|
319
|
+
return await handlePolicy(execContext);
|
|
320
|
+
|
|
321
|
+
default:
|
|
322
|
+
// If it looks like a verify flag, pass to verify
|
|
323
|
+
if (subcommand.startsWith("--")) {
|
|
324
|
+
execContext.args = cleanArgs;
|
|
325
|
+
return await handleVerify(execContext);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return handleUnknownSubcommand(subcommand, execContext);
|
|
329
|
+
}
|
|
330
|
+
} catch (error) {
|
|
331
|
+
return handleError(error, execContext);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
336
|
+
// SUBCOMMAND HANDLERS
|
|
337
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Handle status subcommand
|
|
341
|
+
*/
|
|
342
|
+
async function handleStatus(ctx) {
|
|
343
|
+
const { EXIT } = getExitCodes();
|
|
344
|
+
const { ansi, sym, renderMinimalHeader, renderSectionHeader, renderFooter } = getCliOutput();
|
|
345
|
+
|
|
346
|
+
const firewall = loadImplementation("firewall");
|
|
347
|
+
const agent = loadImplementation("agent");
|
|
348
|
+
|
|
349
|
+
// Gather status from all sources
|
|
350
|
+
const status = firewall ? await firewall.runFirewall({ status: true, projectRoot: ctx.projectRoot }) : { mode: "unknown", error: "Firewall module not available" };
|
|
351
|
+
const agentStatus = agent ? await agent.runAgent({ action: "status", projectRoot: ctx.projectRoot }) : { installed: false };
|
|
352
|
+
|
|
353
|
+
// Check truthpack freshness
|
|
354
|
+
let truthpackAge = null;
|
|
355
|
+
const truthpackPath = path.join(ctx.projectRoot, ".vibecheck", "truthpack.json");
|
|
356
|
+
if (fs.existsSync(truthpackPath)) {
|
|
357
|
+
const stats = fs.statSync(truthpackPath);
|
|
358
|
+
truthpackAge = Date.now() - stats.mtimeMs;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const result = {
|
|
362
|
+
shield: {
|
|
363
|
+
version: SHIELD_VERSION,
|
|
364
|
+
mode: status.mode || "unknown",
|
|
365
|
+
profile: status.profile || "default",
|
|
366
|
+
locked: agentStatus.locked || false,
|
|
367
|
+
},
|
|
368
|
+
hooks: {
|
|
369
|
+
installed: agentStatus.installed || false,
|
|
370
|
+
},
|
|
371
|
+
truthpack: {
|
|
372
|
+
fresh: status.truthpackFresh || false,
|
|
373
|
+
age: truthpackAge ? `${Math.round(truthpackAge / 1000 / 60)}m ago` : "unknown",
|
|
374
|
+
},
|
|
375
|
+
rules: {
|
|
376
|
+
enabled: status.rulesEnabled || 0,
|
|
377
|
+
total: ENFORCEMENT_RULES.length,
|
|
378
|
+
},
|
|
379
|
+
health: calculateHealth(status, agentStatus),
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
if (ctx.json) {
|
|
383
|
+
console.log(JSON.stringify(result, null, 2));
|
|
384
|
+
} else if (!ctx.quiet) {
|
|
385
|
+
renderMinimalHeader("shield", "pro");
|
|
386
|
+
renderSectionHeader("Agent Firewall Status", sym.shield);
|
|
387
|
+
|
|
388
|
+
// Mode indicator with color
|
|
389
|
+
const modeColor = result.shield.mode === "enforce" ? ansi.green :
|
|
390
|
+
result.shield.mode === "observe" ? ansi.yellow : ansi.red;
|
|
391
|
+
const lockIcon = result.shield.locked ? ` ${ansi.red}🔒${ansi.reset}` : "";
|
|
392
|
+
|
|
393
|
+
console.log(`
|
|
394
|
+
${ansi.bold}Shield Configuration${ansi.reset}
|
|
395
|
+
${ansi.dim}Mode:${ansi.reset} ${modeColor}${result.shield.mode.toUpperCase()}${ansi.reset}${lockIcon}
|
|
396
|
+
${ansi.dim}Profile:${ansi.reset} ${result.shield.profile}
|
|
397
|
+
${ansi.dim}Version:${ansi.reset} ${result.shield.version}
|
|
398
|
+
|
|
399
|
+
${ansi.bold}Interception${ansi.reset}
|
|
400
|
+
${ansi.dim}IDE Hooks:${ansi.reset} ${result.hooks.installed ? ansi.green + "✓ Installed" : ansi.yellow + "○ Not installed"}${ansi.reset}
|
|
401
|
+
${ansi.dim}Truthpack:${ansi.reset} ${result.truthpack.fresh ? ansi.green + "✓ Fresh" : ansi.yellow + "○ Stale"}${ansi.reset} ${ansi.dim}(${result.truthpack.age})${ansi.reset}
|
|
402
|
+
${ansi.dim}Rules:${ansi.reset} ${result.rules.enabled}/${result.rules.total} enabled
|
|
403
|
+
|
|
404
|
+
${ansi.bold}Health${ansi.reset}
|
|
405
|
+
${ansi.dim}Overall:${ansi.reset} ${renderHealthBadge(result.health, ansi)}
|
|
406
|
+
`);
|
|
407
|
+
|
|
408
|
+
// Recommendations
|
|
409
|
+
const recommendations = [];
|
|
410
|
+
if (!result.hooks.installed) {
|
|
411
|
+
recommendations.push({ cmd: "vibecheck shield install", desc: "Install IDE hooks" });
|
|
412
|
+
}
|
|
413
|
+
if (result.shield.mode === "observe") {
|
|
414
|
+
recommendations.push({ cmd: "vibecheck shield enforce", desc: "Enable enforcement" });
|
|
415
|
+
}
|
|
416
|
+
if (!result.truthpack.fresh) {
|
|
417
|
+
recommendations.push({ cmd: "vibecheck audit", desc: "Refresh truthpack" });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (recommendations.length > 0) {
|
|
421
|
+
renderFooter({
|
|
422
|
+
nextSteps: recommendations,
|
|
423
|
+
docsUrl: "https://docs.vibecheckai.dev/cli/shield",
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return EXIT.SUCCESS;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Handle enforce/observe mode setting
|
|
433
|
+
*/
|
|
434
|
+
async function handleSetMode(mode, ctx) {
|
|
435
|
+
const { EXIT } = getExitCodes();
|
|
436
|
+
const { ansi, renderSuccess, renderError, renderWarning } = getCliOutput();
|
|
437
|
+
|
|
438
|
+
const firewall = loadImplementation("firewall");
|
|
439
|
+
if (!firewall) {
|
|
440
|
+
return handleModuleNotAvailable("firewall", ctx);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const result = await firewall.runFirewall({ mode, projectRoot: ctx.projectRoot });
|
|
444
|
+
|
|
445
|
+
if (ctx.json) {
|
|
446
|
+
console.log(JSON.stringify({
|
|
447
|
+
success: result.success,
|
|
448
|
+
mode,
|
|
449
|
+
message: result.message,
|
|
450
|
+
timestamp: new Date().toISOString(),
|
|
451
|
+
}, null, 2));
|
|
452
|
+
} else if (!ctx.quiet) {
|
|
453
|
+
if (result.success) {
|
|
454
|
+
if (mode === "enforce") {
|
|
455
|
+
renderSuccess("Enforcement mode ENABLED");
|
|
456
|
+
console.log(`
|
|
457
|
+
${ansi.dim}Shield will now BLOCK violations:${ansi.reset}
|
|
458
|
+
${ansi.red}•${ansi.reset} Ghost routes/env vars
|
|
459
|
+
${ansi.red}•${ansi.reset} Auth drift
|
|
460
|
+
${ansi.red}•${ansi.reset} Contract violations
|
|
461
|
+
${ansi.red}•${ansi.reset} Unsafe side effects
|
|
462
|
+
|
|
463
|
+
${ansi.dim}Use ${ansi.cyan}vibecheck shield observe${ansi.dim} to switch back to logging-only.${ansi.reset}
|
|
464
|
+
`);
|
|
465
|
+
} else {
|
|
466
|
+
renderWarning("Observe mode ENABLED");
|
|
467
|
+
console.log(`
|
|
468
|
+
${ansi.dim}Shield will LOG but not block violations.${ansi.reset}
|
|
469
|
+
${ansi.dim}Use ${ansi.cyan}vibecheck shield enforce${ansi.dim} to enable blocking.${ansi.reset}
|
|
470
|
+
`);
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
renderError(result.error || `Failed to set mode to ${mode}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return result.success ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Handle lock subcommand (repo-lock mode)
|
|
482
|
+
*/
|
|
483
|
+
async function handleLock(ctx) {
|
|
484
|
+
const { EXIT } = getExitCodes();
|
|
485
|
+
const { ansi, renderWarning, renderError } = getCliOutput();
|
|
486
|
+
|
|
487
|
+
const agent = loadImplementation("agent");
|
|
488
|
+
if (!agent) {
|
|
489
|
+
return handleModuleNotAvailable("agent", ctx);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const result = await agent.runAgent({ action: "lock", projectRoot: ctx.projectRoot });
|
|
493
|
+
|
|
494
|
+
if (ctx.json) {
|
|
495
|
+
console.log(JSON.stringify({
|
|
496
|
+
success: result.success,
|
|
497
|
+
mode: "repo-lock",
|
|
498
|
+
rules: ENFORCEMENT_RULES.map(r => r.id),
|
|
499
|
+
message: result.message,
|
|
500
|
+
timestamp: new Date().toISOString(),
|
|
501
|
+
}, null, 2));
|
|
502
|
+
} else if (!ctx.quiet) {
|
|
503
|
+
if (result.success) {
|
|
504
|
+
console.log(`
|
|
505
|
+
${ansi.yellow}${ansi.bold}╔═══════════════════════════════════════════════════════════════════╗
|
|
506
|
+
║ ║
|
|
507
|
+
║ 🔒 REPO LOCK MODE ENABLED ║
|
|
508
|
+
║ ║
|
|
509
|
+
╚═══════════════════════════════════════════════════════════════════╝${ansi.reset}
|
|
510
|
+
|
|
511
|
+
${ansi.yellow}All hard rules are now enforced:${ansi.reset}
|
|
512
|
+
`);
|
|
513
|
+
for (const rule of ENFORCEMENT_RULES) {
|
|
514
|
+
if (rule.severity === "block") {
|
|
515
|
+
console.log(` ${ansi.red}▪${ansi.reset} ${rule.name} - ${rule.description}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
console.log(`
|
|
519
|
+
${ansi.dim}This is the strictest enforcement mode.${ansi.reset}
|
|
520
|
+
${ansi.dim}Run ${ansi.cyan}vibecheck shield unlock${ansi.dim} to release.${ansi.reset}
|
|
521
|
+
`);
|
|
522
|
+
} else {
|
|
523
|
+
renderError(result.error || "Failed to lock repo");
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return result.success ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Handle unlock subcommand
|
|
532
|
+
*/
|
|
533
|
+
async function handleUnlock(ctx) {
|
|
534
|
+
const { EXIT } = getExitCodes();
|
|
535
|
+
const { ansi, renderSuccess, renderError } = getCliOutput();
|
|
536
|
+
|
|
537
|
+
const agent = loadImplementation("agent");
|
|
538
|
+
if (!agent) {
|
|
539
|
+
return handleModuleNotAvailable("agent", ctx);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const result = await agent.runAgent({ action: "unlock", projectRoot: ctx.projectRoot });
|
|
543
|
+
|
|
544
|
+
if (ctx.json) {
|
|
545
|
+
console.log(JSON.stringify({
|
|
546
|
+
success: result.success,
|
|
547
|
+
mode: "observe",
|
|
548
|
+
message: result.message,
|
|
549
|
+
timestamp: new Date().toISOString(),
|
|
550
|
+
}, null, 2));
|
|
551
|
+
} else if (!ctx.quiet) {
|
|
552
|
+
if (result.success) {
|
|
553
|
+
renderSuccess("Repo lock released");
|
|
554
|
+
console.log(`
|
|
555
|
+
${ansi.dim}Firewall is now in observe mode.${ansi.reset}
|
|
556
|
+
${ansi.dim}Violations will be logged but not blocked.${ansi.reset}
|
|
557
|
+
`);
|
|
558
|
+
} else {
|
|
559
|
+
renderError(result.error || "Failed to unlock repo");
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return result.success ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Handle verify subcommand - delegates to runGuard with enhancements
|
|
568
|
+
*/
|
|
569
|
+
async function handleVerify(ctx) {
|
|
570
|
+
const { EXIT } = getExitCodes();
|
|
571
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, renderVerdict, renderFooter, Spinner, sym } = getCliOutput();
|
|
572
|
+
|
|
573
|
+
const guard = loadImplementation("guard");
|
|
574
|
+
if (!guard) {
|
|
575
|
+
return handleModuleNotAvailable("guard", ctx);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Build guard args
|
|
579
|
+
const guardArgs = [...ctx.args];
|
|
580
|
+
if (ctx.json && !guardArgs.includes("--json")) guardArgs.push("--json");
|
|
581
|
+
if (ctx.quiet && !guardArgs.includes("--quiet") && !guardArgs.includes("-q")) guardArgs.push("--quiet");
|
|
582
|
+
|
|
583
|
+
if (!ctx.json && !ctx.quiet) {
|
|
584
|
+
renderMinimalHeader("shield", "pro");
|
|
585
|
+
renderSectionHeader("Verification", sym.shield);
|
|
586
|
+
|
|
587
|
+
// Show what we're checking
|
|
588
|
+
const checkClaims = ctx.args.includes("--claims") || (!ctx.args.includes("--prompts") && !ctx.args.includes("--hallucinations"));
|
|
589
|
+
const checkPrompts = ctx.args.includes("--prompts") || (!ctx.args.includes("--claims") && !ctx.args.includes("--hallucinations"));
|
|
590
|
+
const checkHallucinations = ctx.args.includes("--hallucinations") || (!ctx.args.includes("--claims") && !ctx.args.includes("--prompts"));
|
|
591
|
+
|
|
592
|
+
console.log(`
|
|
593
|
+
${ansi.dim}Running verification checks:${ansi.reset}
|
|
594
|
+
${checkClaims ? ansi.green + "✓" : ansi.dim + "○"} ${ansi.reset}AI Claims against truthpack
|
|
595
|
+
${checkPrompts ? ansi.green + "✓" : ansi.dim + "○"} ${ansi.reset}Prompt injection detection
|
|
596
|
+
${checkHallucinations ? ansi.green + "✓" : ansi.dim + "○"} ${ansi.reset}Hallucination patterns
|
|
597
|
+
`);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Execute guard
|
|
601
|
+
const exitCode = await guard(guardArgs);
|
|
602
|
+
|
|
603
|
+
return exitCode;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Handle check subcommand - v2 enforcement with intent alignment
|
|
608
|
+
*/
|
|
609
|
+
async function handleCheck(ctx) {
|
|
610
|
+
const { EXIT } = getExitCodes();
|
|
611
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, renderSuccess, renderError, sym } = getCliOutput();
|
|
612
|
+
|
|
613
|
+
const createOrchestrator = loadImplementation("orchestrator");
|
|
614
|
+
const IntentStore = loadImplementation("intentStore");
|
|
615
|
+
|
|
616
|
+
if (!createOrchestrator || !IntentStore) {
|
|
617
|
+
if (ctx.json) {
|
|
618
|
+
console.log(JSON.stringify({ success: false, error: "v2 enforcement modules not available" }));
|
|
619
|
+
} else {
|
|
620
|
+
renderError("v2 enforcement modules not available");
|
|
621
|
+
}
|
|
622
|
+
return EXIT.INTERNAL_ERROR;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Check for intent
|
|
626
|
+
const intentStore = new IntentStore(ctx.projectRoot);
|
|
627
|
+
const hasIntent = intentStore.hasIntent();
|
|
628
|
+
const intent = intentStore.getCurrent({ allowMissing: true });
|
|
629
|
+
|
|
630
|
+
if (!ctx.json && !ctx.quiet) {
|
|
631
|
+
renderMinimalHeader("shield", "pro");
|
|
632
|
+
renderSectionHeader("Agent Firewall v2 Check", sym.shield);
|
|
633
|
+
|
|
634
|
+
// Show intent status
|
|
635
|
+
const isBlocking = intent?.summary?.includes("NO INTENT DECLARED");
|
|
636
|
+
|
|
637
|
+
console.log(`
|
|
638
|
+
${ansi.bold}Intent Status${ansi.reset}`);
|
|
639
|
+
|
|
640
|
+
if (!hasIntent || isBlocking) {
|
|
641
|
+
console.log(` ${ansi.yellow}⚠${ansi.reset} No intent declared - ${ansi.red}ALL CHANGES BLOCKED${ansi.reset}`);
|
|
642
|
+
console.log(`
|
|
643
|
+
${ansi.dim}Declare an intent before making AI changes:${ansi.reset}
|
|
644
|
+
${ansi.cyan}vibecheck intent set -s "Your intent description"${ansi.reset}
|
|
645
|
+
`);
|
|
646
|
+
} else {
|
|
647
|
+
console.log(` ${ansi.green}✓${ansi.reset} Intent active: ${intent.summary}`);
|
|
648
|
+
if (intent.constraints && intent.constraints.length > 0) {
|
|
649
|
+
console.log(` ${ansi.dim}Constraints: ${intent.constraints.length}${ansi.reset}`);
|
|
650
|
+
}
|
|
651
|
+
if (intent.allowed_changes && intent.allowed_changes.length > 0) {
|
|
652
|
+
console.log(` ${ansi.dim}Allowed changes: ${intent.allowed_changes.length}${ansi.reset}`);
|
|
653
|
+
}
|
|
654
|
+
console.log(` ${ansi.dim}Hash: ${intent.hash.slice(0, 16)}...${ansi.reset}`);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Get staged changes from git
|
|
659
|
+
let changes = [];
|
|
660
|
+
try {
|
|
661
|
+
const { execSync } = require("child_process");
|
|
662
|
+
const gitDiff = execSync("git diff --cached --name-only", {
|
|
663
|
+
cwd: ctx.projectRoot,
|
|
664
|
+
encoding: "utf-8",
|
|
665
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
666
|
+
}).trim();
|
|
667
|
+
|
|
668
|
+
if (gitDiff) {
|
|
669
|
+
changes = gitDiff.split("\n").filter(Boolean).map(file => ({
|
|
670
|
+
path: file,
|
|
671
|
+
type: "file_write",
|
|
672
|
+
}));
|
|
673
|
+
}
|
|
674
|
+
} catch {
|
|
675
|
+
// No git or no staged changes
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// If no staged changes, check for recent modified files
|
|
679
|
+
if (changes.length === 0) {
|
|
680
|
+
try {
|
|
681
|
+
const { execSync } = require("child_process");
|
|
682
|
+
const gitStatus = execSync("git diff --name-only HEAD~1", {
|
|
683
|
+
cwd: ctx.projectRoot,
|
|
684
|
+
encoding: "utf-8",
|
|
685
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
686
|
+
}).trim();
|
|
687
|
+
|
|
688
|
+
if (gitStatus) {
|
|
689
|
+
changes = gitStatus.split("\n").filter(Boolean).map(file => ({
|
|
690
|
+
path: file,
|
|
691
|
+
type: "file_write",
|
|
692
|
+
}));
|
|
693
|
+
}
|
|
694
|
+
} catch {
|
|
695
|
+
// No recent changes
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if (!ctx.json && !ctx.quiet) {
|
|
700
|
+
console.log(`
|
|
701
|
+
${ansi.bold}Changes to Check${ansi.reset}
|
|
702
|
+
${changes.length > 0 ? `${changes.length} file(s)` : `${ansi.dim}(no staged or recent changes)${ansi.reset}`}`);
|
|
703
|
+
|
|
704
|
+
for (const change of changes.slice(0, 5)) {
|
|
705
|
+
console.log(` ${ansi.dim}•${ansi.reset} ${change.path}`);
|
|
706
|
+
}
|
|
707
|
+
if (changes.length > 5) {
|
|
708
|
+
console.log(` ${ansi.dim}... and ${changes.length - 5} more${ansi.reset}`);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Run enforcement if we have changes
|
|
713
|
+
if (changes.length === 0) {
|
|
714
|
+
if (ctx.json) {
|
|
715
|
+
console.log(JSON.stringify({
|
|
716
|
+
success: true,
|
|
717
|
+
verdict: { decision: "PASS", message: "No changes to check" },
|
|
718
|
+
intent_hash: intent?.hash || null,
|
|
719
|
+
changes: 0,
|
|
720
|
+
}, null, 2));
|
|
721
|
+
} else if (!ctx.quiet) {
|
|
722
|
+
console.log(`
|
|
723
|
+
${ansi.green}✓${ansi.reset} No changes to enforce
|
|
724
|
+
`);
|
|
725
|
+
}
|
|
726
|
+
return EXIT.SUCCESS;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Create orchestrator and run enforcement
|
|
730
|
+
const orchestrator = createOrchestrator(ctx.projectRoot);
|
|
731
|
+
|
|
732
|
+
if (!ctx.json && !ctx.quiet) {
|
|
733
|
+
console.log(`
|
|
734
|
+
${ansi.bold}Running Enforcement${ansi.reset}
|
|
735
|
+
${ansi.dim}Checking intent alignment...${ansi.reset}`);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const result = await orchestrator.enforce({
|
|
739
|
+
changes,
|
|
740
|
+
agentId: "cli-check",
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
if (ctx.json) {
|
|
744
|
+
console.log(JSON.stringify({
|
|
745
|
+
success: !result.blocked,
|
|
746
|
+
verdict: result.verdict,
|
|
747
|
+
violations: result.violations,
|
|
748
|
+
proofs: result.proofs,
|
|
749
|
+
intent_hash: result.intent_hash,
|
|
750
|
+
changes: changes.length,
|
|
751
|
+
}, null, 2));
|
|
752
|
+
} else if (!ctx.quiet) {
|
|
753
|
+
const verdictColor = result.verdict?.decision === "PASS" ? ansi.green : ansi.red;
|
|
754
|
+
|
|
755
|
+
console.log(`
|
|
756
|
+
${ansi.bold}Verdict${ansi.reset}
|
|
757
|
+
${verdictColor}${result.verdict?.decision || "UNKNOWN"}${ansi.reset}`);
|
|
758
|
+
|
|
759
|
+
if (result.violations && result.violations.length > 0) {
|
|
760
|
+
console.log(`
|
|
761
|
+
${ansi.bold}Violations (${result.violations.length})${ansi.reset}`);
|
|
762
|
+
for (const v of result.violations.slice(0, 5)) {
|
|
763
|
+
console.log(` ${ansi.red}✗${ansi.reset} [${v.code}] ${v.message}`);
|
|
764
|
+
console.log(` ${ansi.dim}Resource: ${v.resource}${ansi.reset}`);
|
|
765
|
+
}
|
|
766
|
+
if (result.violations.length > 5) {
|
|
767
|
+
console.log(` ${ansi.dim}... and ${result.violations.length - 5} more${ansi.reset}`);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (result.verdict?.decision === "PASS") {
|
|
772
|
+
console.log(`
|
|
773
|
+
${ansi.green}${ansi.bold}╔═══════════════════════════════════════════════════════════════════╗
|
|
774
|
+
║ ║
|
|
775
|
+
║ ✓ ENFORCEMENT PASSED ║
|
|
776
|
+
║ ║
|
|
777
|
+
╚═══════════════════════════════════════════════════════════════════╝${ansi.reset}
|
|
778
|
+
`);
|
|
779
|
+
} else {
|
|
780
|
+
console.log(`
|
|
781
|
+
${ansi.red}${ansi.bold}╔═══════════════════════════════════════════════════════════════════╗
|
|
782
|
+
║ ║
|
|
783
|
+
║ ✗ ENFORCEMENT BLOCKED ║
|
|
784
|
+
║ ║
|
|
785
|
+
╚═══════════════════════════════════════════════════════════════════╝${ansi.reset}
|
|
786
|
+
|
|
787
|
+
${ansi.dim}To resolve:${ansi.reset}
|
|
788
|
+
1. Update your intent to allow these changes
|
|
789
|
+
2. Or modify changes to align with declared intent
|
|
790
|
+
|
|
791
|
+
${ansi.dim}Current intent: ${ansi.cyan}vibecheck intent show${ansi.reset}
|
|
792
|
+
${ansi.dim}Update intent: ${ansi.cyan}vibecheck intent set -s "..."${ansi.reset}
|
|
793
|
+
`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
return result.blocked ? EXIT.BLOCKING : EXIT.SUCCESS;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Handle install subcommand
|
|
802
|
+
*/
|
|
803
|
+
async function handleInstall(ctx) {
|
|
804
|
+
const { EXIT } = getExitCodes();
|
|
805
|
+
const { ansi, renderSuccess, renderError, renderWarning, sym } = getCliOutput();
|
|
806
|
+
|
|
807
|
+
const agent = loadImplementation("agent");
|
|
808
|
+
if (!agent) {
|
|
809
|
+
return handleModuleNotAvailable("agent", ctx);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (!ctx.json && !ctx.quiet) {
|
|
813
|
+
console.log(`
|
|
814
|
+
${ansi.dim}Installing Agent Firewall hooks...${ansi.reset}
|
|
815
|
+
`);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
const result = await agent.runAgent({ action: "install", projectRoot: ctx.projectRoot });
|
|
819
|
+
|
|
820
|
+
if (ctx.json) {
|
|
821
|
+
console.log(JSON.stringify({
|
|
822
|
+
success: result.success,
|
|
823
|
+
hooks: {
|
|
824
|
+
cursor: true,
|
|
825
|
+
vscode: true,
|
|
826
|
+
windsurf: true,
|
|
827
|
+
},
|
|
828
|
+
message: result.message,
|
|
829
|
+
timestamp: new Date().toISOString(),
|
|
830
|
+
}, null, 2));
|
|
831
|
+
} else if (!ctx.quiet) {
|
|
832
|
+
if (result.success) {
|
|
833
|
+
console.log(`
|
|
834
|
+
${ansi.green}${ansi.bold}╔═══════════════════════════════════════════════════════════════════╗
|
|
835
|
+
║ ║
|
|
836
|
+
║ ${sym.success} AGENT FIREWALL HOOKS INSTALLED ║
|
|
837
|
+
║ ║
|
|
838
|
+
╚═══════════════════════════════════════════════════════════════════╝${ansi.reset}
|
|
839
|
+
|
|
840
|
+
${ansi.dim}IDE Integration:${ansi.reset}
|
|
841
|
+
${ansi.green}✓${ansi.reset} Cursor
|
|
842
|
+
${ansi.green}✓${ansi.reset} VS Code
|
|
843
|
+
${ansi.green}✓${ansi.reset} Windsurf
|
|
844
|
+
|
|
845
|
+
${ansi.dim}The firewall will now intercept AI code changes.${ansi.reset}
|
|
846
|
+
|
|
847
|
+
${ansi.bold}Next Steps:${ansi.reset}
|
|
848
|
+
${ansi.cyan}vibecheck shield enforce${ansi.reset} Enable blocking mode
|
|
849
|
+
${ansi.cyan}vibecheck shield status${ansi.reset} Check configuration
|
|
850
|
+
${ansi.cyan}vibecheck audit${ansi.reset} Generate fresh truthpack
|
|
851
|
+
`);
|
|
852
|
+
} else {
|
|
853
|
+
renderError(result.error || "Failed to install hooks");
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
return result.success ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Handle stats subcommand
|
|
862
|
+
*/
|
|
863
|
+
async function handleStats(ctx) {
|
|
864
|
+
const { EXIT } = getExitCodes();
|
|
865
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
866
|
+
|
|
867
|
+
const firewall = loadImplementation("firewall");
|
|
868
|
+
if (!firewall) {
|
|
869
|
+
return handleModuleNotAvailable("firewall", ctx);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const stats = await firewall.runFirewall({ stats: true, projectRoot: ctx.projectRoot });
|
|
873
|
+
|
|
874
|
+
const result = {
|
|
875
|
+
total: stats.total || 0,
|
|
876
|
+
byVerdict: stats.byVerdict || {},
|
|
877
|
+
byAgent: stats.byAgent || {},
|
|
878
|
+
byDate: stats.byDate || {},
|
|
879
|
+
recent: stats.recent || [],
|
|
880
|
+
period: "all-time",
|
|
881
|
+
timestamp: new Date().toISOString(),
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
if (ctx.json) {
|
|
885
|
+
console.log(JSON.stringify(result, null, 2));
|
|
886
|
+
} else if (!ctx.quiet) {
|
|
887
|
+
renderMinimalHeader("shield", "pro");
|
|
888
|
+
renderSectionHeader("Firewall Statistics", sym.chart);
|
|
889
|
+
|
|
890
|
+
if (stats.error || result.total === 0) {
|
|
891
|
+
console.log(`
|
|
892
|
+
${ansi.dim}No change packets recorded yet.${ansi.reset}
|
|
893
|
+
|
|
894
|
+
${ansi.dim}Change packets are created when:${ansi.reset}
|
|
895
|
+
${ansi.dim}• AI makes code changes through IDE hooks${ansi.reset}
|
|
896
|
+
${ansi.dim}• Files are modified with hooks installed${ansi.reset}
|
|
897
|
+
|
|
898
|
+
${ansi.dim}Run ${ansi.cyan}vibecheck shield install${ansi.dim} to set up interception.${ansi.reset}
|
|
899
|
+
`);
|
|
900
|
+
} else {
|
|
901
|
+
console.log(`
|
|
902
|
+
${ansi.bold}Overview${ansi.reset}
|
|
903
|
+
${ansi.dim}Total Packets:${ansi.reset} ${ansi.bold}${result.total}${ansi.reset}
|
|
904
|
+
`);
|
|
905
|
+
|
|
906
|
+
// Verdict breakdown
|
|
907
|
+
if (Object.keys(result.byVerdict).length > 0) {
|
|
908
|
+
console.log(` ${ansi.bold}By Verdict${ansi.reset}`);
|
|
909
|
+
for (const [verdict, count] of Object.entries(result.byVerdict)) {
|
|
910
|
+
const pct = ((count / result.total) * 100).toFixed(1);
|
|
911
|
+
const bar = renderProgressBar(count / result.total, 20, ansi);
|
|
912
|
+
const color = verdict === "ALLOW" ? ansi.green : verdict === "BLOCK" ? ansi.red : ansi.yellow;
|
|
913
|
+
console.log(` ${color}${verdict.padEnd(8)}${ansi.reset} ${bar} ${count} (${pct}%)`);
|
|
914
|
+
}
|
|
915
|
+
console.log();
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// Agent breakdown
|
|
919
|
+
if (Object.keys(result.byAgent).length > 0) {
|
|
920
|
+
console.log(` ${ansi.bold}By Agent${ansi.reset}`);
|
|
921
|
+
for (const [agent, count] of Object.entries(result.byAgent)) {
|
|
922
|
+
console.log(` ${ansi.dim}${agent.padEnd(20)}${ansi.reset} ${count}`);
|
|
923
|
+
}
|
|
924
|
+
console.log();
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// Recent packets
|
|
928
|
+
if (result.recent.length > 0) {
|
|
929
|
+
console.log(` ${ansi.bold}Recent Activity${ansi.reset}`);
|
|
930
|
+
for (const packet of result.recent.slice(0, 5)) {
|
|
931
|
+
const verdictColor = packet.verdict === "ALLOW" ? ansi.green :
|
|
932
|
+
packet.verdict === "BLOCK" ? ansi.red : ansi.yellow;
|
|
933
|
+
const time = new Date(packet.timestamp).toLocaleTimeString();
|
|
934
|
+
console.log(` ${ansi.dim}${time}${ansi.reset} ${verdictColor}${(packet.verdict || "?").padEnd(6)}${ansi.reset} ${packet.files || 0} files`);
|
|
935
|
+
}
|
|
936
|
+
console.log();
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return EXIT.SUCCESS;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Handle audit subcommand - review recent change packets
|
|
946
|
+
*/
|
|
947
|
+
async function handleAudit(ctx) {
|
|
948
|
+
const { EXIT } = getExitCodes();
|
|
949
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, renderWarning, sym } = getCliOutput();
|
|
950
|
+
|
|
951
|
+
if (!ctx.json && !ctx.quiet) {
|
|
952
|
+
renderMinimalHeader("shield", "pro");
|
|
953
|
+
renderSectionHeader("Change Packet Audit", sym.search);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// Load recent packets
|
|
957
|
+
const packetsDir = path.join(ctx.projectRoot, ".vibecheck", "packets");
|
|
958
|
+
|
|
959
|
+
if (!fs.existsSync(packetsDir)) {
|
|
960
|
+
if (ctx.json) {
|
|
961
|
+
console.log(JSON.stringify({ packets: [], count: 0, message: "No packets directory found" }));
|
|
962
|
+
} else if (!ctx.quiet) {
|
|
963
|
+
renderWarning("No change packets found");
|
|
964
|
+
console.log(`
|
|
965
|
+
${ansi.dim}Install hooks and make changes to generate packets:${ansi.reset}
|
|
966
|
+
${ansi.cyan}vibecheck shield install${ansi.reset}
|
|
967
|
+
`);
|
|
968
|
+
}
|
|
969
|
+
return EXIT.SUCCESS;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Collect packets from date directories
|
|
973
|
+
const packets = [];
|
|
974
|
+
try {
|
|
975
|
+
const dateDirs = fs.readdirSync(packetsDir).filter(d => /^\d{4}-\d{2}-\d{2}$/.test(d));
|
|
976
|
+
for (const dateDir of dateDirs.slice(-7)) { // Last 7 days
|
|
977
|
+
const dayPath = path.join(packetsDir, dateDir);
|
|
978
|
+
const files = fs.readdirSync(dayPath).filter(f => f.endsWith(".json"));
|
|
979
|
+
for (const file of files.slice(-10)) { // Last 10 per day
|
|
980
|
+
try {
|
|
981
|
+
const packet = JSON.parse(fs.readFileSync(path.join(dayPath, file), "utf-8"));
|
|
982
|
+
packets.push({ ...packet, date: dateDir, file });
|
|
983
|
+
} catch {
|
|
984
|
+
// Skip invalid packets
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
} catch {
|
|
989
|
+
// Handle read errors gracefully
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
if (ctx.json) {
|
|
993
|
+
console.log(JSON.stringify({ packets, count: packets.length }, null, 2));
|
|
994
|
+
} else if (!ctx.quiet) {
|
|
995
|
+
if (packets.length === 0) {
|
|
996
|
+
console.log(`
|
|
997
|
+
${ansi.dim}No recent packets found.${ansi.reset}
|
|
998
|
+
`);
|
|
999
|
+
} else {
|
|
1000
|
+
console.log(`
|
|
1001
|
+
${ansi.dim}Found ${packets.length} recent packets:${ansi.reset}
|
|
1002
|
+
`);
|
|
1003
|
+
for (const packet of packets.slice(-10)) {
|
|
1004
|
+
const verdictColor = packet.verdict?.decision === "ALLOW" ? ansi.green :
|
|
1005
|
+
packet.verdict?.decision === "BLOCK" ? ansi.red : ansi.yellow;
|
|
1006
|
+
console.log(` ${ansi.dim}${packet.date}${ansi.reset} ${packet.id?.slice(0, 8) || "?"} ${verdictColor}${(packet.verdict?.decision || "?").padEnd(6)}${ansi.reset} ${packet.files?.length || 0} files`);
|
|
1007
|
+
}
|
|
1008
|
+
console.log();
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
return EXIT.SUCCESS;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Handle policy subcommand
|
|
1017
|
+
*/
|
|
1018
|
+
async function handlePolicy(ctx) {
|
|
1019
|
+
const { EXIT } = getExitCodes();
|
|
1020
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, sym } = getCliOutput();
|
|
1021
|
+
|
|
1022
|
+
const policyPath = path.join(ctx.projectRoot, ".vibecheck", "policy.json");
|
|
1023
|
+
|
|
1024
|
+
if (!ctx.json && !ctx.quiet) {
|
|
1025
|
+
renderMinimalHeader("shield", "pro");
|
|
1026
|
+
renderSectionHeader("Policy Configuration", sym.settings);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
let policy = {
|
|
1030
|
+
mode: "observe",
|
|
1031
|
+
profile: "balanced",
|
|
1032
|
+
rules: {},
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
if (fs.existsSync(policyPath)) {
|
|
1036
|
+
try {
|
|
1037
|
+
policy = JSON.parse(fs.readFileSync(policyPath, "utf-8"));
|
|
1038
|
+
} catch {
|
|
1039
|
+
// Use defaults
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (ctx.json) {
|
|
1044
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
1045
|
+
} else if (!ctx.quiet) {
|
|
1046
|
+
console.log(`
|
|
1047
|
+
${ansi.bold}Current Policy${ansi.reset}
|
|
1048
|
+
${ansi.dim}Mode:${ansi.reset} ${policy.mode}
|
|
1049
|
+
${ansi.dim}Profile:${ansi.reset} ${policy.profile}
|
|
1050
|
+
${ansi.dim}Path:${ansi.reset} ${policyPath}
|
|
1051
|
+
|
|
1052
|
+
${ansi.bold}Rules${ansi.reset}`);
|
|
1053
|
+
|
|
1054
|
+
for (const rule of ENFORCEMENT_RULES) {
|
|
1055
|
+
const ruleConfig = policy.rules?.[rule.id] || {};
|
|
1056
|
+
const enabled = ruleConfig.enabled !== false;
|
|
1057
|
+
const severity = ruleConfig.severity || rule.severity;
|
|
1058
|
+
const severityColor = severity === "block" ? ansi.red : ansi.yellow;
|
|
1059
|
+
|
|
1060
|
+
console.log(` ${enabled ? ansi.green + "✓" : ansi.dim + "○"} ${ansi.reset}${rule.id.padEnd(20)} ${severityColor}${severity.padEnd(5)}${ansi.reset} ${ansi.dim}${rule.description}${ansi.reset}`);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
console.log(`
|
|
1064
|
+
${ansi.dim}Edit ${policyPath} to customize rules.${ansi.reset}
|
|
1065
|
+
`);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
return EXIT.SUCCESS;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1072
|
+
// ERROR HANDLING
|
|
1073
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1074
|
+
|
|
1075
|
+
function handleUnknownSubcommand(subcommand, ctx) {
|
|
1076
|
+
const { EXIT } = getExitCodes();
|
|
1077
|
+
const { ansi } = getCliOutput();
|
|
1078
|
+
|
|
1079
|
+
if (ctx.json) {
|
|
1080
|
+
console.log(JSON.stringify({
|
|
1081
|
+
success: false,
|
|
1082
|
+
error: `Unknown subcommand: ${subcommand}`,
|
|
1083
|
+
available: Object.keys(SUBCOMMANDS),
|
|
1084
|
+
}));
|
|
1085
|
+
} else {
|
|
1086
|
+
console.log(`
|
|
1087
|
+
${ansi.red}Error: Unknown subcommand '${subcommand}'${ansi.reset}
|
|
1088
|
+
|
|
1089
|
+
${ansi.dim}Available subcommands:${ansi.reset}
|
|
1090
|
+
${Object.keys(SUBCOMMANDS).map(s => ` ${ansi.cyan}${s}${ansi.reset}`).join("\n")}
|
|
1091
|
+
|
|
1092
|
+
Run ${ansi.cyan}vibecheck shield --help${ansi.reset} for usage.
|
|
1093
|
+
`);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
return EXIT.USER_ERROR;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
function handleModuleNotAvailable(module, ctx) {
|
|
1100
|
+
const { EXIT } = getExitCodes();
|
|
1101
|
+
const { ansi, renderError } = getCliOutput();
|
|
1102
|
+
|
|
1103
|
+
if (ctx.json) {
|
|
1104
|
+
console.log(JSON.stringify({
|
|
1105
|
+
success: false,
|
|
1106
|
+
error: `${module} module not available`,
|
|
1107
|
+
hint: "Try reinstalling vibecheck or check your installation",
|
|
1108
|
+
}));
|
|
1109
|
+
} else {
|
|
1110
|
+
renderError(`${module} module not available`);
|
|
1111
|
+
console.log(`
|
|
1112
|
+
${ansi.dim}This may indicate an incomplete installation.${ansi.reset}
|
|
1113
|
+
${ansi.dim}Try: ${ansi.cyan}npm install -g @vibecheck/cli${ansi.reset}
|
|
1114
|
+
`);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
return EXIT.INTERNAL_ERROR;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
function handleError(error, ctx) {
|
|
1121
|
+
const { EXIT } = getExitCodes();
|
|
1122
|
+
const { ansi, renderError } = getCliOutput();
|
|
1123
|
+
|
|
1124
|
+
if (ctx.json) {
|
|
1125
|
+
console.log(JSON.stringify({
|
|
1126
|
+
success: false,
|
|
1127
|
+
error: error.message,
|
|
1128
|
+
stack: ctx.verbose ? error.stack : undefined,
|
|
1129
|
+
}));
|
|
1130
|
+
} else {
|
|
1131
|
+
renderError(`Shield error: ${error.message}`);
|
|
1132
|
+
if (ctx.verbose) {
|
|
1133
|
+
console.log(`\n${ansi.dim}${error.stack}${ansi.reset}\n`);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
return EXIT.INTERNAL_ERROR;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1141
|
+
// UTILITY FUNCTIONS
|
|
1142
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1143
|
+
|
|
1144
|
+
function calculateHealth(status, agentStatus) {
|
|
1145
|
+
let score = 100;
|
|
1146
|
+
|
|
1147
|
+
if (!agentStatus.installed) score -= 30;
|
|
1148
|
+
if (!status.truthpackFresh) score -= 20;
|
|
1149
|
+
if (status.mode === "observe") score -= 10;
|
|
1150
|
+
if (status.error) score -= 40;
|
|
1151
|
+
|
|
1152
|
+
if (score >= 80) return { score, level: "excellent", color: "green" };
|
|
1153
|
+
if (score >= 60) return { score, level: "good", color: "green" };
|
|
1154
|
+
if (score >= 40) return { score, level: "fair", color: "yellow" };
|
|
1155
|
+
return { score, level: "needs attention", color: "red" };
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
function renderHealthBadge(health, ansi) {
|
|
1159
|
+
const color = health.color === "green" ? ansi.green :
|
|
1160
|
+
health.color === "yellow" ? ansi.yellow : ansi.red;
|
|
1161
|
+
return `${color}${health.level.toUpperCase()}${ansi.reset} ${ansi.dim}(${health.score}/100)${ansi.reset}`;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
function renderProgressBar(ratio, width, ansi) {
|
|
1165
|
+
const filled = Math.round(ratio * width);
|
|
1166
|
+
const empty = width - filled;
|
|
1167
|
+
return `${ansi.green}${"█".repeat(filled)}${ansi.dim}${"░".repeat(empty)}${ansi.reset}`;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1171
|
+
// SEAL (BADGE) COMMAND
|
|
1172
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* Generate seal (badge) and attestation
|
|
1176
|
+
* @param {string[]} args - Command arguments
|
|
1177
|
+
* @param {Object} context - Execution context
|
|
1178
|
+
*/
|
|
1179
|
+
async function runSeal(args = [], context = {}) {
|
|
1180
|
+
const { EXIT } = getExitCodes();
|
|
1181
|
+
const { ansi, renderMinimalHeader, renderSectionHeader, renderSuccess, sym } = getCliOutput();
|
|
1182
|
+
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = getGlobalFlags();
|
|
1183
|
+
|
|
1184
|
+
const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
|
|
1185
|
+
const quiet = shouldSuppressOutput(globalFlags);
|
|
1186
|
+
const json = isJsonMode(globalFlags) || args.includes("--json");
|
|
1187
|
+
const projectRoot = context.repoRoot || globalFlags.path || process.cwd();
|
|
1188
|
+
|
|
1189
|
+
// Check for --badge flag compatibility (delegate to ship)
|
|
1190
|
+
if (args.includes("--badge") || !args.some(a => a.startsWith("--"))) {
|
|
1191
|
+
try {
|
|
1192
|
+
const { runShip } = require("./runShip");
|
|
1193
|
+
return runShip(["--badge", ...args.filter(a => a !== "--badge")], context);
|
|
1194
|
+
} catch (e) {
|
|
1195
|
+
// Fall through to local implementation
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// Generate seal locally
|
|
1200
|
+
const format = getArgValue(args, "--format") || "svg";
|
|
1201
|
+
const output = getArgValue(args, "--output") || getArgValue(args, "-o");
|
|
1202
|
+
const includeAttest = args.includes("--attest");
|
|
1203
|
+
|
|
1204
|
+
if (!json && !quiet) {
|
|
1205
|
+
renderMinimalHeader("seal", "pro");
|
|
1206
|
+
renderSectionHeader("Badge Generation", sym.badge);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// Load last ship result
|
|
1210
|
+
const shipResultPath = path.join(projectRoot, ".vibecheck", "ship", "last_ship.json");
|
|
1211
|
+
let shipResult = { verdict: "UNKNOWN" };
|
|
1212
|
+
|
|
1213
|
+
if (fs.existsSync(shipResultPath)) {
|
|
1214
|
+
try {
|
|
1215
|
+
shipResult = JSON.parse(fs.readFileSync(shipResultPath, "utf-8"));
|
|
1216
|
+
} catch {
|
|
1217
|
+
// Use defaults
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
const seal = {
|
|
1222
|
+
verdict: shipResult.verdict || "UNKNOWN",
|
|
1223
|
+
timestamp: new Date().toISOString(),
|
|
1224
|
+
version: SHIELD_VERSION,
|
|
1225
|
+
format,
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
if (includeAttest) {
|
|
1229
|
+
seal.attestation = {
|
|
1230
|
+
hash: require("crypto").createHash("sha256").update(JSON.stringify(seal)).digest("hex").slice(0, 16),
|
|
1231
|
+
algorithm: "sha256",
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
if (json) {
|
|
1236
|
+
console.log(JSON.stringify(seal, null, 2));
|
|
1237
|
+
} else if (!quiet) {
|
|
1238
|
+
renderSuccess(`Seal generated: ${seal.verdict}`);
|
|
1239
|
+
console.log(`
|
|
1240
|
+
${ansi.dim}Format:${ansi.reset} ${format}
|
|
1241
|
+
${ansi.dim}Verdict:${ansi.reset} ${seal.verdict}
|
|
1242
|
+
${ansi.dim}Time:${ansi.reset} ${seal.timestamp}
|
|
1243
|
+
`);
|
|
1244
|
+
|
|
1245
|
+
if (includeAttest) {
|
|
1246
|
+
console.log(` ${ansi.dim}Attestation:${ansi.reset} ${seal.attestation.hash}`);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
return EXIT.SUCCESS;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function getArgValue(args, flag) {
|
|
1254
|
+
const index = args.indexOf(flag);
|
|
1255
|
+
if (index !== -1 && args[index + 1] && !args[index + 1].startsWith("--")) {
|
|
1256
|
+
return args[index + 1];
|
|
1257
|
+
}
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1262
|
+
// EXPORTS
|
|
1263
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
1264
|
+
|
|
1265
|
+
module.exports = {
|
|
1266
|
+
runShield,
|
|
1267
|
+
runSeal,
|
|
1268
|
+
// Export constants for testing
|
|
1269
|
+
SHIELD_VERSION,
|
|
1270
|
+
SUBCOMMANDS,
|
|
1271
|
+
ENFORCEMENT_RULES,
|
|
1272
|
+
// Export individual handlers for direct access
|
|
1273
|
+
handleStatus,
|
|
1274
|
+
handleSetMode,
|
|
1275
|
+
handleLock,
|
|
1276
|
+
handleUnlock,
|
|
1277
|
+
handleVerify,
|
|
1278
|
+
handleInstall,
|
|
1279
|
+
handleStats,
|
|
1280
|
+
handleAudit,
|
|
1281
|
+
handlePolicy,
|
|
1282
|
+
};
|