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.
Files changed (456) hide show
  1. package/bin/.generated +25 -0
  2. package/bin/_deprecations.js +463 -0
  3. package/bin/_router.js +46 -0
  4. package/bin/cli-hygiene.js +241 -0
  5. package/bin/dev/run-v2-torture.js +30 -0
  6. package/bin/registry.js +656 -0
  7. package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
  8. package/bin/runners/ENHANCEMENT_GUIDE.md +121 -0
  9. package/bin/runners/REPORT_AUDIT.md +64 -0
  10. package/bin/runners/cli-utils.js +1070 -0
  11. package/bin/runners/context/ai-task-decomposer.js +337 -0
  12. package/bin/runners/context/analyzer.js +513 -0
  13. package/bin/runners/context/api-contracts.js +427 -0
  14. package/bin/runners/context/context-diff.js +342 -0
  15. package/bin/runners/context/context-pruner.js +291 -0
  16. package/bin/runners/context/dependency-graph.js +414 -0
  17. package/bin/runners/context/generators/claude.js +107 -0
  18. package/bin/runners/context/generators/codex.js +108 -0
  19. package/bin/runners/context/generators/copilot.js +119 -0
  20. package/bin/runners/context/generators/cursor-enhanced.js +2525 -0
  21. package/bin/runners/context/generators/cursor.js +514 -0
  22. package/bin/runners/context/generators/mcp.js +169 -0
  23. package/bin/runners/context/generators/windsurf.js +180 -0
  24. package/bin/runners/context/git-context.js +304 -0
  25. package/bin/runners/context/index.js +1110 -0
  26. package/bin/runners/context/insights.js +173 -0
  27. package/bin/runners/context/mcp-server/generate-rules.js +337 -0
  28. package/bin/runners/context/mcp-server/index.js +1176 -0
  29. package/bin/runners/context/mcp-server/package.json +24 -0
  30. package/bin/runners/context/memory.js +200 -0
  31. package/bin/runners/context/monorepo.js +215 -0
  32. package/bin/runners/context/multi-repo-federation.js +404 -0
  33. package/bin/runners/context/patterns.js +253 -0
  34. package/bin/runners/context/proof-context.js +1264 -0
  35. package/bin/runners/context/security-scanner.js +541 -0
  36. package/bin/runners/context/semantic-search.js +350 -0
  37. package/bin/runners/context/shared.js +264 -0
  38. package/bin/runners/context/team-conventions.js +336 -0
  39. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -0
  40. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
  41. package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
  42. package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
  43. package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
  44. package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
  45. package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
  46. package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
  47. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  48. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  49. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  50. package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
  51. package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
  52. package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
  53. package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
  54. package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
  55. package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
  56. package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
  57. package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
  58. package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
  59. package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
  60. package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
  61. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
  62. package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
  63. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
  64. package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
  65. package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
  66. package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
  67. package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
  68. package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
  69. package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
  70. package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
  71. package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
  72. package/bin/runners/lib/agent-firewall/index.js +200 -0
  73. package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
  74. package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
  75. package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
  76. package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
  77. package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
  78. package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
  79. package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
  80. package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
  81. package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
  82. package/bin/runners/lib/agent-firewall/interceptor/base.js +308 -0
  83. package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
  84. package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
  85. package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
  86. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  87. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  88. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  89. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  90. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  91. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  92. package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
  93. package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
  94. package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
  95. package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
  96. package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
  97. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +79 -0
  98. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +227 -0
  99. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +191 -0
  100. package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
  101. package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
  102. package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
  103. package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
  104. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  105. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  106. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  107. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  108. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  109. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  110. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  111. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  112. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  113. package/bin/runners/lib/agent-firewall/risk/thresholds.js +322 -0
  114. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  115. package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
  116. package/bin/runners/lib/agent-firewall/session/index.js +26 -0
  117. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  118. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  119. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  120. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  121. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  122. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  123. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  124. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  125. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  126. package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
  127. package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
  128. package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
  129. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
  130. package/bin/runners/lib/ai-bridge.js +416 -0
  131. package/bin/runners/lib/analysis-core.js +309 -0
  132. package/bin/runners/lib/analyzers.js +2500 -0
  133. package/bin/runners/lib/api-client.js +269 -0
  134. package/bin/runners/lib/approve-output.js +235 -0
  135. package/bin/runners/lib/artifact-envelope.js +540 -0
  136. package/bin/runners/lib/assets/vibecheck-logo.png +0 -0
  137. package/bin/runners/lib/audit-bridge.js +391 -0
  138. package/bin/runners/lib/auth-shared.js +977 -0
  139. package/bin/runners/lib/auth-truth.js +193 -0
  140. package/bin/runners/lib/auth.js +215 -0
  141. package/bin/runners/lib/authority-badge.js +425 -0
  142. package/bin/runners/lib/backup.js +62 -0
  143. package/bin/runners/lib/billing.js +107 -0
  144. package/bin/runners/lib/checkpoint.js +941 -0
  145. package/bin/runners/lib/claims.js +118 -0
  146. package/bin/runners/lib/classify-output.js +204 -0
  147. package/bin/runners/lib/cleanup/engine.js +571 -0
  148. package/bin/runners/lib/cleanup/index.js +53 -0
  149. package/bin/runners/lib/cleanup/output.js +375 -0
  150. package/bin/runners/lib/cleanup/rules.js +1060 -0
  151. package/bin/runners/lib/cli-output.js +400 -0
  152. package/bin/runners/lib/cli-ui.js +540 -0
  153. package/bin/runners/lib/compliance-bridge-new.js +0 -0
  154. package/bin/runners/lib/compliance-bridge.js +165 -0
  155. package/bin/runners/lib/contracts/auth-contract.js +202 -0
  156. package/bin/runners/lib/contracts/env-contract.js +181 -0
  157. package/bin/runners/lib/contracts/external-contract.js +206 -0
  158. package/bin/runners/lib/contracts/guard.js +168 -0
  159. package/bin/runners/lib/contracts/index.js +89 -0
  160. package/bin/runners/lib/contracts/plan-validator.js +311 -0
  161. package/bin/runners/lib/contracts/route-contract.js +199 -0
  162. package/bin/runners/lib/contracts.js +804 -0
  163. package/bin/runners/lib/default-config.js +127 -0
  164. package/bin/runners/lib/detect.js +89 -0
  165. package/bin/runners/lib/detectors-v2.js +622 -0
  166. package/bin/runners/lib/doctor/autofix.js +254 -0
  167. package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
  168. package/bin/runners/lib/doctor/failure-signatures.js +526 -0
  169. package/bin/runners/lib/doctor/fix-script.js +336 -0
  170. package/bin/runners/lib/doctor/index.js +37 -0
  171. package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
  172. package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
  173. package/bin/runners/lib/doctor/modules/index.js +105 -0
  174. package/bin/runners/lib/doctor/modules/network.js +250 -0
  175. package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
  176. package/bin/runners/lib/doctor/modules/project.js +312 -0
  177. package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
  178. package/bin/runners/lib/doctor/modules/runtime.js +224 -0
  179. package/bin/runners/lib/doctor/modules/security.js +350 -0
  180. package/bin/runners/lib/doctor/modules/system.js +213 -0
  181. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
  182. package/bin/runners/lib/doctor/reporter.js +262 -0
  183. package/bin/runners/lib/doctor/safe-repair.js +384 -0
  184. package/bin/runners/lib/doctor/service.js +262 -0
  185. package/bin/runners/lib/doctor/types.js +113 -0
  186. package/bin/runners/lib/doctor/ui.js +263 -0
  187. package/bin/runners/lib/doctor-enhanced.js +233 -0
  188. package/bin/runners/lib/doctor-output.js +226 -0
  189. package/bin/runners/lib/doctor-v2.js +608 -0
  190. package/bin/runners/lib/drift.js +425 -0
  191. package/bin/runners/lib/enforcement.js +72 -0
  192. package/bin/runners/lib/engine/ast-cache.js +210 -0
  193. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  194. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  195. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  196. package/bin/runners/lib/engine/env-extractor.js +207 -0
  197. package/bin/runners/lib/engine/express-extractor.js +208 -0
  198. package/bin/runners/lib/engine/extractors.js +849 -0
  199. package/bin/runners/lib/engine/index.js +207 -0
  200. package/bin/runners/lib/engine/repo-index.js +514 -0
  201. package/bin/runners/lib/engine/types.js +124 -0
  202. package/bin/runners/lib/engines/accessibility-engine.js +190 -0
  203. package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
  204. package/bin/runners/lib/engines/ast-cache.js +99 -0
  205. package/bin/runners/lib/engines/attack-detector.js +1192 -0
  206. package/bin/runners/lib/engines/code-quality-engine.js +255 -0
  207. package/bin/runners/lib/engines/console-logs-engine.js +115 -0
  208. package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
  209. package/bin/runners/lib/engines/dead-code-engine.js +198 -0
  210. package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
  211. package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
  212. package/bin/runners/lib/engines/file-filter.js +131 -0
  213. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
  214. package/bin/runners/lib/engines/mock-data-engine.js +272 -0
  215. package/bin/runners/lib/engines/parallel-processor.js +71 -0
  216. package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
  217. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
  218. package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
  219. package/bin/runners/lib/engines/type-aware-engine.js +152 -0
  220. package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
  221. package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
  222. package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
  223. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  224. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  225. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  226. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  227. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  228. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  229. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  230. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
  231. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  232. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  233. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  234. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  235. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  236. package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
  237. package/bin/runners/lib/enterprise-detect.js +603 -0
  238. package/bin/runners/lib/enterprise-init.js +942 -0
  239. package/bin/runners/lib/entitlements-v2.js +265 -0
  240. package/bin/runners/lib/entitlements.generated.js +0 -0
  241. package/bin/runners/lib/entitlements.js +340 -0
  242. package/bin/runners/lib/env-resolver.js +417 -0
  243. package/bin/runners/lib/env-template.js +66 -0
  244. package/bin/runners/lib/env.js +189 -0
  245. package/bin/runners/lib/error-handler.js +368 -0
  246. package/bin/runners/lib/error-messages.js +289 -0
  247. package/bin/runners/lib/evidence-pack.js +684 -0
  248. package/bin/runners/lib/exit-codes.js +275 -0
  249. package/bin/runners/lib/extractors/client-calls.js +990 -0
  250. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -0
  251. package/bin/runners/lib/extractors/fastify-routes.js +426 -0
  252. package/bin/runners/lib/extractors/index.js +363 -0
  253. package/bin/runners/lib/extractors/next-routes.js +524 -0
  254. package/bin/runners/lib/extractors/proof-graph.js +431 -0
  255. package/bin/runners/lib/extractors/route-matcher.js +451 -0
  256. package/bin/runners/lib/extractors/truthpack-v2.js +377 -0
  257. package/bin/runners/lib/extractors/ui-bindings.js +547 -0
  258. package/bin/runners/lib/finding-id.js +69 -0
  259. package/bin/runners/lib/finding-sorter.js +89 -0
  260. package/bin/runners/lib/findings-schema.js +281 -0
  261. package/bin/runners/lib/fingerprint.js +377 -0
  262. package/bin/runners/lib/firewall-prompt.js +50 -0
  263. package/bin/runners/lib/fix-output.js +228 -0
  264. package/bin/runners/lib/global-flags.js +250 -0
  265. package/bin/runners/lib/graph/graph-builder.js +265 -0
  266. package/bin/runners/lib/graph/html-renderer.js +413 -0
  267. package/bin/runners/lib/graph/index.js +32 -0
  268. package/bin/runners/lib/graph/runtime-collector.js +215 -0
  269. package/bin/runners/lib/graph/static-extractor.js +518 -0
  270. package/bin/runners/lib/help-formatter.js +413 -0
  271. package/bin/runners/lib/html-proof-report.js +913 -0
  272. package/bin/runners/lib/html-report.js +650 -0
  273. package/bin/runners/lib/init-wizard.js +601 -0
  274. package/bin/runners/lib/interactive-menu.js +1496 -0
  275. package/bin/runners/lib/json-output.js +76 -0
  276. package/bin/runners/lib/llm.js +75 -0
  277. package/bin/runners/lib/logger.js +38 -0
  278. package/bin/runners/lib/meter.js +61 -0
  279. package/bin/runners/lib/missions/briefing.js +427 -0
  280. package/bin/runners/lib/missions/checkpoint.js +753 -0
  281. package/bin/runners/lib/missions/evidence.js +126 -0
  282. package/bin/runners/lib/missions/hardening.js +851 -0
  283. package/bin/runners/lib/missions/plan.js +648 -0
  284. package/bin/runners/lib/missions/safety-gates.js +645 -0
  285. package/bin/runners/lib/missions/schema.js +478 -0
  286. package/bin/runners/lib/missions/templates.js +317 -0
  287. package/bin/runners/lib/next-action.js +560 -0
  288. package/bin/runners/lib/packs/bundle.js +675 -0
  289. package/bin/runners/lib/packs/evidence-pack.js +671 -0
  290. package/bin/runners/lib/packs/pack-factory.js +837 -0
  291. package/bin/runners/lib/packs/permissions-pack.js +686 -0
  292. package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
  293. package/bin/runners/lib/patch.js +40 -0
  294. package/bin/runners/lib/permissions/auth-model.js +213 -0
  295. package/bin/runners/lib/permissions/idor-prover.js +205 -0
  296. package/bin/runners/lib/permissions/index.js +45 -0
  297. package/bin/runners/lib/permissions/matrix-builder.js +198 -0
  298. package/bin/runners/lib/pkgjson.js +28 -0
  299. package/bin/runners/lib/policy.js +295 -0
  300. package/bin/runners/lib/polish/accessibility.js +62 -0
  301. package/bin/runners/lib/polish/analyzer.js +93 -0
  302. package/bin/runners/lib/polish/backend.js +87 -0
  303. package/bin/runners/lib/polish/configuration.js +83 -0
  304. package/bin/runners/lib/polish/documentation.js +83 -0
  305. package/bin/runners/lib/polish/frontend.js +817 -0
  306. package/bin/runners/lib/polish/index.js +27 -0
  307. package/bin/runners/lib/polish/infrastructure.js +80 -0
  308. package/bin/runners/lib/polish/internationalization.js +85 -0
  309. package/bin/runners/lib/polish/libraries.js +180 -0
  310. package/bin/runners/lib/polish/observability.js +75 -0
  311. package/bin/runners/lib/polish/performance.js +64 -0
  312. package/bin/runners/lib/polish/privacy.js +110 -0
  313. package/bin/runners/lib/polish/resilience.js +92 -0
  314. package/bin/runners/lib/polish/security.js +78 -0
  315. package/bin/runners/lib/polish/seo.js +71 -0
  316. package/bin/runners/lib/polish/styles.js +62 -0
  317. package/bin/runners/lib/polish/utils.js +104 -0
  318. package/bin/runners/lib/preflight.js +142 -0
  319. package/bin/runners/lib/prerequisites.js +149 -0
  320. package/bin/runners/lib/prove-output.js +220 -0
  321. package/bin/runners/lib/reality/correlation-detectors.js +359 -0
  322. package/bin/runners/lib/reality/index.js +318 -0
  323. package/bin/runners/lib/reality/request-hashing.js +416 -0
  324. package/bin/runners/lib/reality/request-mapper.js +453 -0
  325. package/bin/runners/lib/reality/safety-rails.js +463 -0
  326. package/bin/runners/lib/reality/semantic-snapshot.js +408 -0
  327. package/bin/runners/lib/reality/toast-detector.js +393 -0
  328. package/bin/runners/lib/reality-findings.js +84 -0
  329. package/bin/runners/lib/reality-output.js +231 -0
  330. package/bin/runners/lib/receipts.js +179 -0
  331. package/bin/runners/lib/redact.js +29 -0
  332. package/bin/runners/lib/replay/capsule-manager.js +154 -0
  333. package/bin/runners/lib/replay/index.js +263 -0
  334. package/bin/runners/lib/replay/player.js +348 -0
  335. package/bin/runners/lib/replay/recorder.js +331 -0
  336. package/bin/runners/lib/report-engine.js +626 -0
  337. package/bin/runners/lib/report-html.js +1233 -0
  338. package/bin/runners/lib/report-output.js +366 -0
  339. package/bin/runners/lib/report-templates.js +967 -0
  340. package/bin/runners/lib/report.js +135 -0
  341. package/bin/runners/lib/route-detection.js +1209 -0
  342. package/bin/runners/lib/route-truth.js +1322 -0
  343. package/bin/runners/lib/safelist/index.js +96 -0
  344. package/bin/runners/lib/safelist/integration.js +334 -0
  345. package/bin/runners/lib/safelist/matcher.js +696 -0
  346. package/bin/runners/lib/safelist/schema.js +948 -0
  347. package/bin/runners/lib/safelist/store.js +438 -0
  348. package/bin/runners/lib/sandbox/index.js +59 -0
  349. package/bin/runners/lib/sandbox/proof-chain.js +399 -0
  350. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
  351. package/bin/runners/lib/sandbox/worktree.js +174 -0
  352. package/bin/runners/lib/scan-cache.js +330 -0
  353. package/bin/runners/lib/scan-output-schema.js +344 -0
  354. package/bin/runners/lib/scan-output.js +631 -0
  355. package/bin/runners/lib/scan-runner.js +135 -0
  356. package/bin/runners/lib/schema-validator.js +350 -0
  357. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  358. package/bin/runners/lib/schemas/contracts.schema.json +160 -0
  359. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  360. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  361. package/bin/runners/lib/schemas/finding.schema.json +100 -0
  362. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -0
  363. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -0
  364. package/bin/runners/lib/schemas/reality-report.schema.json +162 -0
  365. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  366. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  367. package/bin/runners/lib/schemas/share-pack.schema.json +180 -0
  368. package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
  369. package/bin/runners/lib/schemas/ship-report.schema.json +117 -0
  370. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -0
  371. package/bin/runners/lib/schemas/validator.js +465 -0
  372. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  373. package/bin/runners/lib/score-history.js +282 -0
  374. package/bin/runners/lib/security-bridge.js +249 -0
  375. package/bin/runners/lib/server-usage.js +513 -0
  376. package/bin/runners/lib/share-pack.js +239 -0
  377. package/bin/runners/lib/ship-gate.js +832 -0
  378. package/bin/runners/lib/ship-manifest.js +1153 -0
  379. package/bin/runners/lib/ship-output-enterprise.js +239 -0
  380. package/bin/runners/lib/ship-output.js +1128 -0
  381. package/bin/runners/lib/snippets.js +67 -0
  382. package/bin/runners/lib/status-output.js +340 -0
  383. package/bin/runners/lib/terminal-ui.js +356 -0
  384. package/bin/runners/lib/truth.js +1691 -0
  385. package/bin/runners/lib/ui.js +562 -0
  386. package/bin/runners/lib/unified-cli-output.js +947 -0
  387. package/bin/runners/lib/unified-output.js +197 -0
  388. package/bin/runners/lib/upsell.js +410 -0
  389. package/bin/runners/lib/usage.js +153 -0
  390. package/bin/runners/lib/validate-patch.js +156 -0
  391. package/bin/runners/lib/verdict-engine.js +628 -0
  392. package/bin/runners/lib/verification.js +345 -0
  393. package/bin/runners/lib/why-tree.js +650 -0
  394. package/bin/runners/reality/engine.js +917 -0
  395. package/bin/runners/reality/flows.js +122 -0
  396. package/bin/runners/reality/report.js +378 -0
  397. package/bin/runners/reality/session.js +193 -0
  398. package/bin/runners/runAIAgent.js +229 -0
  399. package/bin/runners/runAgent.d.ts +5 -0
  400. package/bin/runners/runAgent.js +161 -0
  401. package/bin/runners/runAllowlist.js +418 -0
  402. package/bin/runners/runApprove.js +320 -0
  403. package/bin/runners/runAudit.js +692 -0
  404. package/bin/runners/runAuth.js +731 -0
  405. package/bin/runners/runCI.js +353 -0
  406. package/bin/runners/runCheckpoint.js +530 -0
  407. package/bin/runners/runClassify.js +928 -0
  408. package/bin/runners/runCleanup.js +343 -0
  409. package/bin/runners/runContext.d.ts +4 -0
  410. package/bin/runners/runContext.js +175 -0
  411. package/bin/runners/runDoctor.js +877 -0
  412. package/bin/runners/runEvidencePack.js +362 -0
  413. package/bin/runners/runFirewall.d.ts +5 -0
  414. package/bin/runners/runFirewall.js +134 -0
  415. package/bin/runners/runFirewallHook.d.ts +5 -0
  416. package/bin/runners/runFirewallHook.js +56 -0
  417. package/bin/runners/runFix.js +1355 -0
  418. package/bin/runners/runForge.js +451 -0
  419. package/bin/runners/runGuard.js +262 -0
  420. package/bin/runners/runInit.js +1927 -0
  421. package/bin/runners/runIntent.js +906 -0
  422. package/bin/runners/runKickoff.js +878 -0
  423. package/bin/runners/runLabs.js +424 -0
  424. package/bin/runners/runLaunch.js +2000 -0
  425. package/bin/runners/runLink.js +785 -0
  426. package/bin/runners/runMcp.js +1875 -0
  427. package/bin/runners/runPacks.js +2089 -0
  428. package/bin/runners/runPolish.d.ts +4 -0
  429. package/bin/runners/runPolish.js +390 -0
  430. package/bin/runners/runPromptFirewall.js +211 -0
  431. package/bin/runners/runProve.js +1411 -0
  432. package/bin/runners/runQuickstart.js +531 -0
  433. package/bin/runners/runReality.js +2260 -0
  434. package/bin/runners/runReport.js +726 -0
  435. package/bin/runners/runRuntime.js +110 -0
  436. package/bin/runners/runSafelist.js +1190 -0
  437. package/bin/runners/runScan.js +688 -0
  438. package/bin/runners/runShield.js +1282 -0
  439. package/bin/runners/runShip.js +1660 -0
  440. package/bin/runners/runTruth.d.ts +5 -0
  441. package/bin/runners/runTruth.js +101 -0
  442. package/bin/runners/runValidate.js +179 -0
  443. package/bin/runners/runWatch.js +478 -0
  444. package/bin/runners/utils.js +360 -0
  445. package/bin/scan.js +617 -0
  446. package/bin/vibecheck.js +1617 -0
  447. package/dist/guardrail/index.d.ts +2405 -0
  448. package/dist/guardrail/index.js +9747 -0
  449. package/dist/guardrail/index.js.map +1 -0
  450. package/dist/scanner/index.d.ts +282 -0
  451. package/dist/scanner/index.js +3395 -0
  452. package/dist/scanner/index.js.map +1 -0
  453. package/package.json +123 -104
  454. package/README.md +0 -491
  455. package/dist/index.js +0 -99711
  456. 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
+ };