vibecheck-ai 2.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,753 @@
1
+ // bin/runners/lib/missions/checkpoint.js
2
+ // ═══════════════════════════════════════════════════════════════════════════════
3
+ // MISSION CHECKPOINTS - Named checkpoints for instant rollback
4
+ // Each mission gets a checkpoint before execution for safe, reversible operations
5
+ // ═══════════════════════════════════════════════════════════════════════════════
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const crypto = require('crypto');
10
+ const { execSync } = require('child_process');
11
+ const {
12
+ CheckpointError,
13
+ RollbackError,
14
+ ValidationError,
15
+ isValidMissionId,
16
+ isValidCheckpointId,
17
+ isValidFilePath,
18
+ safeReadFile,
19
+ safeWriteFile,
20
+ safeReadJson,
21
+ safeWriteJson,
22
+ getAuditTrail,
23
+ } = require('./hardening');
24
+
25
+ /**
26
+ * Checkpoint directory within .vibecheck
27
+ */
28
+ const CHECKPOINT_DIR = '.vibecheck/checkpoints/missions';
29
+
30
+ /**
31
+ * Mission history file
32
+ */
33
+ const HISTORY_FILE = '.vibecheck/checkpoints/mission-history.json';
34
+
35
+ /**
36
+ * Generate a checkpoint ID for a mission
37
+ * @param {string} missionId - Mission ID
38
+ * @returns {string} Checkpoint ID
39
+ */
40
+ function generateCheckpointId(missionId) {
41
+ const timestamp = Date.now().toString(36);
42
+ return `cp_${missionId}_${timestamp}`;
43
+ }
44
+
45
+ /**
46
+ * Ensure directory exists
47
+ * @param {string} dir - Directory path
48
+ */
49
+ function ensureDir(dir) {
50
+ fs.mkdirSync(dir, { recursive: true });
51
+ }
52
+
53
+ /**
54
+ * Get git status for checkpoint metadata
55
+ * @param {string} repoRoot - Repository root
56
+ * @returns {object} Git status info
57
+ */
58
+ function getGitStatus(repoRoot) {
59
+ try {
60
+ const status = execSync('git status --porcelain', {
61
+ cwd: repoRoot,
62
+ encoding: 'utf8',
63
+ stdio: ['pipe', 'pipe', 'pipe']
64
+ }).trim();
65
+
66
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', {
67
+ cwd: repoRoot,
68
+ encoding: 'utf8',
69
+ stdio: ['pipe', 'pipe', 'pipe']
70
+ }).trim();
71
+
72
+ const commit = execSync('git rev-parse HEAD', {
73
+ cwd: repoRoot,
74
+ encoding: 'utf8',
75
+ stdio: ['pipe', 'pipe', 'pipe']
76
+ }).trim();
77
+
78
+ return {
79
+ branch,
80
+ commit,
81
+ dirty: status.length > 0,
82
+ changes: status.split('\n').filter(Boolean).length,
83
+ };
84
+ } catch (e) {
85
+ return { branch: 'unknown', commit: 'unknown', dirty: false, changes: 0 };
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Create a hash of file contents
91
+ * @param {string} content - File content
92
+ * @returns {string} SHA256 hash
93
+ */
94
+ function hashContent(content) {
95
+ return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
96
+ }
97
+
98
+ /**
99
+ * Create a checkpoint before a mission
100
+ * @param {string} repoRoot - Repository root
101
+ * @param {object} mission - Mission object
102
+ * @param {string[]} files - Files to snapshot
103
+ * @returns {object} Checkpoint object
104
+ * @throws {CheckpointError} If checkpoint creation fails
105
+ */
106
+ function createCheckpoint(repoRoot, mission, files) {
107
+ const audit = getAuditTrail();
108
+
109
+ // ═══════════════════════════════════════════════════════════════════════════════
110
+ // INPUT VALIDATION
111
+ // ═══════════════════════════════════════════════════════════════════════════════
112
+
113
+ if (!repoRoot || typeof repoRoot !== 'string') {
114
+ throw new ValidationError('repoRoot is required and must be a string', 'repoRoot', repoRoot);
115
+ }
116
+
117
+ if (!fs.existsSync(repoRoot)) {
118
+ throw new ValidationError('repoRoot does not exist', 'repoRoot', repoRoot);
119
+ }
120
+
121
+ if (!mission || typeof mission !== 'object') {
122
+ throw new ValidationError('mission is required and must be an object', 'mission', mission);
123
+ }
124
+
125
+ if (!mission.id) {
126
+ throw new ValidationError('mission.id is required', 'mission.id', null);
127
+ }
128
+
129
+ if (!Array.isArray(files)) {
130
+ throw new ValidationError('files must be an array', 'files', files);
131
+ }
132
+
133
+ // Validate and sanitize file paths
134
+ const validFiles = files.filter(f => {
135
+ if (!isValidFilePath(f)) {
136
+ audit.warn('checkpoint_invalid_file_skipped', { file: f, missionId: mission.id });
137
+ return false;
138
+ }
139
+ return true;
140
+ });
141
+
142
+ // ═══════════════════════════════════════════════════════════════════════════════
143
+ // CHECKPOINT CREATION
144
+ // ═══════════════════════════════════════════════════════════════════════════════
145
+
146
+ const checkpointId = generateCheckpointId(mission.id);
147
+ const checkpointDir = path.join(repoRoot, CHECKPOINT_DIR, checkpointId);
148
+
149
+ audit.info('checkpoint_create_start', { checkpointId, missionId: mission.id, fileCount: validFiles.length });
150
+
151
+ try {
152
+ ensureDir(checkpointDir);
153
+ } catch (e) {
154
+ throw new CheckpointError(`Failed to create checkpoint directory: ${e.message}`, 'create', checkpointId, { dir: checkpointDir });
155
+ }
156
+
157
+ // Snapshot files
158
+ const snapshots = [];
159
+ const errors = [];
160
+
161
+ for (const relPath of validFiles) {
162
+ const absPath = path.join(repoRoot, relPath);
163
+
164
+ try {
165
+ if (fs.existsSync(absPath)) {
166
+ const stats = fs.statSync(absPath);
167
+
168
+ // Skip directories
169
+ if (stats.isDirectory()) {
170
+ audit.warn('checkpoint_skip_directory', { path: relPath });
171
+ continue;
172
+ }
173
+
174
+ // Skip files that are too large (5MB max for checkpoints)
175
+ const MAX_FILE_SIZE = 5 * 1024 * 1024;
176
+ if (stats.size > MAX_FILE_SIZE) {
177
+ audit.warn('checkpoint_skip_large_file', { path: relPath, size: stats.size });
178
+ snapshots.push({
179
+ path: relPath,
180
+ existed: true,
181
+ hash: null,
182
+ size: stats.size,
183
+ skipped: true,
184
+ reason: 'File too large',
185
+ });
186
+ continue;
187
+ }
188
+
189
+ const content = fs.readFileSync(absPath, 'utf8');
190
+ const hash = hashContent(content);
191
+
192
+ // Save snapshot
193
+ const snapshotPath = path.join(checkpointDir, relPath);
194
+ ensureDir(path.dirname(snapshotPath));
195
+ fs.writeFileSync(snapshotPath, content, 'utf8');
196
+
197
+ snapshots.push({
198
+ path: relPath,
199
+ existed: true,
200
+ hash,
201
+ size: content.length,
202
+ });
203
+ } else {
204
+ // File doesn't exist - record this so we can delete it on rollback
205
+ snapshots.push({
206
+ path: relPath,
207
+ existed: false,
208
+ hash: null,
209
+ size: 0,
210
+ });
211
+ }
212
+ } catch (e) {
213
+ errors.push({ path: relPath, error: e.message });
214
+ audit.error('checkpoint_file_error', { path: relPath, error: e.message });
215
+ }
216
+ }
217
+
218
+ // If too many errors, fail the checkpoint
219
+ if (errors.length > validFiles.length / 2) {
220
+ // Clean up partial checkpoint
221
+ try {
222
+ fs.rmSync(checkpointDir, { recursive: true, force: true });
223
+ } catch (e) {
224
+ // Ignore cleanup errors
225
+ }
226
+ throw new CheckpointError(`Too many file errors: ${errors.length}/${validFiles.length} failed`, 'create', checkpointId, { errors });
227
+ }
228
+
229
+ // Create checkpoint metadata
230
+ const checkpoint = {
231
+ id: checkpointId,
232
+ missionId: mission.id,
233
+ missionType: mission.type,
234
+ createdAt: new Date().toISOString(),
235
+ gitStatus: getGitStatus(repoRoot),
236
+ snapshots,
237
+ files: validFiles.length,
238
+ successfulSnapshots: snapshots.filter(s => !s.skipped).length,
239
+ errors: errors.length > 0 ? errors : undefined,
240
+ };
241
+
242
+ // Save checkpoint metadata
243
+ const metadataPath = path.join(checkpointDir, '_checkpoint.json');
244
+ const writeResult = safeWriteJson(metadataPath, checkpoint);
245
+
246
+ if (!writeResult.ok) {
247
+ throw new CheckpointError(`Failed to write checkpoint metadata: ${writeResult.error}`, 'create', checkpointId);
248
+ }
249
+
250
+ // Update mission history
251
+ addToHistory(repoRoot, {
252
+ checkpointId,
253
+ missionId: mission.id,
254
+ missionType: mission.type,
255
+ missionTitle: mission.objective?.title || mission.title,
256
+ createdAt: checkpoint.createdAt,
257
+ status: 'created',
258
+ });
259
+
260
+ audit.info('checkpoint_create_success', {
261
+ checkpointId,
262
+ missionId: mission.id,
263
+ snapshotCount: snapshots.length,
264
+ errorCount: errors.length,
265
+ });
266
+
267
+ return checkpoint;
268
+ }
269
+
270
+ /**
271
+ * Rollback to a checkpoint
272
+ * @param {string} repoRoot - Repository root
273
+ * @param {string} checkpointId - Checkpoint ID
274
+ * @returns {object} Rollback result
275
+ */
276
+ function rollbackToCheckpoint(repoRoot, checkpointId) {
277
+ const audit = getAuditTrail();
278
+
279
+ // ═══════════════════════════════════════════════════════════════════════════════
280
+ // INPUT VALIDATION
281
+ // ═══════════════════════════════════════════════════════════════════════════════
282
+
283
+ if (!repoRoot || typeof repoRoot !== 'string') {
284
+ return {
285
+ ok: false,
286
+ error: 'repoRoot is required',
287
+ restored: [],
288
+ deleted: [],
289
+ };
290
+ }
291
+
292
+ if (!checkpointId || typeof checkpointId !== 'string') {
293
+ return {
294
+ ok: false,
295
+ error: 'checkpointId is required',
296
+ restored: [],
297
+ deleted: [],
298
+ };
299
+ }
300
+
301
+ // ═══════════════════════════════════════════════════════════════════════════════
302
+ // CHECKPOINT VALIDATION
303
+ // ═══════════════════════════════════════════════════════════════════════════════
304
+
305
+ const checkpointDir = path.join(repoRoot, CHECKPOINT_DIR, checkpointId);
306
+ const metadataPath = path.join(checkpointDir, '_checkpoint.json');
307
+
308
+ if (!fs.existsSync(checkpointDir)) {
309
+ audit.warn('rollback_checkpoint_not_found', { checkpointId });
310
+ return {
311
+ ok: false,
312
+ error: `Checkpoint not found: ${checkpointId}`,
313
+ restored: [],
314
+ deleted: [],
315
+ };
316
+ }
317
+
318
+ const metadataResult = safeReadJson(metadataPath);
319
+ if (!metadataResult.ok) {
320
+ audit.error('rollback_metadata_read_failed', { checkpointId, error: metadataResult.error });
321
+ return {
322
+ ok: false,
323
+ error: `Checkpoint metadata corrupted: ${metadataResult.error}`,
324
+ restored: [],
325
+ deleted: [],
326
+ };
327
+ }
328
+
329
+ const checkpoint = metadataResult.data;
330
+
331
+ // Validate checkpoint structure
332
+ if (!checkpoint.snapshots || !Array.isArray(checkpoint.snapshots)) {
333
+ audit.error('rollback_invalid_checkpoint', { checkpointId });
334
+ return {
335
+ ok: false,
336
+ error: 'Checkpoint has invalid structure (missing snapshots)',
337
+ restored: [],
338
+ deleted: [],
339
+ };
340
+ }
341
+
342
+ audit.info('rollback_start', {
343
+ checkpointId,
344
+ missionId: checkpoint.missionId,
345
+ snapshotCount: checkpoint.snapshots.length,
346
+ });
347
+
348
+ // ═══════════════════════════════════════════════════════════════════════════════
349
+ // ROLLBACK EXECUTION
350
+ // ═══════════════════════════════════════════════════════════════════════════════
351
+
352
+ const restored = [];
353
+ const deleted = [];
354
+ const errors = [];
355
+ const skipped = [];
356
+
357
+ for (const snapshot of checkpoint.snapshots) {
358
+ // Skip invalid paths
359
+ if (!snapshot.path || !isValidFilePath(snapshot.path)) {
360
+ skipped.push({ path: snapshot.path, reason: 'Invalid path' });
361
+ continue;
362
+ }
363
+
364
+ // Skip snapshots that were skipped during creation
365
+ if (snapshot.skipped) {
366
+ skipped.push({ path: snapshot.path, reason: snapshot.reason || 'Skipped during checkpoint' });
367
+ continue;
368
+ }
369
+
370
+ const absPath = path.join(repoRoot, snapshot.path);
371
+
372
+ try {
373
+ if (snapshot.existed) {
374
+ // Restore file from snapshot
375
+ const snapshotPath = path.join(checkpointDir, snapshot.path);
376
+ if (fs.existsSync(snapshotPath)) {
377
+ ensureDir(path.dirname(absPath));
378
+ fs.copyFileSync(snapshotPath, absPath);
379
+
380
+ // Verify restoration
381
+ const restoredContent = fs.readFileSync(absPath, 'utf8');
382
+ const restoredHash = hashContent(restoredContent);
383
+
384
+ if (snapshot.hash && restoredHash !== snapshot.hash) {
385
+ audit.warn('rollback_hash_mismatch', { path: snapshot.path });
386
+ }
387
+
388
+ restored.push(snapshot.path);
389
+ } else {
390
+ errors.push(`Snapshot missing: ${snapshot.path}`);
391
+ audit.error('rollback_snapshot_missing', { path: snapshot.path, checkpointId });
392
+ }
393
+ } else {
394
+ // File didn't exist before - delete it if it exists now
395
+ if (fs.existsSync(absPath)) {
396
+ fs.rmSync(absPath, { force: true });
397
+ deleted.push(snapshot.path);
398
+ }
399
+ }
400
+ } catch (e) {
401
+ errors.push(`Failed to restore ${snapshot.path}: ${e.message}`);
402
+ audit.error('rollback_file_error', { path: snapshot.path, error: e.message });
403
+ }
404
+ }
405
+
406
+ // Update history
407
+ updateHistoryStatus(repoRoot, checkpointId, 'rolled_back');
408
+
409
+ const success = errors.length === 0;
410
+
411
+ audit.info('rollback_complete', {
412
+ checkpointId,
413
+ success,
414
+ restored: restored.length,
415
+ deleted: deleted.length,
416
+ errors: errors.length,
417
+ skipped: skipped.length,
418
+ });
419
+
420
+ return {
421
+ ok: success,
422
+ checkpointId,
423
+ missionId: checkpoint.missionId,
424
+ restored,
425
+ deleted,
426
+ skipped,
427
+ errors,
428
+ };
429
+ }
430
+
431
+ /**
432
+ * Rollback a mission by its ID
433
+ * Finds the most recent checkpoint for the mission and rolls back
434
+ * @param {string} repoRoot - Repository root
435
+ * @param {string} missionId - Mission ID
436
+ * @returns {object} Rollback result
437
+ */
438
+ function rollbackMission(repoRoot, missionId) {
439
+ const audit = getAuditTrail();
440
+
441
+ // ═══════════════════════════════════════════════════════════════════════════════
442
+ // INPUT VALIDATION
443
+ // ═══════════════════════════════════════════════════════════════════════════════
444
+
445
+ if (!repoRoot || typeof repoRoot !== 'string') {
446
+ return {
447
+ ok: false,
448
+ error: 'repoRoot is required',
449
+ restored: [],
450
+ deleted: [],
451
+ };
452
+ }
453
+
454
+ if (!missionId || typeof missionId !== 'string') {
455
+ return {
456
+ ok: false,
457
+ error: 'missionId is required',
458
+ restored: [],
459
+ deleted: [],
460
+ };
461
+ }
462
+
463
+ audit.info('rollback_mission_start', { missionId });
464
+
465
+ // ═══════════════════════════════════════════════════════════════════════════════
466
+ // FIND CHECKPOINT
467
+ // ═══════════════════════════════════════════════════════════════════════════════
468
+
469
+ const history = loadHistory(repoRoot);
470
+
471
+ // Find most recent checkpoint for this mission
472
+ const missionCheckpoints = history
473
+ .filter(h => h.missionId === missionId && h.status !== 'rolled_back')
474
+ .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
475
+
476
+ if (missionCheckpoints.length === 0) {
477
+ audit.warn('rollback_mission_no_checkpoint', { missionId });
478
+ return {
479
+ ok: false,
480
+ error: `No checkpoint found for mission: ${missionId}`,
481
+ restored: [],
482
+ deleted: [],
483
+ };
484
+ }
485
+
486
+ const checkpointId = missionCheckpoints[0].checkpointId;
487
+ audit.debug('rollback_mission_using_checkpoint', { missionId, checkpointId });
488
+
489
+ return rollbackToCheckpoint(repoRoot, checkpointId);
490
+ }
491
+
492
+ /**
493
+ * Delete a checkpoint
494
+ * @param {string} repoRoot - Repository root
495
+ * @param {string} checkpointId - Checkpoint ID
496
+ * @returns {object} Delete result
497
+ */
498
+ function deleteCheckpoint(repoRoot, checkpointId) {
499
+ const checkpointDir = path.join(repoRoot, CHECKPOINT_DIR, checkpointId);
500
+
501
+ if (!fs.existsSync(checkpointDir)) {
502
+ return { ok: false, error: `Checkpoint not found: ${checkpointId}` };
503
+ }
504
+
505
+ try {
506
+ fs.rmSync(checkpointDir, { recursive: true, force: true });
507
+ updateHistoryStatus(repoRoot, checkpointId, 'deleted');
508
+ return { ok: true, checkpointId };
509
+ } catch (e) {
510
+ return { ok: false, error: e.message };
511
+ }
512
+ }
513
+
514
+ /**
515
+ * List all checkpoints
516
+ * @param {string} repoRoot - Repository root
517
+ * @returns {object[]} Array of checkpoint metadata
518
+ */
519
+ function listCheckpoints(repoRoot) {
520
+ const baseDir = path.join(repoRoot, CHECKPOINT_DIR);
521
+
522
+ if (!fs.existsSync(baseDir)) {
523
+ return [];
524
+ }
525
+
526
+ const checkpoints = [];
527
+ const dirs = fs.readdirSync(baseDir, { withFileTypes: true });
528
+
529
+ for (const dir of dirs) {
530
+ if (!dir.isDirectory() || dir.name.startsWith('.')) continue;
531
+
532
+ const metadataPath = path.join(baseDir, dir.name, '_checkpoint.json');
533
+ if (fs.existsSync(metadataPath)) {
534
+ try {
535
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
536
+ checkpoints.push(metadata);
537
+ } catch (e) {
538
+ // Skip invalid checkpoints
539
+ }
540
+ }
541
+ }
542
+
543
+ // Sort by creation date, newest first
544
+ return checkpoints.sort((a, b) =>
545
+ new Date(b.createdAt) - new Date(a.createdAt)
546
+ );
547
+ }
548
+
549
+ /**
550
+ * Get checkpoint by ID
551
+ * @param {string} repoRoot - Repository root
552
+ * @param {string} checkpointId - Checkpoint ID
553
+ * @returns {object|null} Checkpoint metadata or null
554
+ */
555
+ function getCheckpoint(repoRoot, checkpointId) {
556
+ const metadataPath = path.join(repoRoot, CHECKPOINT_DIR, checkpointId, '_checkpoint.json');
557
+
558
+ if (!fs.existsSync(metadataPath)) {
559
+ return null;
560
+ }
561
+
562
+ return JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
563
+ }
564
+
565
+ /**
566
+ * Get checkpoints for a specific mission
567
+ * @param {string} repoRoot - Repository root
568
+ * @param {string} missionId - Mission ID
569
+ * @returns {object[]} Array of checkpoints for the mission
570
+ */
571
+ function getCheckpointsForMission(repoRoot, missionId) {
572
+ return listCheckpoints(repoRoot).filter(cp => cp.missionId === missionId);
573
+ }
574
+
575
+ /**
576
+ * Load mission history
577
+ * @param {string} repoRoot - Repository root
578
+ * @returns {object[]} History entries
579
+ */
580
+ function loadHistory(repoRoot) {
581
+ const historyPath = path.join(repoRoot, HISTORY_FILE);
582
+
583
+ if (!fs.existsSync(historyPath)) {
584
+ return [];
585
+ }
586
+
587
+ try {
588
+ return JSON.parse(fs.readFileSync(historyPath, 'utf8'));
589
+ } catch (e) {
590
+ return [];
591
+ }
592
+ }
593
+
594
+ /**
595
+ * Add entry to mission history
596
+ * @param {string} repoRoot - Repository root
597
+ * @param {object} entry - History entry
598
+ */
599
+ function addToHistory(repoRoot, entry) {
600
+ const history = loadHistory(repoRoot);
601
+ history.push(entry);
602
+
603
+ // Keep only last 100 entries
604
+ const trimmed = history.slice(-100);
605
+
606
+ const historyPath = path.join(repoRoot, HISTORY_FILE);
607
+ ensureDir(path.dirname(historyPath));
608
+ fs.writeFileSync(historyPath, JSON.stringify(trimmed, null, 2), 'utf8');
609
+ }
610
+
611
+ /**
612
+ * Update history entry status
613
+ * @param {string} repoRoot - Repository root
614
+ * @param {string} checkpointId - Checkpoint ID
615
+ * @param {string} status - New status
616
+ */
617
+ function updateHistoryStatus(repoRoot, checkpointId, status) {
618
+ const history = loadHistory(repoRoot);
619
+
620
+ for (const entry of history) {
621
+ if (entry.checkpointId === checkpointId) {
622
+ entry.status = status;
623
+ entry.updatedAt = new Date().toISOString();
624
+ }
625
+ }
626
+
627
+ const historyPath = path.join(repoRoot, HISTORY_FILE);
628
+ fs.writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf8');
629
+ }
630
+
631
+ /**
632
+ * Get mission history
633
+ * @param {string} repoRoot - Repository root
634
+ * @param {object} options - Filter options
635
+ * @returns {object[]} Filtered history entries
636
+ */
637
+ function getMissionHistory(repoRoot, options = {}) {
638
+ const { missionId, missionType, status, limit = 50 } = options;
639
+ let history = loadHistory(repoRoot);
640
+
641
+ if (missionId) {
642
+ history = history.filter(h => h.missionId === missionId);
643
+ }
644
+
645
+ if (missionType) {
646
+ history = history.filter(h => h.missionType === missionType);
647
+ }
648
+
649
+ if (status) {
650
+ history = history.filter(h => h.status === status);
651
+ }
652
+
653
+ // Sort by creation date, newest first
654
+ history.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
655
+
656
+ return history.slice(0, limit);
657
+ }
658
+
659
+ /**
660
+ * Clean up old checkpoints
661
+ * @param {string} repoRoot - Repository root
662
+ * @param {object} options - Cleanup options
663
+ * @returns {object} Cleanup result
664
+ */
665
+ function cleanupOldCheckpoints(repoRoot, options = {}) {
666
+ const { maxAge = 7 * 24 * 60 * 60 * 1000, maxCount = 50 } = options; // 7 days default
667
+ const checkpoints = listCheckpoints(repoRoot);
668
+ const now = Date.now();
669
+ const deleted = [];
670
+
671
+ // Delete checkpoints older than maxAge
672
+ for (const cp of checkpoints) {
673
+ const age = now - new Date(cp.createdAt).getTime();
674
+ if (age > maxAge) {
675
+ const result = deleteCheckpoint(repoRoot, cp.id);
676
+ if (result.ok) deleted.push(cp.id);
677
+ }
678
+ }
679
+
680
+ // If still over maxCount, delete oldest
681
+ const remaining = listCheckpoints(repoRoot);
682
+ if (remaining.length > maxCount) {
683
+ const toDelete = remaining.slice(maxCount);
684
+ for (const cp of toDelete) {
685
+ const result = deleteCheckpoint(repoRoot, cp.id);
686
+ if (result.ok) deleted.push(cp.id);
687
+ }
688
+ }
689
+
690
+ return { deleted, count: deleted.length };
691
+ }
692
+
693
+ /**
694
+ * Mark checkpoint as applied (mission completed successfully)
695
+ * @param {string} repoRoot - Repository root
696
+ * @param {string} checkpointId - Checkpoint ID
697
+ */
698
+ function markCheckpointApplied(repoRoot, checkpointId) {
699
+ updateHistoryStatus(repoRoot, checkpointId, 'applied');
700
+ }
701
+
702
+ /**
703
+ * Mark checkpoint as failed
704
+ * @param {string} repoRoot - Repository root
705
+ * @param {string} checkpointId - Checkpoint ID
706
+ * @param {string} reason - Failure reason
707
+ */
708
+ function markCheckpointFailed(repoRoot, checkpointId, reason) {
709
+ const history = loadHistory(repoRoot);
710
+
711
+ for (const entry of history) {
712
+ if (entry.checkpointId === checkpointId) {
713
+ entry.status = 'failed';
714
+ entry.failureReason = reason;
715
+ entry.updatedAt = new Date().toISOString();
716
+ }
717
+ }
718
+
719
+ const historyPath = path.join(repoRoot, HISTORY_FILE);
720
+ fs.writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf8');
721
+ }
722
+
723
+ module.exports = {
724
+ // Core functions
725
+ createCheckpoint,
726
+ rollbackToCheckpoint,
727
+ rollbackMission,
728
+ deleteCheckpoint,
729
+
730
+ // Query functions
731
+ listCheckpoints,
732
+ getCheckpoint,
733
+ getCheckpointsForMission,
734
+
735
+ // History functions
736
+ getMissionHistory,
737
+ loadHistory,
738
+
739
+ // Status updates
740
+ markCheckpointApplied,
741
+ markCheckpointFailed,
742
+
743
+ // Maintenance
744
+ cleanupOldCheckpoints,
745
+
746
+ // Utilities
747
+ generateCheckpointId,
748
+ getGitStatus,
749
+
750
+ // Constants
751
+ CHECKPOINT_DIR,
752
+ HISTORY_FILE,
753
+ };