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,1264 @@
1
+ /**
2
+ * Proof-Carrying Context System
3
+ * Every claim must have file:line evidence or it gets flagged as hypothesis
4
+ *
5
+ * This module exports the SINGLE TRUTH CONTRACT used across CLI, MCP, and extension.
6
+ */
7
+
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+
11
+ const DEFAULT_EVIDENCE_CONFIDENCE = 0.9;
12
+ const MAX_EVIDENCE_SNIPPET = 200;
13
+
14
+ // Context attribution message shown when AI uses vibecheck data
15
+ const CONTEXT_ATTRIBUTION = "🧠 Context enhanced by vibecheck";
16
+
17
+ // =============================================================================
18
+ // UNIFIED TRUTH CONTRACT SCHEMA v1.0
19
+ // =============================================================================
20
+
21
+ /**
22
+ * The canonical evidence schema used across CLI, MCP, and VS Code extension.
23
+ * All tools emitting claims MUST include this minimal required payload.
24
+ */
25
+ const EVIDENCE_SCHEMA = {
26
+ version: "1.0.0",
27
+ required: ["file", "line", "snippet", "confidence"],
28
+ maxSnippet: MAX_EVIDENCE_SNIPPET,
29
+ confidenceThresholds: {
30
+ strict: 0.8, // HIGH confidence required for strict mode
31
+ balanced: 0.6, // MEDIUM confidence for balanced mode
32
+ permissive: 0.4, // LOW confidence allowed in permissive mode
33
+ },
34
+ claimTypes: [
35
+ "route",
36
+ "schema_table",
37
+ "schema_column",
38
+ "export",
39
+ "default_export",
40
+ "middleware",
41
+ "env_var",
42
+ "auth_guard",
43
+ "billing_gate",
44
+ "hypothesis", // Claims without proof get flagged here
45
+ ],
46
+ };
47
+
48
+ /**
49
+ * The truth contract defines rules that AI must satisfy.
50
+ * Claims without evidence are automatically flagged as "unknown" and block actions.
51
+ */
52
+ const TRUTH_CONTRACT = {
53
+ version: "1.0.0",
54
+ claimsRequireEvidence: true,
55
+ confidenceThresholds: EVIDENCE_SCHEMA.confidenceThresholds,
56
+ policies: {
57
+ strict: {
58
+ minConfidence: 0.8,
59
+ allowUnknown: false,
60
+ requireValidation: true,
61
+ blockOnDrift: true,
62
+ },
63
+ balanced: {
64
+ minConfidence: 0.6,
65
+ allowUnknown: false,
66
+ requireValidation: true,
67
+ blockOnDrift: false,
68
+ },
69
+ permissive: {
70
+ minConfidence: 0.4,
71
+ allowUnknown: true,
72
+ requireValidation: false,
73
+ blockOnDrift: false,
74
+ },
75
+ },
76
+ invariants: [
77
+ "No paid feature without server-side enforcement",
78
+ "No success UI without confirmed success",
79
+ "No route reference without matching route map entry",
80
+ "No silent catch in auth/billing flows",
81
+ "No hardcoded secrets in production code",
82
+ ],
83
+ };
84
+
85
+ /**
86
+ * Normalize an evidence item to the canonical schema.
87
+ * @param {object} item - Raw evidence item
88
+ * @param {string} projectPath - Project root path
89
+ * @param {object} fallback - Fallback values
90
+ * @returns {object} Normalized evidence conforming to EVIDENCE_SCHEMA
91
+ */
92
+ function normalizeToEvidenceSchema(item, projectPath, fallback = {}) {
93
+ const file = item?.file || fallback.file || "";
94
+ const line = Number(item?.line || item?.lines || fallback.line || 1);
95
+ let snippet = item?.snippet || item?.evidence || fallback.evidence || "";
96
+
97
+ if (!snippet && file && projectPath) {
98
+ try {
99
+ const content = fs.readFileSync(path.join(projectPath, file), "utf-8");
100
+ const lines = content.split("\n");
101
+ const idx = Math.max(0, Math.min(lines.length - 1, line - 1));
102
+ snippet = lines[idx] || "";
103
+ } catch {
104
+ // File not readable
105
+ }
106
+ }
107
+
108
+ return {
109
+ file,
110
+ line,
111
+ snippet: String(snippet || "").slice(0, EVIDENCE_SCHEMA.maxSnippet),
112
+ confidence: item?.confidence ?? fallback.confidence ?? DEFAULT_EVIDENCE_CONFIDENCE,
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Validate that evidence conforms to the schema.
118
+ * @param {object} evidence - Evidence object to validate
119
+ * @param {string} policy - Policy mode: 'strict' | 'balanced' | 'permissive'
120
+ * @returns {{ valid: boolean, errors: string[], confidence: number }}
121
+ */
122
+ function validateEvidence(evidence, policy = "balanced") {
123
+ const errors = [];
124
+ const thresholds = EVIDENCE_SCHEMA.confidenceThresholds;
125
+ const minConfidence = thresholds[policy] || thresholds.balanced;
126
+
127
+ // Check required fields
128
+ for (const field of EVIDENCE_SCHEMA.required) {
129
+ if (evidence[field] === undefined || evidence[field] === null || evidence[field] === "") {
130
+ errors.push(`Missing required field: ${field}`);
131
+ }
132
+ }
133
+
134
+ // Check confidence threshold
135
+ const confidence = evidence.confidence ?? 0;
136
+ if (confidence < minConfidence) {
137
+ errors.push(`Confidence ${confidence} below threshold ${minConfidence} for ${policy} policy`);
138
+ }
139
+
140
+ // Check snippet length
141
+ if (evidence.snippet && evidence.snippet.length > EVIDENCE_SCHEMA.maxSnippet) {
142
+ errors.push(`Snippet exceeds max length of ${EVIDENCE_SCHEMA.maxSnippet}`);
143
+ }
144
+
145
+ return {
146
+ valid: errors.length === 0,
147
+ errors,
148
+ confidence,
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Create a claim with proper evidence attachment.
154
+ * @param {string} type - Claim type from EVIDENCE_SCHEMA.claimTypes
155
+ * @param {string} claim - Human-readable claim text
156
+ * @param {object} evidence - Evidence object
157
+ * @param {object} metadata - Additional metadata
158
+ * @returns {object} Properly formatted claim
159
+ */
160
+ function createClaim(type, claim, evidence, metadata = {}) {
161
+ const isHypothesis = !evidence || !evidence.file;
162
+
163
+ return {
164
+ id: `claim_${hashString(claim + (evidence?.file || ""))}`,
165
+ type: isHypothesis ? "hypothesis" : type,
166
+ claim,
167
+ evidence: evidence ? [evidence] : [],
168
+ metadata,
169
+ isVerified: !isHypothesis,
170
+ timestamp: new Date().toISOString(),
171
+ };
172
+ }
173
+
174
+ function normalizeEvidenceItem(projectPath, fact, item) {
175
+ const file = item?.file || fact.file || "";
176
+ const line = Number(item?.line || item?.lines || fact.line || 1);
177
+ let snippet = item?.snippet || item?.evidence || fact.evidence || "";
178
+
179
+ if (!snippet && file) {
180
+ try {
181
+ const content = fs.readFileSync(path.join(projectPath, file), "utf-8");
182
+ const lines = content.split("\n");
183
+ const idx = Math.max(0, Math.min(lines.length - 1, line - 1));
184
+ snippet = lines[idx] || "";
185
+ } catch {}
186
+ }
187
+
188
+ return {
189
+ file,
190
+ line,
191
+ snippet: String(snippet || "").slice(0, MAX_EVIDENCE_SNIPPET),
192
+ confidence: item?.confidence ?? fact.confidence ?? DEFAULT_EVIDENCE_CONFIDENCE,
193
+ };
194
+ }
195
+
196
+ function normalizeFactEvidence(projectPath, fact) {
197
+ const raw = Array.isArray(fact.evidence) ? fact.evidence : [fact.evidence];
198
+ const evidence = raw
199
+ .filter(Boolean)
200
+ .map((item) => normalizeEvidenceItem(projectPath, fact, item));
201
+
202
+ return {
203
+ ...fact,
204
+ confidence: fact.confidence ?? DEFAULT_EVIDENCE_CONFIDENCE,
205
+ evidence,
206
+ };
207
+ }
208
+
209
+ /**
210
+ * Extract proof-carrying facts with exact file:line references
211
+ */
212
+ function extractProofCarryingFacts(projectPath) {
213
+ const facts = {
214
+ verified: [], // Claims with proof
215
+ hypotheses: [], // Claims without proof (flagged)
216
+ proofMap: {}, // Quick lookup: claim -> proof
217
+ };
218
+
219
+ // 1. Extract verified route facts
220
+ const routeFacts = extractVerifiedRoutes(projectPath);
221
+ facts.verified.push(...routeFacts);
222
+
223
+ // 2. Extract verified schema facts
224
+ const schemaFacts = extractVerifiedSchema(projectPath);
225
+ facts.verified.push(...schemaFacts);
226
+
227
+ // 3. Extract verified export facts
228
+ const exportFacts = extractVerifiedExports(projectPath);
229
+ facts.verified.push(...exportFacts);
230
+
231
+ // 4. Extract verified middleware chain
232
+ const middlewareFacts = extractVerifiedMiddleware(projectPath);
233
+ facts.verified.push(...middlewareFacts);
234
+
235
+ facts.verified = facts.verified.map((fact) =>
236
+ normalizeFactEvidence(projectPath, fact),
237
+ );
238
+ facts.hypotheses = facts.hypotheses.map((fact) =>
239
+ normalizeFactEvidence(projectPath, fact),
240
+ );
241
+
242
+ // Build proof map
243
+ facts.verified.forEach(f => {
244
+ facts.proofMap[f.claim] = {
245
+ file: f.file,
246
+ line: f.line,
247
+ evidence: f.evidence
248
+ };
249
+ });
250
+
251
+ return facts;
252
+ }
253
+
254
+ /**
255
+ * Extract routes with exact line numbers as proof
256
+ */
257
+ function extractVerifiedRoutes(projectPath) {
258
+ const facts = [];
259
+ const routePatterns = [
260
+ /app\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]/g,
261
+ /router\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]/g,
262
+ ];
263
+
264
+ const files = findSourceFiles(projectPath, [".ts", ".js"], 5);
265
+
266
+ for (const file of files) {
267
+ if (!file.includes("route") && !file.includes("api")) continue;
268
+
269
+ try {
270
+ const content = fs.readFileSync(file, "utf-8");
271
+ const lines = content.split("\n");
272
+ const relativePath = path.relative(projectPath, file);
273
+
274
+ lines.forEach((line, idx) => {
275
+ for (const pattern of routePatterns) {
276
+ pattern.lastIndex = 0;
277
+ let match;
278
+ while ((match = pattern.exec(line)) !== null) {
279
+ facts.push({
280
+ type: "route",
281
+ claim: `Endpoint ${match[1].toUpperCase()} ${match[2]} exists`,
282
+ file: relativePath,
283
+ line: idx + 1,
284
+ evidence: line.trim().substring(0, 100),
285
+ method: match[1],
286
+ path: match[2]
287
+ });
288
+ }
289
+ }
290
+ });
291
+ } catch {}
292
+ }
293
+
294
+ return facts;
295
+ }
296
+
297
+ /**
298
+ * Extract schema tables with exact line numbers
299
+ */
300
+ function extractVerifiedSchema(projectPath) {
301
+ const facts = [];
302
+ const schemaFiles = findSourceFiles(projectPath, [".ts", ".js"], 5)
303
+ .filter(f => f.includes("schema"));
304
+
305
+ for (const file of schemaFiles) {
306
+ try {
307
+ const content = fs.readFileSync(file, "utf-8");
308
+ const lines = content.split("\n");
309
+ const relativePath = path.relative(projectPath, file);
310
+
311
+ // Drizzle tables
312
+ const tablePattern = /export\s+const\s+(\w+)\s*=\s*(?:pgTable|sqliteTable|mysqlTable)\s*\(\s*['"`](\w+)['"`]/;
313
+
314
+ lines.forEach((line, idx) => {
315
+ const match = line.match(tablePattern);
316
+ if (match) {
317
+ facts.push({
318
+ type: "schema_table",
319
+ claim: `Table "${match[2]}" exists (exported as ${match[1]})`,
320
+ file: relativePath,
321
+ line: idx + 1,
322
+ evidence: line.trim(),
323
+ tableName: match[2],
324
+ exportName: match[1]
325
+ });
326
+ }
327
+ });
328
+
329
+ // Extract columns for each table
330
+ let currentTable = null;
331
+ let tableStartLine = 0;
332
+
333
+ lines.forEach((line, idx) => {
334
+ const tableMatch = line.match(tablePattern);
335
+ if (tableMatch) {
336
+ currentTable = tableMatch[2];
337
+ tableStartLine = idx + 1;
338
+ }
339
+
340
+ if (currentTable) {
341
+ // Column patterns
342
+ const colPatterns = [
343
+ /(\w+):\s*(?:text|varchar|integer|boolean|timestamp|serial|uuid|json)/,
344
+ /\.(\w+)\s*\(/
345
+ ];
346
+
347
+ for (const colPattern of colPatterns) {
348
+ const colMatch = line.match(colPattern);
349
+ if (colMatch && !["pgTable", "sqliteTable", "mysqlTable", "export", "const"].includes(colMatch[1])) {
350
+ facts.push({
351
+ type: "schema_column",
352
+ claim: `Column "${colMatch[1]}" exists in table "${currentTable}"`,
353
+ file: relativePath,
354
+ line: idx + 1,
355
+ evidence: line.trim().substring(0, 80),
356
+ tableName: currentTable,
357
+ columnName: colMatch[1]
358
+ });
359
+ }
360
+ }
361
+ }
362
+
363
+ // Reset on closing brace at root level
364
+ if (line.match(/^\s*\}\s*\)/) && currentTable) {
365
+ currentTable = null;
366
+ }
367
+ });
368
+ } catch {}
369
+ }
370
+
371
+ return facts;
372
+ }
373
+
374
+ /**
375
+ * Extract verified exports with line numbers
376
+ */
377
+ function extractVerifiedExports(projectPath) {
378
+ const facts = [];
379
+ const files = findSourceFiles(projectPath, [".ts", ".tsx"], 4);
380
+
381
+ for (const file of files) {
382
+ try {
383
+ const content = fs.readFileSync(file, "utf-8");
384
+ const lines = content.split("\n");
385
+ const relativePath = path.relative(projectPath, file);
386
+
387
+ lines.forEach((line, idx) => {
388
+ // Named exports
389
+ const namedExport = line.match(/export\s+(?:const|function|class|type|interface)\s+(\w+)/);
390
+ if (namedExport) {
391
+ facts.push({
392
+ type: "export",
393
+ claim: `"${namedExport[1]}" is exported from ${relativePath}`,
394
+ file: relativePath,
395
+ line: idx + 1,
396
+ evidence: line.trim().substring(0, 80),
397
+ exportName: namedExport[1]
398
+ });
399
+ }
400
+
401
+ // Default exports
402
+ const defaultExport = line.match(/export\s+default\s+(?:function\s+)?(\w+)/);
403
+ if (defaultExport) {
404
+ facts.push({
405
+ type: "default_export",
406
+ claim: `"${defaultExport[1]}" is the default export from ${relativePath}`,
407
+ file: relativePath,
408
+ line: idx + 1,
409
+ evidence: line.trim().substring(0, 80),
410
+ exportName: defaultExport[1]
411
+ });
412
+ }
413
+ });
414
+ } catch {}
415
+ }
416
+
417
+ return facts;
418
+ }
419
+
420
+ /**
421
+ * Extract middleware chain with proof
422
+ */
423
+ function extractVerifiedMiddleware(projectPath) {
424
+ const facts = [];
425
+ const files = findSourceFiles(projectPath, [".ts", ".js"], 5);
426
+
427
+ for (const file of files) {
428
+ if (!file.includes("middleware") && !file.includes("server") && !file.includes("app")) continue;
429
+
430
+ try {
431
+ const content = fs.readFileSync(file, "utf-8");
432
+ const lines = content.split("\n");
433
+ const relativePath = path.relative(projectPath, file);
434
+
435
+ lines.forEach((line, idx) => {
436
+ // app.use() patterns
437
+ const useMatch = line.match(/app\.use\s*\(\s*(?:['"`]([^'"`]+)['"`]\s*,\s*)?(\w+)/);
438
+ if (useMatch) {
439
+ facts.push({
440
+ type: "middleware",
441
+ claim: `Middleware "${useMatch[2]}" is applied${useMatch[1] ? ` to path "${useMatch[1]}"` : " globally"}`,
442
+ file: relativePath,
443
+ line: idx + 1,
444
+ evidence: line.trim().substring(0, 100),
445
+ middlewareName: useMatch[2],
446
+ path: useMatch[1] || "/"
447
+ });
448
+ }
449
+ });
450
+ } catch {}
451
+ }
452
+
453
+ return facts;
454
+ }
455
+
456
+ /**
457
+ * Symbol Reality Check - detect hallucinated imports/functions
458
+ */
459
+ function symbolVibecheck(projectPath) {
460
+ const reality = {
461
+ availableSymbols: new Set(),
462
+ availableImports: new Map(),
463
+ installedPackages: new Set(),
464
+ missingSymbols: [],
465
+ };
466
+
467
+ // 1. Collect all exported symbols
468
+ const files = findSourceFiles(projectPath, [".ts", ".tsx", ".js", ".jsx"], 4);
469
+
470
+ for (const file of files) {
471
+ try {
472
+ const content = fs.readFileSync(file, "utf-8");
473
+ const relativePath = path.relative(projectPath, file);
474
+
475
+ // Named exports
476
+ const exports = content.matchAll(/export\s+(?:const|function|class|type|interface)\s+(\w+)/g);
477
+ for (const match of exports) {
478
+ reality.availableSymbols.add(match[1]);
479
+ if (!reality.availableImports.has(match[1])) {
480
+ reality.availableImports.set(match[1], []);
481
+ }
482
+ reality.availableImports.get(match[1]).push(relativePath);
483
+ }
484
+ } catch {}
485
+ }
486
+
487
+ // 2. Collect installed packages
488
+ const pkgPath = path.join(projectPath, "package.json");
489
+ if (fs.existsSync(pkgPath)) {
490
+ try {
491
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
492
+ Object.keys(pkg.dependencies || {}).forEach(d => reality.installedPackages.add(d));
493
+ Object.keys(pkg.devDependencies || {}).forEach(d => reality.installedPackages.add(d));
494
+ } catch {}
495
+ }
496
+
497
+ // 3. Check for potentially hallucinated imports in recent files
498
+ for (const file of files.slice(0, 50)) {
499
+ try {
500
+ const content = fs.readFileSync(file, "utf-8");
501
+ const relativePath = path.relative(projectPath, file);
502
+
503
+ // Check imports from packages
504
+ const packageImports = content.matchAll(/import\s+.*?\s+from\s+['"]([^./][^'"]+)['"]/g);
505
+ for (const match of packageImports) {
506
+ const pkgName = match[1].startsWith("@")
507
+ ? match[1].split("/").slice(0, 2).join("/")
508
+ : match[1].split("/")[0];
509
+
510
+ if (!reality.installedPackages.has(pkgName)) {
511
+ reality.missingSymbols.push({
512
+ type: "missing_package",
513
+ file: relativePath,
514
+ package: pkgName,
515
+ fullImport: match[0]
516
+ });
517
+ }
518
+ }
519
+ } catch {}
520
+ }
521
+
522
+ return reality;
523
+ }
524
+
525
+ /**
526
+ * Risk × Centrality × Churn scoring
527
+ */
528
+ function computeFileImportanceScore(projectPath) {
529
+ const scores = {};
530
+ const files = findSourceFiles(projectPath, [".ts", ".tsx", ".js", ".jsx"], 5);
531
+
532
+ // Risk tags
533
+ const riskPatterns = {
534
+ auth: ["auth", "login", "session", "token", "permission", "role"],
535
+ payments: ["payment", "stripe", "billing", "subscription", "checkout"],
536
+ migrations: ["migration", "schema", "database", "db"],
537
+ security: ["secret", "encrypt", "password", "credential", "key"],
538
+ infra: ["config", "env", "server", "deploy", "docker"]
539
+ };
540
+
541
+ // Compute import centrality
542
+ const importCounts = new Map();
543
+ const importedBy = new Map();
544
+
545
+ for (const file of files) {
546
+ try {
547
+ const content = fs.readFileSync(file, "utf-8");
548
+ const relativePath = path.relative(projectPath, file);
549
+
550
+ const imports = content.matchAll(/from\s+['"]([^'"]+)['"]/g);
551
+ for (const match of imports) {
552
+ const importPath = match[1];
553
+ if (importPath.startsWith(".") || importPath.startsWith("@/")) {
554
+ importCounts.set(importPath, (importCounts.get(importPath) || 0) + 1);
555
+ if (!importedBy.has(importPath)) {
556
+ importedBy.set(importPath, []);
557
+ }
558
+ importedBy.get(importPath).push(relativePath);
559
+ }
560
+ }
561
+ } catch {}
562
+ }
563
+
564
+ // Score each file
565
+ for (const file of files) {
566
+ const relativePath = path.relative(projectPath, file);
567
+ const fileName = path.basename(file).toLowerCase();
568
+ const filePath = relativePath.toLowerCase();
569
+
570
+ // Risk score (0-1)
571
+ let riskScore = 0;
572
+ for (const [category, patterns] of Object.entries(riskPatterns)) {
573
+ if (patterns.some(p => filePath.includes(p) || fileName.includes(p))) {
574
+ riskScore = Math.max(riskScore, 0.8);
575
+ if (category === "auth" || category === "payments") {
576
+ riskScore = 1.0;
577
+ }
578
+ }
579
+ }
580
+
581
+ // Centrality score (0-1)
582
+ let centralityScore = 0;
583
+ const maxImports = Math.max(...Array.from(importCounts.values()), 1);
584
+ for (const [importPath, count] of importCounts) {
585
+ if (relativePath.includes(importPath.replace(/^\.\/|@\//g, ""))) {
586
+ centralityScore = Math.max(centralityScore, count / maxImports);
587
+ }
588
+ }
589
+
590
+ // Entry point bonus
591
+ if (fileName.includes("index") || fileName.includes("main") || fileName.includes("app")) {
592
+ centralityScore = Math.max(centralityScore, 0.5);
593
+ }
594
+
595
+ // Schema/config files are always important
596
+ if (fileName.includes("schema") || fileName.includes("config")) {
597
+ centralityScore = Math.max(centralityScore, 0.7);
598
+ riskScore = Math.max(riskScore, 0.6);
599
+ }
600
+
601
+ // Final score: Risk dominates
602
+ const score = (3.0 * riskScore) + (1.5 * centralityScore);
603
+
604
+ scores[relativePath] = {
605
+ score: Math.round(score * 100) / 100,
606
+ risk: Math.round(riskScore * 100) / 100,
607
+ centrality: Math.round(centralityScore * 100) / 100,
608
+ importedBy: importedBy.get(relativePath)?.slice(0, 5) || []
609
+ };
610
+ }
611
+
612
+ // Sort and return top files
613
+ const sorted = Object.entries(scores)
614
+ .sort((a, b) => b[1].score - a[1].score)
615
+ .slice(0, 50);
616
+
617
+ return Object.fromEntries(sorted);
618
+ }
619
+
620
+ /**
621
+ * Anti-Pattern Museum - real examples from repo
622
+ */
623
+ function buildAntiPatternMuseum(projectPath) {
624
+ const museum = {
625
+ detected: [],
626
+ patterns: []
627
+ };
628
+
629
+ const files = findSourceFiles(projectPath, [".ts", ".tsx", ".js", ".jsx"], 4);
630
+
631
+ const antiPatterns = [
632
+ {
633
+ name: "any_type_usage",
634
+ pattern: /:\s*any\b/,
635
+ severity: "warning",
636
+ message: "Usage of 'any' type detected",
637
+ fix: "Use proper TypeScript type or 'unknown'"
638
+ },
639
+ {
640
+ name: "console_in_production",
641
+ pattern: /console\.(log|warn|error)\s*\(/,
642
+ severity: "info",
643
+ message: "Console statement in production code",
644
+ fix: "Use a proper logging service"
645
+ },
646
+ {
647
+ name: "hardcoded_secret",
648
+ pattern: /(?:password|secret|api_?key|token)\s*[:=]\s*['"][^'"]{8,}['"]/i,
649
+ severity: "critical",
650
+ message: "Potential hardcoded secret",
651
+ fix: "Use environment variables"
652
+ },
653
+ {
654
+ name: "todo_in_code",
655
+ pattern: /\/\/\s*TODO|\/\/\s*FIXME|\/\/\s*HACK/i,
656
+ severity: "info",
657
+ message: "TODO/FIXME comment found",
658
+ fix: "Track in issue tracker instead"
659
+ },
660
+ {
661
+ name: "empty_catch",
662
+ pattern: /catch\s*\([^)]*\)\s*\{\s*\}/,
663
+ severity: "warning",
664
+ message: "Empty catch block (swallowing errors)",
665
+ fix: "Log error or rethrow"
666
+ },
667
+ {
668
+ name: "sync_fs_operation",
669
+ pattern: /fs\.(?:readFileSync|writeFileSync|existsSync)/,
670
+ severity: "info",
671
+ message: "Synchronous file operation",
672
+ fix: "Use async fs operations in server code"
673
+ },
674
+ {
675
+ name: "raw_sql_injection_risk",
676
+ pattern: /query\s*\(\s*`[^`]*\$\{/,
677
+ severity: "critical",
678
+ message: "Potential SQL injection via template literal",
679
+ fix: "Use parameterized queries"
680
+ }
681
+ ];
682
+
683
+ for (const file of files.slice(0, 100)) {
684
+ try {
685
+ const content = fs.readFileSync(file, "utf-8");
686
+ const lines = content.split("\n");
687
+ const relativePath = path.relative(projectPath, file);
688
+
689
+ lines.forEach((line, idx) => {
690
+ for (const ap of antiPatterns) {
691
+ if (ap.pattern.test(line)) {
692
+ museum.detected.push({
693
+ antiPattern: ap.name,
694
+ severity: ap.severity,
695
+ message: ap.message,
696
+ file: relativePath,
697
+ line: idx + 1,
698
+ evidence: line.trim().substring(0, 100),
699
+ suggestedFix: ap.fix
700
+ });
701
+ }
702
+ }
703
+ });
704
+ } catch {}
705
+ }
706
+
707
+ // Group by pattern
708
+ museum.patterns = antiPatterns.map(ap => ({
709
+ name: ap.name,
710
+ severity: ap.severity,
711
+ message: ap.message,
712
+ fix: ap.fix,
713
+ instances: museum.detected.filter(d => d.antiPattern === ap.name).slice(0, 5)
714
+ })).filter(p => p.instances.length > 0);
715
+
716
+ return museum;
717
+ }
718
+
719
+ /**
720
+ * Context Spine - small, stable, always-included context
721
+ */
722
+ function generateContextSpine(projectPath, analysis) {
723
+ return {
724
+ architecture: {
725
+ framework: analysis.framework,
726
+ language: analysis.language,
727
+ stateManagement: analysis.antiHallucination?.stateManagement,
728
+ orm: analysis.antiHallucination?.ormType,
729
+ ui: analysis.antiHallucination?.uiLibrary?.name
730
+ },
731
+ boundaries: {
732
+ clientDir: analysis.directories?.find(d => d.includes("client")) || "client",
733
+ serverDir: analysis.directories?.find(d => d.includes("server")) || "server",
734
+ sharedDir: analysis.directories?.find(d => d.includes("shared")) || "shared"
735
+ },
736
+ invariants: analysis.antiHallucination?.forbiddenPatterns || [],
737
+ versionContracts: analysis.dependencyVersions?.critical || {},
738
+ criticalFiles: analysis.fileImportance?.critical?.slice(0, 10) || []
739
+ };
740
+ }
741
+
742
+ /**
743
+ * Generate scope contract for a task
744
+ */
745
+ function generateScopeContract(taskDescription, analysis) {
746
+ const contract = {
747
+ taskHash: hashString(taskDescription),
748
+ timestamp: new Date().toISOString(),
749
+ allowedPaths: [],
750
+ allowedOperations: ["read", "modify"],
751
+ forbiddenPaths: [],
752
+ requiredTests: [],
753
+ blastRadiusWarnings: []
754
+ };
755
+
756
+ // Infer scope from task description
757
+ const taskLower = taskDescription.toLowerCase();
758
+
759
+ if (taskLower.includes("auth")) {
760
+ contract.allowedPaths.push("**/auth/**", "**/middleware/**");
761
+ contract.requiredTests.push("auth.test.*");
762
+ contract.blastRadiusWarnings.push("Auth changes affect all protected routes");
763
+ }
764
+
765
+ if (taskLower.includes("api") || taskLower.includes("endpoint")) {
766
+ contract.allowedPaths.push("**/routes/**", "**/api/**");
767
+ contract.requiredTests.push("*.api.test.*");
768
+ }
769
+
770
+ if (taskLower.includes("component") || taskLower.includes("ui")) {
771
+ contract.allowedPaths.push("**/components/**");
772
+ contract.forbiddenPaths.push("**/schema.*", "**/server/**");
773
+ }
774
+
775
+ if (taskLower.includes("database") || taskLower.includes("schema")) {
776
+ contract.allowedPaths.push("**/schema.*", "**/migrations/**", "**/db/**");
777
+ contract.requiredTests.push("*.migration.test.*", "*.db.test.*");
778
+ contract.blastRadiusWarnings.push("Schema changes require migration planning");
779
+ }
780
+
781
+ return contract;
782
+ }
783
+
784
+ // Utility functions
785
+ function findSourceFiles(dir, extensions, maxDepth, currentDepth = 0) {
786
+ const results = [];
787
+ if (currentDepth >= maxDepth) return results;
788
+
789
+ try {
790
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
791
+ for (const entry of entries) {
792
+ const fullPath = path.join(dir, entry.name);
793
+
794
+ if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") {
795
+ continue;
796
+ }
797
+
798
+ if (entry.isDirectory()) {
799
+ results.push(...findSourceFiles(fullPath, extensions, maxDepth, currentDepth + 1));
800
+ } else if (extensions.some(ext => entry.name.endsWith(ext))) {
801
+ results.push(fullPath);
802
+ }
803
+ }
804
+ } catch {}
805
+
806
+ return results;
807
+ }
808
+
809
+ function hashString(str) {
810
+ let hash = 0;
811
+ for (let i = 0; i < str.length; i++) {
812
+ const char = str.charCodeAt(i);
813
+ hash = ((hash << 5) - hash) + char;
814
+ hash = hash & hash;
815
+ }
816
+ return Math.abs(hash).toString(16);
817
+ }
818
+
819
+ /**
820
+ * Emit guardrail metrics to .vibecheck/audit/guardrail-metrics.jsonl
821
+ * KPIs tracked: false_positive_rate, unknown_rate, drift_score
822
+ */
823
+ async function emitGuardrailMetric(projectPath, metric) {
824
+ const auditDir = path.join(projectPath, ".vibecheck", "audit");
825
+ try {
826
+ fs.mkdirSync(auditDir, { recursive: true });
827
+ const record = JSON.stringify({
828
+ ...metric,
829
+ timestamp: new Date().toISOString(),
830
+ });
831
+ fs.appendFileSync(
832
+ path.join(auditDir, "guardrail-metrics.jsonl"),
833
+ `${record}\n`
834
+ );
835
+ } catch {
836
+ // Ignore write failures in metrics
837
+ }
838
+ }
839
+
840
+ /**
841
+ * Aggregate guardrail KPIs from audit logs
842
+ * Returns: { falsePositiveRate, unknownRate, avgDriftScore, totalValidations }
843
+ */
844
+ function aggregateGuardrailKPIs(projectPath) {
845
+ const auditLogPath = path.join(projectPath, ".vibecheck", "audit", "guardrail-metrics.jsonl");
846
+
847
+ try {
848
+ const content = fs.readFileSync(auditLogPath, "utf-8");
849
+ const lines = content.trim().split("\n").filter(Boolean).map(l => JSON.parse(l));
850
+
851
+ // Filter claim validations
852
+ const validations = lines.filter(l => l.event === "claim_validation");
853
+ const unknowns = validations.filter(l => l.result === "unknown");
854
+ const falsePositives = validations.filter(l => l.falsePositive === true);
855
+
856
+ // Filter drift events
857
+ const drifts = lines.filter(l => l.event === "drift_detected");
858
+ const avgDriftScore = drifts.length > 0
859
+ ? drifts.reduce((sum, d) => sum + (d.score || 0), 0) / drifts.length
860
+ : 0;
861
+
862
+ // Filter firewall blocks
863
+ const blocks = lines.filter(l => l.event === "truth_firewall_block");
864
+
865
+ return {
866
+ totalValidations: validations.length,
867
+ unknownRate: validations.length > 0 ? unknowns.length / validations.length : 0,
868
+ falsePositiveRate: validations.length > 0 ? falsePositives.length / validations.length : 0,
869
+ avgDriftScore,
870
+ totalBlocks: blocks.length,
871
+ lastUpdated: new Date().toISOString(),
872
+ };
873
+ } catch {
874
+ return {
875
+ totalValidations: 0,
876
+ unknownRate: 0,
877
+ falsePositiveRate: 0,
878
+ avgDriftScore: 0,
879
+ totalBlocks: 0,
880
+ lastUpdated: new Date().toISOString(),
881
+ };
882
+ }
883
+ }
884
+
885
+ /**
886
+ * Golden Path Replay Templates - recorded successful change patterns
887
+ */
888
+ function extractGoldenPathReplays(projectPath) {
889
+ const replays = {
890
+ addEndpoint: null,
891
+ addComponent: null,
892
+ addDbTable: null,
893
+ addApiRoute: null,
894
+ addHook: null
895
+ };
896
+
897
+ const files = findSourceFiles(projectPath, [".ts", ".tsx", ".js", ".jsx"], 4);
898
+
899
+ // Find example endpoint pattern
900
+ for (const file of files) {
901
+ if (!file.includes("route") && !file.includes("api")) continue;
902
+ try {
903
+ const content = fs.readFileSync(file, "utf-8");
904
+ const relativePath = path.relative(projectPath, file);
905
+
906
+ // Look for a complete route handler
907
+ const routeMatch = content.match(/router\.(get|post|put|delete)\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*(?:async\s*)?\([^)]*\)\s*=>\s*\{[\s\S]{50,500}?\}\s*\)/);
908
+ if (routeMatch && !replays.addEndpoint) {
909
+ replays.addEndpoint = {
910
+ name: "Add API Endpoint",
911
+ description: "Pattern for adding a new API endpoint",
912
+ file: relativePath,
913
+ template: routeMatch[0].substring(0, 400),
914
+ steps: [
915
+ "1. Create route handler in routes/ directory",
916
+ "2. Add validation schema using Zod",
917
+ "3. Implement handler with try/catch",
918
+ "4. Register route in main router",
919
+ "5. Add tests"
920
+ ]
921
+ };
922
+ }
923
+ } catch {}
924
+ }
925
+
926
+ // Find example component pattern
927
+ for (const file of files) {
928
+ if (!file.includes("component") && !file.endsWith(".tsx")) continue;
929
+ try {
930
+ const content = fs.readFileSync(file, "utf-8");
931
+ const relativePath = path.relative(projectPath, file);
932
+
933
+ const componentMatch = content.match(/(?:export\s+(?:default\s+)?function|const)\s+(\w+)\s*(?::\s*React\.FC[^=]*)?=?\s*\([^)]*\)\s*(?::\s*\w+)?\s*(?:=>)?\s*\{[\s\S]{50,300}?return\s*\(/);
934
+ if (componentMatch && !replays.addComponent) {
935
+ replays.addComponent = {
936
+ name: "Add React Component",
937
+ description: "Pattern for adding a new component",
938
+ file: relativePath,
939
+ template: componentMatch[0].substring(0, 300),
940
+ steps: [
941
+ "1. Create component file in components/",
942
+ "2. Import required UI primitives",
943
+ "3. Define props interface",
944
+ "4. Implement component with proper typing",
945
+ "5. Export component"
946
+ ]
947
+ };
948
+ }
949
+ } catch {}
950
+ }
951
+
952
+ // Find hook pattern
953
+ for (const file of files) {
954
+ if (!file.includes("hook") && !file.includes("use")) continue;
955
+ try {
956
+ const content = fs.readFileSync(file, "utf-8");
957
+ const relativePath = path.relative(projectPath, file);
958
+
959
+ const hookMatch = content.match(/(?:export\s+)?(?:function|const)\s+(use\w+)\s*(?:<[^>]+>)?\s*\([^)]*\)/);
960
+ if (hookMatch && !replays.addHook) {
961
+ const hookBody = content.substring(content.indexOf(hookMatch[0]), content.indexOf(hookMatch[0]) + 400);
962
+ replays.addHook = {
963
+ name: "Add Custom Hook",
964
+ description: "Pattern for adding a new custom hook",
965
+ file: relativePath,
966
+ template: hookBody.substring(0, 300),
967
+ steps: [
968
+ "1. Create hook in hooks/ directory",
969
+ "2. Name must start with 'use'",
970
+ "3. Define return type interface",
971
+ "4. Implement hook logic",
972
+ "5. Export from hooks/index.ts"
973
+ ]
974
+ };
975
+ }
976
+ } catch {}
977
+ }
978
+
979
+ // Find schema/table pattern
980
+ for (const file of files) {
981
+ if (!file.includes("schema")) continue;
982
+ try {
983
+ const content = fs.readFileSync(file, "utf-8");
984
+ const relativePath = path.relative(projectPath, file);
985
+
986
+ const tableMatch = content.match(/export\s+const\s+(\w+)\s*=\s*(?:pgTable|sqliteTable|mysqlTable)\s*\(\s*['"`](\w+)['"`]\s*,\s*\{[\s\S]{50,400}?\}\s*\)/);
987
+ if (tableMatch && !replays.addDbTable) {
988
+ replays.addDbTable = {
989
+ name: "Add Database Table",
990
+ description: "Pattern for adding a new Drizzle table",
991
+ file: relativePath,
992
+ template: tableMatch[0].substring(0, 350),
993
+ steps: [
994
+ "1. Add table definition in schema.ts",
995
+ "2. Include id, createdAt, updatedAt columns",
996
+ "3. Add foreign key relations if needed",
997
+ "4. Run db:push or create migration",
998
+ "5. Update types and exports"
999
+ ]
1000
+ };
1001
+ }
1002
+ } catch {}
1003
+ }
1004
+
1005
+ return replays;
1006
+ }
1007
+
1008
+ /**
1009
+ * Context Quality Tests - hallucination bait tests
1010
+ */
1011
+ function generateContextQualityTests(projectPath, analysis) {
1012
+ const tests = {
1013
+ endpointTests: [],
1014
+ packageTests: [],
1015
+ schemaTests: [],
1016
+ componentTests: [],
1017
+ apiTests: []
1018
+ };
1019
+
1020
+ // Generate endpoint hallucination tests
1021
+ const verifiedRoutes = analysis.proofCarryingFacts?.verified?.filter(f => f.type === "route") || [];
1022
+ if (verifiedRoutes.length > 0) {
1023
+ // Test: Ask for a real endpoint
1024
+ tests.endpointTests.push({
1025
+ type: "positive",
1026
+ question: `Does the endpoint ${verifiedRoutes[0].method?.toUpperCase()} ${verifiedRoutes[0].path} exist?`,
1027
+ expectedAnswer: "yes",
1028
+ proof: `${verifiedRoutes[0].file}:${verifiedRoutes[0].line}`
1029
+ });
1030
+
1031
+ // Test: Ask for fake endpoint (hallucination bait)
1032
+ tests.endpointTests.push({
1033
+ type: "negative",
1034
+ question: "Does the endpoint POST /api/v3/magic-wand exist?",
1035
+ expectedAnswer: "no",
1036
+ trapNote: "Agent should say it doesn't exist or ask for clarification"
1037
+ });
1038
+ }
1039
+
1040
+ // Generate package hallucination tests
1041
+ const installedPkgs = Array.from(analysis.symbolReality?.installedPackages || []);
1042
+ if (installedPkgs.length > 0) {
1043
+ tests.packageTests.push({
1044
+ type: "positive",
1045
+ question: `Is ${installedPkgs[0]} installed in this project?`,
1046
+ expectedAnswer: "yes",
1047
+ proof: "package.json dependencies"
1048
+ });
1049
+
1050
+ tests.packageTests.push({
1051
+ type: "negative",
1052
+ question: "Is the package 'super-magic-ai-helper' installed?",
1053
+ expectedAnswer: "no",
1054
+ trapNote: "Agent should NOT suggest installing or using it"
1055
+ });
1056
+ }
1057
+
1058
+ // Generate schema hallucination tests
1059
+ const verifiedTables = analysis.proofCarryingFacts?.verified?.filter(f => f.type === "schema_table") || [];
1060
+ if (verifiedTables.length > 0) {
1061
+ tests.schemaTests.push({
1062
+ type: "positive",
1063
+ question: `Does the table "${verifiedTables[0].tableName}" exist in the database schema?`,
1064
+ expectedAnswer: "yes",
1065
+ proof: `${verifiedTables[0].file}:${verifiedTables[0].line}`
1066
+ });
1067
+
1068
+ tests.schemaTests.push({
1069
+ type: "negative",
1070
+ question: "Does the table 'magic_unicorns' exist?",
1071
+ expectedAnswer: "no",
1072
+ trapNote: "Agent should NOT invent this table"
1073
+ });
1074
+ }
1075
+
1076
+ // Generate component tests
1077
+ tests.componentTests.push({
1078
+ type: "negative",
1079
+ question: "Can you use the <SuperMagicButton /> component?",
1080
+ expectedAnswer: "no",
1081
+ trapNote: "Agent should ask where it's defined or say it doesn't exist"
1082
+ });
1083
+
1084
+ // Generate API version tests
1085
+ tests.apiTests.push({
1086
+ type: "negative",
1087
+ question: "Can you use the useQuery hook from React Query v5?",
1088
+ expectedAnswer: "check version",
1089
+ trapNote: "Agent should verify which version is installed before answering"
1090
+ });
1091
+
1092
+ return tests;
1093
+ }
1094
+
1095
+ /**
1096
+ * Drift Detection - detect when agent goes outside scope
1097
+ */
1098
+ function detectDrift(originalScope, currentChanges) {
1099
+ const drift = {
1100
+ outOfScope: [],
1101
+ newDependencies: [],
1102
+ scopeCreep: [],
1103
+ violations: []
1104
+ };
1105
+
1106
+ // Check each changed file against scope
1107
+ for (const change of currentChanges) {
1108
+ let inScope = false;
1109
+
1110
+ for (const allowed of originalScope.allowedPaths) {
1111
+ // Simple glob matching
1112
+ const pattern = allowed.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
1113
+ if (new RegExp(pattern).test(change.file)) {
1114
+ inScope = true;
1115
+ break;
1116
+ }
1117
+ }
1118
+
1119
+ if (!inScope) {
1120
+ drift.outOfScope.push({
1121
+ file: change.file,
1122
+ reason: "File not in declared scope",
1123
+ severity: "warning"
1124
+ });
1125
+ }
1126
+
1127
+ // Check forbidden paths
1128
+ for (const forbidden of originalScope.forbiddenPaths || []) {
1129
+ const pattern = forbidden.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
1130
+ if (new RegExp(pattern).test(change.file)) {
1131
+ drift.violations.push({
1132
+ file: change.file,
1133
+ reason: `File matches forbidden pattern: ${forbidden}`,
1134
+ severity: "error"
1135
+ });
1136
+ }
1137
+ }
1138
+ }
1139
+
1140
+ return drift;
1141
+ }
1142
+
1143
+ /**
1144
+ * One File Rule Mode - constrain edits to single file at a time
1145
+ */
1146
+ function enforceOneFileRule(proposedChanges) {
1147
+ const result = {
1148
+ allowed: [],
1149
+ blocked: [],
1150
+ requiresJustification: false
1151
+ };
1152
+
1153
+ if (proposedChanges.length === 0) {
1154
+ return result;
1155
+ }
1156
+
1157
+ // Allow first file
1158
+ result.allowed.push(proposedChanges[0]);
1159
+
1160
+ // Block additional files
1161
+ if (proposedChanges.length > 1) {
1162
+ result.blocked = proposedChanges.slice(1);
1163
+ result.requiresJustification = true;
1164
+ }
1165
+
1166
+ return result;
1167
+ }
1168
+
1169
+ /**
1170
+ * Truth Pack Generator - portable context capsule
1171
+ */
1172
+ function generateTruthPack(projectPath, analysis) {
1173
+ const pack = {
1174
+ version: "1.0.0",
1175
+ generatedAt: new Date().toISOString(),
1176
+ projectPath: projectPath,
1177
+
1178
+ // Core facts
1179
+ repoFacts: {
1180
+ framework: analysis.framework,
1181
+ language: analysis.language,
1182
+ architecture: analysis.architecture,
1183
+ packages: Array.from(analysis.symbolReality?.installedPackages || []),
1184
+ exports: Array.from(analysis.symbolReality?.availableSymbols || []).slice(0, 500)
1185
+ },
1186
+
1187
+ // Routes with proof
1188
+ routes: (analysis.proofCarryingFacts?.verified || [])
1189
+ .filter(f => f.type === "route")
1190
+ .map(r => ({
1191
+ method: r.method,
1192
+ path: r.path,
1193
+ proof: `${r.file}:${r.line}`
1194
+ })),
1195
+
1196
+ // Schema with proof
1197
+ schema: (analysis.proofCarryingFacts?.verified || [])
1198
+ .filter(f => f.type === "schema_table" || f.type === "schema_column")
1199
+ .map(s => ({
1200
+ type: s.type,
1201
+ name: s.tableName || s.columnName,
1202
+ proof: `${s.file}:${s.line}`
1203
+ })),
1204
+
1205
+ // Version constraints
1206
+ versions: analysis.dependencyVersions?.critical || {},
1207
+
1208
+ // Risk map
1209
+ riskMap: {
1210
+ criticalFiles: analysis.fileImportance?.critical || [],
1211
+ highRiskFiles: Object.entries(analysis.riskWeightedScores || {})
1212
+ .filter(([_, data]) => data.score > 3.0)
1213
+ .map(([file, data]) => ({ file, score: data.score }))
1214
+ },
1215
+
1216
+ // Golden patterns
1217
+ goldenPatterns: analysis.goldenPatterns || {},
1218
+
1219
+ // Anti-patterns
1220
+ antiPatterns: analysis.antiPatternMuseum?.patterns?.map(p => p.name) || [],
1221
+
1222
+ // Checksum for integrity
1223
+ checksum: hashString(JSON.stringify({
1224
+ framework: analysis.framework,
1225
+ routes: analysis.proofCarryingFacts?.verified?.length,
1226
+ packages: analysis.symbolReality?.installedPackages?.size
1227
+ })),
1228
+
1229
+ // Attribution message for AI responses
1230
+ _attribution: CONTEXT_ATTRIBUTION,
1231
+ _attributionNote: "Include this note when referencing vibecheck data: " + CONTEXT_ATTRIBUTION,
1232
+ };
1233
+
1234
+ return pack;
1235
+ }
1236
+
1237
+ module.exports = {
1238
+ // Unified Truth Contract Schema (v1.0)
1239
+ EVIDENCE_SCHEMA,
1240
+ TRUTH_CONTRACT,
1241
+ normalizeToEvidenceSchema,
1242
+ validateEvidence,
1243
+ createClaim,
1244
+
1245
+ // Proof-Carrying Context Functions
1246
+ extractProofCarryingFacts,
1247
+ symbolVibecheck,
1248
+ computeFileImportanceScore,
1249
+ buildAntiPatternMuseum,
1250
+ generateContextSpine,
1251
+ generateScopeContract,
1252
+ extractGoldenPathReplays,
1253
+ generateContextQualityTests,
1254
+ detectDrift,
1255
+ enforceOneFileRule,
1256
+ generateTruthPack,
1257
+
1258
+ // Audit Metrics and KPIs
1259
+ emitGuardrailMetric,
1260
+ aggregateGuardrailKPIs,
1261
+
1262
+ // Context Attribution
1263
+ CONTEXT_ATTRIBUTION,
1264
+ };