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,941 @@
1
+ /**
2
+ * Checkpoint System - Time Machine for Fearless Experimentation
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════════════════════
5
+ * "Checkpoint is the time machine. Let users experiment fearlessly."
6
+ * ═══════════════════════════════════════════════════════════════════════════════
7
+ *
8
+ * Features:
9
+ * - Delta storage (only modified files, not full repo)
10
+ * - Git-aware (captures branch, commit, dirty state)
11
+ * - Manifest with "why" (auto vs manual, command context)
12
+ * - Storage-aware with auto-cleanup
13
+ * - Fast create/restore operations
14
+ *
15
+ * Storage Model:
16
+ * ~/.vibecheck/checkpoints/
17
+ * ├── index.json # Checkpoint registry
18
+ * └── CP_<timestamp>_<hash>/
19
+ * ├── manifest.json # What, why, when
20
+ * ├── files/ # Changed files (delta storage)
21
+ * │ └── <relative-path>.bak
22
+ * └── metadata.json # Git state, env info
23
+ *
24
+ * @module lib/checkpoint
25
+ */
26
+
27
+ const fs = require("fs");
28
+ const path = require("path");
29
+ const os = require("os");
30
+ const crypto = require("crypto");
31
+ const { execSync } = require("child_process");
32
+
33
+ // ═══════════════════════════════════════════════════════════════════════════════
34
+ // CONSTANTS
35
+ // ═══════════════════════════════════════════════════════════════════════════════
36
+
37
+ const CHECKPOINT_DIR = path.join(os.homedir(), ".vibecheck", "checkpoints");
38
+ const INDEX_FILE = "index.json";
39
+ const MANIFEST_FILE = "manifest.json";
40
+ const METADATA_FILE = "metadata.json";
41
+ const FILES_DIR = "files";
42
+
43
+ /** Max checkpoints to keep (default) */
44
+ const DEFAULT_MAX_CHECKPOINTS = 20;
45
+
46
+ /** Max total storage size in bytes (100MB default) */
47
+ const DEFAULT_MAX_STORAGE_BYTES = 100 * 1024 * 1024;
48
+
49
+ /** Checkpoint ID prefix */
50
+ const CHECKPOINT_PREFIX = "CP";
51
+
52
+ /** Auto-checkpoint reasons */
53
+ const AUTO_REASONS = {
54
+ FIX_APPLY: "fix --apply",
55
+ FIX_MISSION: "fix mission",
56
+ POLISH_APPLY: "polish --apply",
57
+ SHIELD_ENFORCE: "shield enforce",
58
+ FORGE_OVERWRITE: "forge overwrite",
59
+ MANUAL: "manual",
60
+ };
61
+
62
+ // ═══════════════════════════════════════════════════════════════════════════════
63
+ // STORAGE MANAGEMENT
64
+ // ═══════════════════════════════════════════════════════════════════════════════
65
+
66
+ /**
67
+ * Ensure checkpoint directory exists.
68
+ */
69
+ function ensureCheckpointDir() {
70
+ if (!fs.existsSync(CHECKPOINT_DIR)) {
71
+ fs.mkdirSync(CHECKPOINT_DIR, { recursive: true, mode: 0o700 });
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Get checkpoint index path.
77
+ */
78
+ function getIndexPath() {
79
+ return path.join(CHECKPOINT_DIR, INDEX_FILE);
80
+ }
81
+
82
+ /**
83
+ * Read checkpoint index.
84
+ * @returns {object}
85
+ */
86
+ function readIndex() {
87
+ ensureCheckpointDir();
88
+ const indexPath = getIndexPath();
89
+
90
+ if (!fs.existsSync(indexPath)) {
91
+ return {
92
+ version: 1,
93
+ checkpoints: [],
94
+ settings: {
95
+ maxCheckpoints: DEFAULT_MAX_CHECKPOINTS,
96
+ maxStorageBytes: DEFAULT_MAX_STORAGE_BYTES,
97
+ },
98
+ };
99
+ }
100
+
101
+ try {
102
+ return JSON.parse(fs.readFileSync(indexPath, "utf8"));
103
+ } catch {
104
+ return {
105
+ version: 1,
106
+ checkpoints: [],
107
+ settings: {
108
+ maxCheckpoints: DEFAULT_MAX_CHECKPOINTS,
109
+ maxStorageBytes: DEFAULT_MAX_STORAGE_BYTES,
110
+ },
111
+ };
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Write checkpoint index.
117
+ * @param {object} index
118
+ */
119
+ function writeIndex(index) {
120
+ ensureCheckpointDir();
121
+ fs.writeFileSync(getIndexPath(), JSON.stringify(index, null, 2), { mode: 0o600 });
122
+ }
123
+
124
+ /**
125
+ * Generate checkpoint ID.
126
+ * @param {string} [tag]
127
+ * @returns {string}
128
+ */
129
+ function generateCheckpointId(tag) {
130
+ const timestamp = Date.now();
131
+ const hash = crypto.randomBytes(4).toString("hex");
132
+ const base = `${CHECKPOINT_PREFIX}_${timestamp}_${hash}`;
133
+ return tag ? `${base}_${sanitizeTag(tag)}` : base;
134
+ }
135
+
136
+ /**
137
+ * Sanitize tag for filesystem.
138
+ * @param {string} tag
139
+ * @returns {string}
140
+ */
141
+ function sanitizeTag(tag) {
142
+ return tag
143
+ .toLowerCase()
144
+ .replace(/[^a-z0-9-_]/g, "-")
145
+ .replace(/-+/g, "-")
146
+ .slice(0, 32);
147
+ }
148
+
149
+ /**
150
+ * Get checkpoint directory path.
151
+ * @param {string} checkpointId
152
+ * @returns {string}
153
+ */
154
+ function getCheckpointPath(checkpointId) {
155
+ return path.join(CHECKPOINT_DIR, checkpointId);
156
+ }
157
+
158
+ /**
159
+ * Calculate directory size recursively.
160
+ * @param {string} dir
161
+ * @returns {number}
162
+ */
163
+ function getDirectorySize(dir) {
164
+ if (!fs.existsSync(dir)) return 0;
165
+
166
+ let size = 0;
167
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
168
+
169
+ for (const entry of entries) {
170
+ const fullPath = path.join(dir, entry.name);
171
+ if (entry.isDirectory()) {
172
+ size += getDirectorySize(fullPath);
173
+ } else {
174
+ try {
175
+ size += fs.statSync(fullPath).size;
176
+ } catch {
177
+ // Skip inaccessible files
178
+ }
179
+ }
180
+ }
181
+
182
+ return size;
183
+ }
184
+
185
+ /**
186
+ * Get total checkpoint storage size.
187
+ * @returns {number}
188
+ */
189
+ function getTotalStorageSize() {
190
+ return getDirectorySize(CHECKPOINT_DIR);
191
+ }
192
+
193
+ // ═══════════════════════════════════════════════════════════════════════════════
194
+ // GIT INTEGRATION
195
+ // ═══════════════════════════════════════════════════════════════════════════════
196
+
197
+ /**
198
+ * Get current git state.
199
+ * @param {string} cwd
200
+ * @returns {object|null}
201
+ */
202
+ function getGitState(cwd) {
203
+ try {
204
+ // Check if in git repo
205
+ execSync("git rev-parse --git-dir", { cwd, stdio: "pipe" });
206
+
207
+ const branch = execSync("git branch --show-current", { cwd, encoding: "utf8" }).trim();
208
+ const commit = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim().slice(0, 8);
209
+ const dirty = execSync("git status --porcelain", { cwd, encoding: "utf8" }).trim().length > 0;
210
+
211
+ let stashCount = 0;
212
+ try {
213
+ const stashList = execSync("git stash list", { cwd, encoding: "utf8" });
214
+ stashCount = stashList.split("\n").filter(Boolean).length;
215
+ } catch {
216
+ // No stash
217
+ }
218
+
219
+ return {
220
+ branch,
221
+ commit,
222
+ dirty,
223
+ stashCount,
224
+ timestamp: new Date().toISOString(),
225
+ };
226
+ } catch {
227
+ return null;
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Get list of modified files from git.
233
+ * @param {string} cwd
234
+ * @returns {string[]}
235
+ */
236
+ function getGitModifiedFiles(cwd) {
237
+ try {
238
+ const output = execSync("git status --porcelain", { cwd, encoding: "utf8" });
239
+ return output
240
+ .split("\n")
241
+ .filter(Boolean)
242
+ .map(line => line.slice(3).trim())
243
+ .filter(f => !f.includes(" -> ")); // Exclude renames for now
244
+ } catch {
245
+ return [];
246
+ }
247
+ }
248
+
249
+ // ═══════════════════════════════════════════════════════════════════════════════
250
+ // CHECKPOINT CREATION
251
+ // ═══════════════════════════════════════════════════════════════════════════════
252
+
253
+ /**
254
+ * Create a checkpoint.
255
+ *
256
+ * @param {object} options
257
+ * @param {string} options.cwd - Working directory
258
+ * @param {string[]} options.files - Files to checkpoint (relative paths)
259
+ * @param {string} options.reason - Why checkpoint was created
260
+ * @param {string} [options.tag] - Optional tag
261
+ * @param {string} [options.command] - Command that triggered checkpoint
262
+ * @param {object} [options.context] - Additional context
263
+ * @returns {object} - Checkpoint info
264
+ */
265
+ function createCheckpoint({
266
+ cwd = process.cwd(),
267
+ files = [],
268
+ reason = AUTO_REASONS.MANUAL,
269
+ tag,
270
+ command,
271
+ context = {},
272
+ }) {
273
+ ensureCheckpointDir();
274
+
275
+ const checkpointId = generateCheckpointId(tag);
276
+ const checkpointPath = getCheckpointPath(checkpointId);
277
+ const filesPath = path.join(checkpointPath, FILES_DIR);
278
+
279
+ // Create checkpoint directory
280
+ fs.mkdirSync(filesPath, { recursive: true, mode: 0o700 });
281
+
282
+ // Get git state
283
+ const gitState = getGitState(cwd);
284
+
285
+ // If no files specified, get modified files from git
286
+ let filesToBackup = files.length > 0 ? files : getGitModifiedFiles(cwd);
287
+
288
+ // Filter to only existing files
289
+ filesToBackup = filesToBackup.filter(f => {
290
+ const fullPath = path.isAbsolute(f) ? f : path.join(cwd, f);
291
+ return fs.existsSync(fullPath) && fs.statSync(fullPath).isFile();
292
+ });
293
+
294
+ // Backup files
295
+ const backedUpFiles = [];
296
+ let totalSize = 0;
297
+
298
+ for (const file of filesToBackup) {
299
+ try {
300
+ const fullPath = path.isAbsolute(file) ? file : path.join(cwd, file);
301
+ const relativePath = path.isAbsolute(file) ? path.relative(cwd, file) : file;
302
+ const backupPath = path.join(filesPath, relativePath.replace(/[/\\]/g, "__"));
303
+
304
+ // Copy file
305
+ fs.copyFileSync(fullPath, backupPath);
306
+
307
+ const stats = fs.statSync(backupPath);
308
+ totalSize += stats.size;
309
+
310
+ backedUpFiles.push({
311
+ original: relativePath,
312
+ backup: path.basename(backupPath),
313
+ size: stats.size,
314
+ hash: hashFile(fullPath),
315
+ });
316
+ } catch (err) {
317
+ // Skip files that can't be backed up
318
+ console.warn(`Warning: Could not backup ${file}: ${err.message}`);
319
+ }
320
+ }
321
+
322
+ // Create manifest
323
+ const manifest = {
324
+ id: checkpointId,
325
+ version: 1,
326
+ created: new Date().toISOString(),
327
+ reason,
328
+ tag: tag || null,
329
+ command: command || null,
330
+ context,
331
+ files: backedUpFiles,
332
+ totalSize,
333
+ cwd,
334
+ };
335
+
336
+ fs.writeFileSync(
337
+ path.join(checkpointPath, MANIFEST_FILE),
338
+ JSON.stringify(manifest, null, 2),
339
+ { mode: 0o600 }
340
+ );
341
+
342
+ // Create metadata
343
+ const metadata = {
344
+ git: gitState,
345
+ env: {
346
+ platform: process.platform,
347
+ nodeVersion: process.version,
348
+ user: os.userInfo().username,
349
+ hostname: os.hostname(),
350
+ },
351
+ created: new Date().toISOString(),
352
+ };
353
+
354
+ fs.writeFileSync(
355
+ path.join(checkpointPath, METADATA_FILE),
356
+ JSON.stringify(metadata, null, 2),
357
+ { mode: 0o600 }
358
+ );
359
+
360
+ // Update index
361
+ const index = readIndex();
362
+ index.checkpoints.unshift({
363
+ id: checkpointId,
364
+ created: manifest.created,
365
+ reason,
366
+ tag: tag || null,
367
+ fileCount: backedUpFiles.length,
368
+ totalSize,
369
+ command: command || null,
370
+ });
371
+ writeIndex(index);
372
+
373
+ // Auto-cleanup if needed
374
+ autoCleanup();
375
+
376
+ return {
377
+ id: checkpointId,
378
+ path: checkpointPath,
379
+ files: backedUpFiles.length,
380
+ size: totalSize,
381
+ tag,
382
+ reason,
383
+ };
384
+ }
385
+
386
+ /**
387
+ * Hash file contents.
388
+ * @param {string} filePath
389
+ * @returns {string}
390
+ */
391
+ function hashFile(filePath) {
392
+ try {
393
+ const content = fs.readFileSync(filePath);
394
+ return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
395
+ } catch {
396
+ return "unknown";
397
+ }
398
+ }
399
+
400
+ // ═══════════════════════════════════════════════════════════════════════════════
401
+ // CHECKPOINT RESTORATION
402
+ // ═══════════════════════════════════════════════════════════════════════════════
403
+
404
+ /**
405
+ * Restore a checkpoint.
406
+ *
407
+ * @param {string} checkpointId - Checkpoint ID or "latest"
408
+ * @param {object} options
409
+ * @param {boolean} [options.dryRun] - Preview without restoring
410
+ * @param {string[]} [options.onlyFiles] - Only restore specific files
411
+ * @returns {object} - Restore result
412
+ */
413
+ function restoreCheckpoint(checkpointId, { dryRun = false, onlyFiles = [] } = {}) {
414
+ const index = readIndex();
415
+
416
+ // Handle "latest"
417
+ if (checkpointId === "latest") {
418
+ if (index.checkpoints.length === 0) {
419
+ throw new Error("No checkpoints available");
420
+ }
421
+ checkpointId = index.checkpoints[0].id;
422
+ }
423
+
424
+ // Handle tag lookup
425
+ if (!checkpointId.startsWith(CHECKPOINT_PREFIX)) {
426
+ const found = index.checkpoints.find(c => c.tag === checkpointId);
427
+ if (found) {
428
+ checkpointId = found.id;
429
+ } else {
430
+ throw new Error(`Checkpoint not found: ${checkpointId}`);
431
+ }
432
+ }
433
+
434
+ const checkpointPath = getCheckpointPath(checkpointId);
435
+
436
+ if (!fs.existsSync(checkpointPath)) {
437
+ throw new Error(`Checkpoint not found: ${checkpointId}`);
438
+ }
439
+
440
+ // Read manifest
441
+ const manifestPath = path.join(checkpointPath, MANIFEST_FILE);
442
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
443
+ const filesPath = path.join(checkpointPath, FILES_DIR);
444
+
445
+ const results = {
446
+ id: checkpointId,
447
+ restored: [],
448
+ skipped: [],
449
+ errors: [],
450
+ dryRun,
451
+ };
452
+
453
+ for (const file of manifest.files) {
454
+ // Filter by onlyFiles if specified
455
+ if (onlyFiles.length > 0 && !onlyFiles.includes(file.original)) {
456
+ results.skipped.push({ file: file.original, reason: "not in filter" });
457
+ continue;
458
+ }
459
+
460
+ const backupPath = path.join(filesPath, file.backup);
461
+ const targetPath = path.join(manifest.cwd, file.original);
462
+
463
+ if (!fs.existsSync(backupPath)) {
464
+ results.errors.push({ file: file.original, reason: "backup file missing" });
465
+ continue;
466
+ }
467
+
468
+ if (dryRun) {
469
+ results.restored.push({
470
+ file: file.original,
471
+ action: fs.existsSync(targetPath) ? "overwrite" : "create",
472
+ });
473
+ } else {
474
+ try {
475
+ // Ensure directory exists
476
+ const targetDir = path.dirname(targetPath);
477
+ if (!fs.existsSync(targetDir)) {
478
+ fs.mkdirSync(targetDir, { recursive: true });
479
+ }
480
+
481
+ // Copy file back
482
+ fs.copyFileSync(backupPath, targetPath);
483
+
484
+ results.restored.push({
485
+ file: file.original,
486
+ action: "restored",
487
+ });
488
+ } catch (err) {
489
+ results.errors.push({ file: file.original, reason: err.message });
490
+ }
491
+ }
492
+ }
493
+
494
+ return results;
495
+ }
496
+
497
+ // ═══════════════════════════════════════════════════════════════════════════════
498
+ // CHECKPOINT LISTING & INFO
499
+ // ═══════════════════════════════════════════════════════════════════════════════
500
+
501
+ /**
502
+ * List all checkpoints.
503
+ * @param {object} [options]
504
+ * @param {number} [options.limit]
505
+ * @returns {object[]}
506
+ */
507
+ function listCheckpoints({ limit } = {}) {
508
+ const index = readIndex();
509
+ let checkpoints = index.checkpoints;
510
+
511
+ if (limit && limit > 0) {
512
+ checkpoints = checkpoints.slice(0, limit);
513
+ }
514
+
515
+ return checkpoints.map(cp => ({
516
+ ...cp,
517
+ age: getAge(cp.created),
518
+ sizeFormatted: formatBytes(cp.totalSize),
519
+ }));
520
+ }
521
+
522
+ /**
523
+ * Get checkpoint details.
524
+ * @param {string} checkpointId
525
+ * @returns {object|null}
526
+ */
527
+ function getCheckpoint(checkpointId) {
528
+ const index = readIndex();
529
+
530
+ // Handle tag lookup
531
+ if (!checkpointId.startsWith(CHECKPOINT_PREFIX)) {
532
+ const found = index.checkpoints.find(c => c.tag === checkpointId);
533
+ if (found) {
534
+ checkpointId = found.id;
535
+ }
536
+ }
537
+
538
+ const checkpointPath = getCheckpointPath(checkpointId);
539
+
540
+ if (!fs.existsSync(checkpointPath)) {
541
+ return null;
542
+ }
543
+
544
+ try {
545
+ const manifest = JSON.parse(
546
+ fs.readFileSync(path.join(checkpointPath, MANIFEST_FILE), "utf8")
547
+ );
548
+ const metadata = JSON.parse(
549
+ fs.readFileSync(path.join(checkpointPath, METADATA_FILE), "utf8")
550
+ );
551
+
552
+ return {
553
+ ...manifest,
554
+ metadata,
555
+ age: getAge(manifest.created),
556
+ sizeFormatted: formatBytes(manifest.totalSize),
557
+ };
558
+ } catch {
559
+ return null;
560
+ }
561
+ }
562
+
563
+ /**
564
+ * Get latest checkpoint.
565
+ * @returns {object|null}
566
+ */
567
+ function getLatestCheckpoint() {
568
+ const index = readIndex();
569
+ if (index.checkpoints.length === 0) return null;
570
+ return getCheckpoint(index.checkpoints[0].id);
571
+ }
572
+
573
+ // ═══════════════════════════════════════════════════════════════════════════════
574
+ // CHECKPOINT DIFF
575
+ // ═══════════════════════════════════════════════════════════════════════════════
576
+
577
+ /**
578
+ * Compare checkpoint with current state.
579
+ * @param {string} checkpointId
580
+ * @returns {object}
581
+ */
582
+ function diffCheckpoint(checkpointId) {
583
+ const checkpoint = getCheckpoint(checkpointId);
584
+
585
+ if (!checkpoint) {
586
+ throw new Error(`Checkpoint not found: ${checkpointId}`);
587
+ }
588
+
589
+ const filesPath = path.join(getCheckpointPath(checkpoint.id), FILES_DIR);
590
+ const results = {
591
+ id: checkpoint.id,
592
+ created: checkpoint.created,
593
+ changes: [],
594
+ summary: { modified: 0, deleted: 0, unchanged: 0 },
595
+ };
596
+
597
+ for (const file of checkpoint.files) {
598
+ const backupPath = path.join(filesPath, file.backup);
599
+ const currentPath = path.join(checkpoint.cwd, file.original);
600
+
601
+ if (!fs.existsSync(currentPath)) {
602
+ results.changes.push({
603
+ file: file.original,
604
+ status: "deleted",
605
+ checkpointHash: file.hash,
606
+ currentHash: null,
607
+ });
608
+ results.summary.deleted++;
609
+ } else {
610
+ const currentHash = hashFile(currentPath);
611
+ if (currentHash === file.hash) {
612
+ results.changes.push({
613
+ file: file.original,
614
+ status: "unchanged",
615
+ hash: file.hash,
616
+ });
617
+ results.summary.unchanged++;
618
+ } else {
619
+ results.changes.push({
620
+ file: file.original,
621
+ status: "modified",
622
+ checkpointHash: file.hash,
623
+ currentHash,
624
+ });
625
+ results.summary.modified++;
626
+ }
627
+ }
628
+ }
629
+
630
+ return results;
631
+ }
632
+
633
+ // ═══════════════════════════════════════════════════════════════════════════════
634
+ // CHECKPOINT DELETION & CLEANUP
635
+ // ═══════════════════════════════════════════════════════════════════════════════
636
+
637
+ /**
638
+ * Delete a checkpoint.
639
+ * @param {string} checkpointId
640
+ * @returns {boolean}
641
+ */
642
+ function deleteCheckpoint(checkpointId) {
643
+ const index = readIndex();
644
+
645
+ // Handle tag lookup
646
+ if (!checkpointId.startsWith(CHECKPOINT_PREFIX)) {
647
+ const found = index.checkpoints.find(c => c.tag === checkpointId);
648
+ if (found) {
649
+ checkpointId = found.id;
650
+ }
651
+ }
652
+
653
+ const checkpointPath = getCheckpointPath(checkpointId);
654
+
655
+ if (!fs.existsSync(checkpointPath)) {
656
+ return false;
657
+ }
658
+
659
+ // Remove directory recursively
660
+ fs.rmSync(checkpointPath, { recursive: true, force: true });
661
+
662
+ // Update index
663
+ index.checkpoints = index.checkpoints.filter(c => c.id !== checkpointId);
664
+ writeIndex(index);
665
+
666
+ return true;
667
+ }
668
+
669
+ /**
670
+ * Prune old checkpoints.
671
+ * @param {object} options
672
+ * @param {number} [options.keep] - Number to keep
673
+ * @param {number} [options.olderThanDays] - Delete older than N days
674
+ * @returns {object}
675
+ */
676
+ function pruneCheckpoints({ keep, olderThanDays } = {}) {
677
+ const index = readIndex();
678
+ const results = { deleted: [], kept: [] };
679
+
680
+ let toDelete = [];
681
+
682
+ if (keep !== undefined && keep >= 0) {
683
+ // Keep N most recent
684
+ toDelete = index.checkpoints.slice(keep);
685
+ } else if (olderThanDays !== undefined && olderThanDays > 0) {
686
+ // Delete older than N days
687
+ const cutoff = Date.now() - (olderThanDays * 24 * 60 * 60 * 1000);
688
+ toDelete = index.checkpoints.filter(c => new Date(c.created).getTime() < cutoff);
689
+ }
690
+
691
+ for (const cp of toDelete) {
692
+ if (deleteCheckpoint(cp.id)) {
693
+ results.deleted.push(cp.id);
694
+ }
695
+ }
696
+
697
+ // Re-read index after deletions
698
+ const newIndex = readIndex();
699
+ results.kept = newIndex.checkpoints.map(c => c.id);
700
+
701
+ return results;
702
+ }
703
+
704
+ /**
705
+ * Auto-cleanup based on settings.
706
+ */
707
+ function autoCleanup() {
708
+ const index = readIndex();
709
+ const settings = index.settings || {
710
+ maxCheckpoints: DEFAULT_MAX_CHECKPOINTS,
711
+ maxStorageBytes: DEFAULT_MAX_STORAGE_BYTES,
712
+ };
713
+
714
+ // Check count limit
715
+ if (index.checkpoints.length > settings.maxCheckpoints) {
716
+ pruneCheckpoints({ keep: settings.maxCheckpoints });
717
+ }
718
+
719
+ // Check storage limit
720
+ const totalSize = getTotalStorageSize();
721
+ if (totalSize > settings.maxStorageBytes) {
722
+ // Delete oldest checkpoints until under limit
723
+ const newIndex = readIndex();
724
+ while (newIndex.checkpoints.length > 1 && getTotalStorageSize() > settings.maxStorageBytes) {
725
+ const oldest = newIndex.checkpoints[newIndex.checkpoints.length - 1];
726
+ deleteCheckpoint(oldest.id);
727
+ newIndex.checkpoints = newIndex.checkpoints.slice(0, -1);
728
+ }
729
+ }
730
+ }
731
+
732
+ // ═══════════════════════════════════════════════════════════════════════════════
733
+ // AUTO-CHECKPOINT INTEGRATION
734
+ // ═══════════════════════════════════════════════════════════════════════════════
735
+
736
+ /**
737
+ * Create auto-checkpoint before risky operation.
738
+ * Returns checkpoint ID for rollback reference.
739
+ *
740
+ * @param {object} options
741
+ * @param {string} options.command - Command name (fix, polish, shield, forge)
742
+ * @param {string} options.reason - Specific reason
743
+ * @param {string[]} options.files - Files to be modified
744
+ * @param {object} [options.context] - Additional context
745
+ * @returns {object}
746
+ */
747
+ function autoCheckpoint({ command, reason, files, context = {} }) {
748
+ return createCheckpoint({
749
+ cwd: process.cwd(),
750
+ files,
751
+ reason: `auto:${command}`,
752
+ command,
753
+ context: {
754
+ ...context,
755
+ auto: true,
756
+ timestamp: new Date().toISOString(),
757
+ },
758
+ });
759
+ }
760
+
761
+ /**
762
+ * Rollback to checkpoint (alias for restore).
763
+ * @param {string} checkpointId
764
+ * @returns {object}
765
+ */
766
+ function rollback(checkpointId) {
767
+ return restoreCheckpoint(checkpointId, { dryRun: false });
768
+ }
769
+
770
+ /**
771
+ * Register a mission checkpoint in the global checkpoint index.
772
+ * This bridges the mission checkpoint system with the CLI checkpoint system.
773
+ *
774
+ * @param {object} missionCheckpoint - Checkpoint from mission system
775
+ * @param {string} repoRoot - Repository root
776
+ */
777
+ function registerMissionCheckpoint(missionCheckpoint, repoRoot) {
778
+ try {
779
+ const index = readIndex();
780
+
781
+ // Check if already registered
782
+ const exists = index.checkpoints.some(c => c.id === missionCheckpoint.id);
783
+ if (exists) return;
784
+
785
+ index.checkpoints.unshift({
786
+ id: missionCheckpoint.id,
787
+ created: missionCheckpoint.createdAt || new Date().toISOString(),
788
+ reason: `auto:fix mission ${missionCheckpoint.missionId || ""}`,
789
+ tag: null,
790
+ fileCount: missionCheckpoint.snapshots?.length || 0,
791
+ totalSize: missionCheckpoint.snapshots?.reduce((sum, s) => sum + (s.size || 0), 0) || 0,
792
+ command: "fix --apply",
793
+ missionId: missionCheckpoint.missionId,
794
+ repoRoot,
795
+ });
796
+
797
+ writeIndex(index);
798
+ } catch {
799
+ // Non-critical - mission checkpoint still works
800
+ }
801
+ }
802
+
803
+ /**
804
+ * Bulk restore from mission checkpoint.
805
+ * Used when user wants to restore from a fix mission checkpoint via CLI.
806
+ *
807
+ * @param {string} checkpointId - Mission checkpoint ID
808
+ * @param {string} repoRoot - Repository root
809
+ * @returns {object}
810
+ */
811
+ function restoreMissionCheckpoint(checkpointId, repoRoot) {
812
+ try {
813
+ // Try mission checkpoint system first
814
+ const missionCheckpointModule = require("./missions/checkpoint");
815
+ const result = missionCheckpointModule.rollbackToCheckpoint(repoRoot, checkpointId);
816
+ return {
817
+ id: checkpointId,
818
+ restored: result.restored || [],
819
+ errors: result.errors || [],
820
+ dryRun: false,
821
+ source: "mission",
822
+ };
823
+ } catch {
824
+ // Fall back to standard checkpoint
825
+ return restoreCheckpoint(checkpointId);
826
+ }
827
+ }
828
+
829
+ // ═══════════════════════════════════════════════════════════════════════════════
830
+ // HELPERS
831
+ // ═══════════════════════════════════════════════════════════════════════════════
832
+
833
+ /**
834
+ * Format bytes to human readable.
835
+ * @param {number} bytes
836
+ * @returns {string}
837
+ */
838
+ function formatBytes(bytes) {
839
+ if (bytes === 0) return "0 B";
840
+ const k = 1024;
841
+ const sizes = ["B", "KB", "MB", "GB"];
842
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
843
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
844
+ }
845
+
846
+ /**
847
+ * Get age string from ISO date.
848
+ * @param {string} isoDate
849
+ * @returns {string}
850
+ */
851
+ function getAge(isoDate) {
852
+ const ms = Date.now() - new Date(isoDate).getTime();
853
+ const seconds = Math.floor(ms / 1000);
854
+ const minutes = Math.floor(seconds / 60);
855
+ const hours = Math.floor(minutes / 60);
856
+ const days = Math.floor(hours / 24);
857
+
858
+ if (days > 0) return `${days}d ago`;
859
+ if (hours > 0) return `${hours}h ago`;
860
+ if (minutes > 0) return `${minutes}m ago`;
861
+ return "just now";
862
+ }
863
+
864
+ /**
865
+ * Get storage status.
866
+ * @returns {object}
867
+ */
868
+ function getStorageStatus() {
869
+ const index = readIndex();
870
+ const totalSize = getTotalStorageSize();
871
+ const settings = index.settings || {
872
+ maxCheckpoints: DEFAULT_MAX_CHECKPOINTS,
873
+ maxStorageBytes: DEFAULT_MAX_STORAGE_BYTES,
874
+ };
875
+
876
+ return {
877
+ checkpointCount: index.checkpoints.length,
878
+ maxCheckpoints: settings.maxCheckpoints,
879
+ totalSize,
880
+ totalSizeFormatted: formatBytes(totalSize),
881
+ maxSize: settings.maxStorageBytes,
882
+ maxSizeFormatted: formatBytes(settings.maxStorageBytes),
883
+ usagePercent: Math.round((totalSize / settings.maxStorageBytes) * 100),
884
+ };
885
+ }
886
+
887
+ /**
888
+ * Update settings.
889
+ * @param {object} newSettings
890
+ */
891
+ function updateSettings(newSettings) {
892
+ const index = readIndex();
893
+ index.settings = { ...index.settings, ...newSettings };
894
+ writeIndex(index);
895
+ }
896
+
897
+ // ═══════════════════════════════════════════════════════════════════════════════
898
+ // EXPORTS
899
+ // ═══════════════════════════════════════════════════════════════════════════════
900
+
901
+ module.exports = {
902
+ // Constants
903
+ AUTO_REASONS,
904
+ CHECKPOINT_PREFIX,
905
+ CHECKPOINT_DIR,
906
+
907
+ // Core operations
908
+ createCheckpoint,
909
+ restoreCheckpoint,
910
+ deleteCheckpoint,
911
+
912
+ // Listing & info
913
+ listCheckpoints,
914
+ getCheckpoint,
915
+ getLatestCheckpoint,
916
+ diffCheckpoint,
917
+
918
+ // Cleanup
919
+ pruneCheckpoints,
920
+ autoCleanup,
921
+
922
+ // Auto-integration
923
+ autoCheckpoint,
924
+ rollback,
925
+
926
+ // Mission integration
927
+ registerMissionCheckpoint,
928
+ restoreMissionCheckpoint,
929
+
930
+ // Status & settings
931
+ getStorageStatus,
932
+ updateSettings,
933
+
934
+ // Helpers
935
+ formatBytes,
936
+ getAge,
937
+ getCheckpointPath,
938
+ ensureCheckpointDir,
939
+ readIndex,
940
+ writeIndex,
941
+ };