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,648 @@
1
+ // bin/runners/lib/missions/plan.js
2
+ // ═══════════════════════════════════════════════════════════════════════════════
3
+ // MISSION PLANNING V2 - Enhanced with dependency-aware grouping, blast radius
4
+ // analysis, and risk-based batching. "Missions, not chaos."
5
+ // ═══════════════════════════════════════════════════════════════════════════════
6
+
7
+ const {
8
+ createMission,
9
+ calculateBlastRadius,
10
+ calculateRiskLevel,
11
+ RISK_LEVEL,
12
+ BLAST_RADIUS,
13
+ } = require('./schema');
14
+ const { templateForMissionType } = require('./templates');
15
+ const {
16
+ ValidationError,
17
+ validateFinding,
18
+ validateOptions,
19
+ getAuditTrail,
20
+ } = require('./hardening');
21
+
22
+ /**
23
+ * Score a finding for priority ordering
24
+ * Enhanced with confidence-based scoring
25
+ */
26
+ function scoreFinding(f) {
27
+ let score = 0;
28
+
29
+ // Base severity score
30
+ if (f.severity === "BLOCK") score += 100;
31
+ else if (f.severity === "WARN") score += 50;
32
+
33
+ // Confidence adjustment (findings with evidence are more reliable)
34
+ const confidence = f.confidence || (f.evidence?.length > 0 ? 0.8 : 0.5);
35
+ score = Math.round(score * confidence);
36
+
37
+ // Boost for findings with file evidence (more actionable)
38
+ if (f.file || f.evidence?.some(e => e.file)) {
39
+ score += 10;
40
+ }
41
+
42
+ // Boost for security-related categories
43
+ if (['Security', 'GhostAuth', 'AuthCoverage', 'Billing'].includes(f.category)) {
44
+ score += 20;
45
+ }
46
+
47
+ return score;
48
+ }
49
+
50
+ /**
51
+ * Generate a fingerprint for deduplication
52
+ * Uses multiple signals to identify truly unique findings
53
+ */
54
+ function generateFingerprint(f) {
55
+ const parts = [];
56
+
57
+ // Primary: category + normalized title
58
+ parts.push(f.category || 'Unknown');
59
+
60
+ // Normalize title (remove specific IDs, file paths, line numbers)
61
+ let normalizedTitle = (f.title || '')
62
+ .replace(/[a-f0-9]{8,}/gi, 'HASH') // Remove hash-like IDs
63
+ .replace(/:\d+/g, ':LINE') // Normalize line numbers
64
+ .replace(/\/[^/\s]+\.(ts|js|tsx|jsx)/gi, '/FILE.$1') // Normalize file paths
65
+ .trim();
66
+ parts.push(normalizedTitle);
67
+
68
+ // Secondary: file if available (for file-specific issues)
69
+ if (f.file) {
70
+ // Normalize the file path to base name for grouping
71
+ const fileName = f.file.split(/[/\\]/).pop() || f.file;
72
+ parts.push(fileName);
73
+ }
74
+
75
+ return parts.join('|');
76
+ }
77
+
78
+ /**
79
+ * Extended category to mission type mapping
80
+ * Includes new categories from enhanced detection
81
+ */
82
+ const CATEGORY_TO_MISSION_TYPE = {
83
+ // Security & Auth
84
+ Security: "REMOVE_OWNER_MODE",
85
+ GhostAuth: "ADD_SERVER_AUTH",
86
+ AuthCoverage: "ADD_SERVER_AUTH",
87
+ AuthDrift: "FIX_AUTH_DRIFT",
88
+
89
+ // Billing & Payments
90
+ Billing: "FIX_STRIPE_WEBHOOKS",
91
+ Entitlements: "ENFORCE_PAID_SURFACE",
92
+
93
+ // Routes & APIs
94
+ MissingRoute: "FIX_MISSING_ROUTE",
95
+ RouteDrift: "FIX_ROUTE_DRIFT",
96
+
97
+ // Environment & Config
98
+ EnvContract: "FIX_ENV_CONTRACT",
99
+
100
+ // Reality/Runtime issues
101
+ FakeSuccess: "FIX_FAKE_SUCCESS",
102
+ DeadUI: "FIX_DEAD_UI",
103
+ FakeDomain: "FIX_MOCK_DOMAINS",
104
+ FakeResponse: "FIX_PLACEHOLDER_DATA",
105
+ MockStatus: "FIX_MOCK_DOMAINS",
106
+
107
+ // Code Quality
108
+ EmptyCatch: "FIX_EMPTY_CATCH",
109
+ TestKeys: "FIX_TEST_KEYS",
110
+ HardcodedSecrets: "FIX_HARDCODED_SECRETS",
111
+ SilentFallback: "FIX_SILENT_FALLBACK",
112
+ };
113
+
114
+ /**
115
+ * Mission type priority (lower = higher priority)
116
+ * Security issues come first, then billing, then everything else
117
+ */
118
+ const MISSION_PRIORITY = {
119
+ // P0: Critical security (immediate fix required)
120
+ REMOVE_OWNER_MODE: 1,
121
+ FIX_HARDCODED_SECRETS: 2,
122
+ FIX_AUTH_DRIFT: 3,
123
+
124
+ // P1: Security & billing (fix before shipping)
125
+ FIX_STRIPE_WEBHOOKS: 10,
126
+ ENFORCE_PAID_SURFACE: 11,
127
+ ADD_SERVER_AUTH: 12,
128
+ FIX_TEST_KEYS: 13,
129
+
130
+ // P2: Fake data (fix before production)
131
+ FIX_MOCK_DOMAINS: 20,
132
+ FIX_PLACEHOLDER_DATA: 21,
133
+ FIX_FAKE_SUCCESS: 22,
134
+
135
+ // P3: Code quality (fix when possible)
136
+ FIX_MISSING_ROUTE: 30,
137
+ FIX_ROUTE_DRIFT: 31,
138
+ FIX_ENV_CONTRACT: 32,
139
+ FIX_EMPTY_CATCH: 33,
140
+ FIX_SILENT_FALLBACK: 34,
141
+
142
+ // P4: UI issues (fix before polish)
143
+ FIX_DEAD_UI: 40,
144
+
145
+ // P5: Generic (lowest priority)
146
+ GENERIC_FIX: 99,
147
+ };
148
+
149
+ /**
150
+ * Extract files from findings
151
+ * @param {Array} findings - Findings array
152
+ * @returns {string[]} Unique file paths
153
+ */
154
+ function extractFilesFromFindings(findings) {
155
+ const files = new Set();
156
+ for (const f of findings) {
157
+ if (f.file) files.add(f.file);
158
+ for (const ev of (f.evidence || [])) {
159
+ if (ev.file) files.add(ev.file);
160
+ if (ev.path) files.add(ev.path);
161
+ }
162
+ }
163
+ return Array.from(files);
164
+ }
165
+
166
+ /**
167
+ * Build a simple import graph from truthpack
168
+ * @param {object} truthpack - Truthpack object
169
+ * @returns {Map} Map of file -> imported files
170
+ */
171
+ function buildImportGraph(truthpack) {
172
+ const graph = new Map();
173
+
174
+ // Extract imports from truthpack if available
175
+ const imports = truthpack?.imports || truthpack?.dependencies?.imports || [];
176
+ for (const imp of imports) {
177
+ if (imp.from && imp.to) {
178
+ if (!graph.has(imp.from)) graph.set(imp.from, new Set());
179
+ graph.get(imp.from).add(imp.to);
180
+ }
181
+ }
182
+
183
+ return graph;
184
+ }
185
+
186
+ /**
187
+ * Find connected components in file graph
188
+ * Files that import each other should be grouped together
189
+ * @param {string[]} files - List of files
190
+ * @param {Map} importGraph - Import graph
191
+ * @returns {string[][]} Array of file clusters
192
+ */
193
+ function findConnectedFileClusters(files, importGraph) {
194
+ const fileSet = new Set(files);
195
+ const visited = new Set();
196
+ const clusters = [];
197
+
198
+ function dfs(file, cluster) {
199
+ if (visited.has(file)) return;
200
+ visited.add(file);
201
+ cluster.push(file);
202
+
203
+ // Check files this one imports
204
+ const imports = importGraph.get(file) || new Set();
205
+ for (const imported of imports) {
206
+ if (fileSet.has(imported)) {
207
+ dfs(imported, cluster);
208
+ }
209
+ }
210
+
211
+ // Check files that import this one
212
+ for (const [from, toSet] of importGraph) {
213
+ if (toSet.has(file) && fileSet.has(from)) {
214
+ dfs(from, cluster);
215
+ }
216
+ }
217
+ }
218
+
219
+ for (const file of files) {
220
+ if (!visited.has(file)) {
221
+ const cluster = [];
222
+ dfs(file, cluster);
223
+ if (cluster.length > 0) {
224
+ clusters.push(cluster);
225
+ }
226
+ }
227
+ }
228
+
229
+ return clusters;
230
+ }
231
+
232
+ /**
233
+ * Calculate cluster risk score
234
+ * @param {Array} findings - Findings in cluster
235
+ * @returns {number} Risk score 0-100
236
+ */
237
+ function calculateClusterRisk(findings) {
238
+ let score = 0;
239
+
240
+ for (const f of findings) {
241
+ // Severity contribution
242
+ if (f.severity === 'BLOCK') score += 30;
243
+ else if (f.severity === 'WARN') score += 15;
244
+ else score += 5;
245
+
246
+ // Confidence inverse (lower confidence = higher risk)
247
+ const confidence = f.confidence || 0.5;
248
+ score += Math.round((1 - confidence) * 10);
249
+ }
250
+
251
+ // Normalize by finding count, cap at 100
252
+ return Math.min(100, score);
253
+ }
254
+
255
+ /**
256
+ * Create a mission from a finding using the new schema
257
+ * Enhanced with confidence and better metadata
258
+ */
259
+ function missionFromFinding(f, relatedFindings = [], options = {}) {
260
+ const type = CATEGORY_TO_MISSION_TYPE[f.category] || "GENERIC_FIX";
261
+ const allFindingIds = [f.id, ...relatedFindings.map(r => r.id)];
262
+ const allFindings = [f, ...relatedFindings];
263
+
264
+ // Calculate mission confidence based on findings
265
+ const confidences = [f.confidence || 0.5, ...relatedFindings.map(r => r.confidence || 0.5)];
266
+ const avgConfidence = confidences.reduce((a, b) => a + b, 0) / confidences.length;
267
+
268
+ // Extract all files from findings
269
+ const allowedFiles = extractFilesFromFindings(allFindings);
270
+
271
+ // Get template for this mission type
272
+ const template = templateForMissionType(type);
273
+
274
+ // Use the new schema to create a proper mission object
275
+ return createMission({
276
+ type,
277
+ title: f.title,
278
+ severity: f.severity,
279
+ category: f.category,
280
+ targetFindingIds: allFindingIds,
281
+ template,
282
+ allowedFiles,
283
+ readOnlyContext: options.readOnlyContext || [],
284
+ confidence: avgConfidence,
285
+ evidence: f.evidence || [],
286
+ file: f.file || null,
287
+ });
288
+ }
289
+
290
+ /**
291
+ * Group related findings that can be fixed together
292
+ * E.g., multiple Dead UI issues in the same file
293
+ * Now with dependency-aware clustering
294
+ */
295
+ function groupRelatedFindings(findings, options = {}) {
296
+ const { importGraph = new Map(), maxClusterRisk = 80 } = options;
297
+ const groups = new Map();
298
+
299
+ // First pass: group by category
300
+ const byCategory = new Map();
301
+ for (const f of findings) {
302
+ const cat = f.category || 'Unknown';
303
+ if (!byCategory.has(cat)) byCategory.set(cat, []);
304
+ byCategory.get(cat).push(f);
305
+ }
306
+
307
+ // Second pass: within each category, cluster by file dependencies
308
+ for (const [category, catFindings] of byCategory) {
309
+ const files = extractFilesFromFindings(catFindings);
310
+ const clusters = findConnectedFileClusters(files, importGraph);
311
+
312
+ // Map files to their cluster index
313
+ const fileToCluster = new Map();
314
+ clusters.forEach((cluster, idx) => {
315
+ for (const file of cluster) {
316
+ fileToCluster.set(file, idx);
317
+ }
318
+ });
319
+
320
+ // Group findings by their file's cluster
321
+ const clusterGroups = new Map();
322
+ for (const f of catFindings) {
323
+ const file = f.file || f.evidence?.[0]?.file || f.evidence?.[0]?.path || 'unknown';
324
+ const clusterIdx = fileToCluster.get(file) ?? -1;
325
+ const groupKey = `${category}:cluster_${clusterIdx}:${file}`;
326
+
327
+ if (!clusterGroups.has(groupKey)) {
328
+ clusterGroups.set(groupKey, []);
329
+ }
330
+ clusterGroups.get(groupKey).push(f);
331
+ }
332
+
333
+ // Third pass: split groups that exceed risk threshold
334
+ for (const [groupKey, groupFindings] of clusterGroups) {
335
+ const risk = calculateClusterRisk(groupFindings);
336
+
337
+ if (risk > maxClusterRisk && groupFindings.length > 1) {
338
+ // Split into individual findings for high-risk groups
339
+ for (let i = 0; i < groupFindings.length; i++) {
340
+ groups.set(`${groupKey}:split_${i}`, [groupFindings[i]]);
341
+ }
342
+ } else {
343
+ groups.set(groupKey, groupFindings);
344
+ }
345
+ }
346
+ }
347
+
348
+ return groups;
349
+ }
350
+
351
+ /**
352
+ * Advanced grouping with blast radius analysis
353
+ * Groups findings while respecting blast radius limits
354
+ */
355
+ function groupWithBlastRadiusLimit(findings, options = {}) {
356
+ const { maxBlastRadius = 5, importGraph = new Map() } = options;
357
+ const groups = new Map();
358
+
359
+ // Start with basic grouping
360
+ const basicGroups = groupRelatedFindings(findings, { importGraph });
361
+
362
+ // Check each group's blast radius
363
+ for (const [key, groupFindings] of basicGroups) {
364
+ const files = extractFilesFromFindings(groupFindings);
365
+
366
+ if (files.length > maxBlastRadius) {
367
+ // Split into smaller groups by file
368
+ const byFile = new Map();
369
+ for (const f of groupFindings) {
370
+ const file = f.file || f.evidence?.[0]?.file || 'unknown';
371
+ if (!byFile.has(file)) byFile.set(file, []);
372
+ byFile.get(file).push(f);
373
+ }
374
+
375
+ // Create separate groups for each file
376
+ let idx = 0;
377
+ for (const [file, fileFindings] of byFile) {
378
+ groups.set(`${key}:file_${idx++}`, fileFindings);
379
+ }
380
+ } else {
381
+ groups.set(key, groupFindings);
382
+ }
383
+ }
384
+
385
+ return groups;
386
+ }
387
+
388
+ /**
389
+ * Plan missions from findings with enhanced deduplication and prioritization
390
+ *
391
+ * @param {Array} findings - List of findings from ship/scan
392
+ * @param {Object} options - Planning options
393
+ * @param {number} [options.maxMissions=12] - Maximum missions to plan
394
+ * @param {boolean} [options.blocksOnlyFirst=true] - Prioritize BLOCK findings
395
+ * @param {boolean} [options.groupRelated=true] - Group related findings
396
+ * @param {object} [options.truthpack] - Truthpack for dependency analysis
397
+ * @param {number} [options.maxBlastRadius=5] - Maximum files per mission
398
+ * @param {number} [options.maxClusterRisk=80] - Maximum cluster risk score
399
+ * @param {number} [options.minConfidence=0] - Minimum confidence threshold
400
+ * @returns {Array} Planned missions
401
+ */
402
+ function planMissions(findings, options = {}) {
403
+ const audit = getAuditTrail();
404
+
405
+ // ═══════════════════════════════════════════════════════════════════════════════
406
+ // INPUT VALIDATION
407
+ // ═══════════════════════════════════════════════════════════════════════════════
408
+
409
+ // Handle null/undefined findings
410
+ if (!findings) {
411
+ audit.warn('plan_missions_no_findings', { findings });
412
+ return [];
413
+ }
414
+
415
+ // Handle non-array findings
416
+ if (!Array.isArray(findings)) {
417
+ audit.error('plan_missions_invalid_findings', { type: typeof findings });
418
+ throw new ValidationError('findings must be an array', 'findings', findings);
419
+ }
420
+
421
+ // Handle empty findings
422
+ if (findings.length === 0) {
423
+ audit.info('plan_missions_empty_findings');
424
+ return [];
425
+ }
426
+
427
+ // Validate and sanitize options
428
+ const optionsSchema = {
429
+ maxMissions: { type: 'number', default: 12, min: 1, max: 100 },
430
+ blocksOnlyFirst: { type: 'boolean', default: true },
431
+ groupRelated: { type: 'boolean', default: true },
432
+ maxBlastRadius: { type: 'number', default: 5, min: 1, max: 50 },
433
+ maxClusterRisk: { type: 'number', default: 80, min: 0, max: 100 },
434
+ minConfidence: { type: 'number', default: 0, min: 0, max: 1 },
435
+ };
436
+
437
+ const validatedOptions = validateOptions(options, optionsSchema);
438
+ if (!validatedOptions.valid) {
439
+ audit.warn('plan_missions_invalid_options', { errors: validatedOptions.errors });
440
+ }
441
+
442
+ const {
443
+ maxMissions,
444
+ blocksOnlyFirst,
445
+ groupRelated,
446
+ maxBlastRadius,
447
+ maxClusterRisk,
448
+ minConfidence,
449
+ } = validatedOptions.sanitized;
450
+
451
+ const truthpack = options.truthpack || null;
452
+
453
+ audit.info('plan_missions_start', {
454
+ findingCount: findings.length,
455
+ maxMissions,
456
+ blocksOnlyFirst,
457
+ groupRelated,
458
+ });
459
+
460
+ // Build import graph from truthpack if available
461
+ const importGraph = truthpack ? buildImportGraph(truthpack) : new Map();
462
+
463
+ // ═══════════════════════════════════════════════════════════════════════════════
464
+ // FINDING VALIDATION & FILTERING
465
+ // ═══════════════════════════════════════════════════════════════════════════════
466
+
467
+ // Validate and filter findings
468
+ const validFindings = [];
469
+ let invalidCount = 0;
470
+
471
+ for (const f of findings) {
472
+ const validation = validateFinding(f);
473
+ if (validation.valid) {
474
+ validFindings.push(f);
475
+ } else {
476
+ invalidCount++;
477
+ audit.debug('plan_missions_invalid_finding', { id: f?.id, errors: validation.errors });
478
+ }
479
+ }
480
+
481
+ if (invalidCount > 0) {
482
+ audit.warn('plan_missions_invalid_findings_skipped', { invalidCount, validCount: validFindings.length });
483
+ }
484
+
485
+ if (validFindings.length === 0) {
486
+ audit.info('plan_missions_no_valid_findings');
487
+ return [];
488
+ }
489
+
490
+ // Step 1: Sort by score (severity + confidence + evidence)
491
+ const sorted = [...validFindings].sort((a, b) => scoreFinding(b) - scoreFinding(a));
492
+
493
+ // Step 2: Filter to BLOCKs only if we have them (cost control)
494
+ const hasBlocks = sorted.some(f => f.severity === "BLOCK");
495
+ const scoped = (blocksOnlyFirst && hasBlocks)
496
+ ? sorted.filter(f => f.severity === "BLOCK")
497
+ : sorted;
498
+
499
+ // Step 3: Deduplicate using fingerprints
500
+ const seenFingerprints = new Set();
501
+ const deduplicated = [];
502
+
503
+ for (const f of scoped) {
504
+ const fingerprint = generateFingerprint(f);
505
+
506
+ // Skip exact duplicates
507
+ if (seenFingerprints.has(fingerprint)) continue;
508
+ seenFingerprints.add(fingerprint);
509
+
510
+ // Also check for near-duplicates (same category + similar title)
511
+ const nearDupeKey = `${f.category}:${(f.title || '').substring(0, 50)}`;
512
+ if (f.severity === "WARN" && seenFingerprints.has(nearDupeKey)) continue;
513
+ seenFingerprints.add(nearDupeKey);
514
+
515
+ // Filter by minimum confidence if specified
516
+ const confidence = f.confidence || 0.5;
517
+ if (confidence < minConfidence) continue;
518
+
519
+ deduplicated.push(f);
520
+ }
521
+
522
+ // Step 4: Group related findings with enhanced heuristics
523
+ let missions = [];
524
+
525
+ if (groupRelated) {
526
+ // Use blast radius-aware grouping
527
+ const groups = groupWithBlastRadiusLimit(deduplicated, {
528
+ maxBlastRadius,
529
+ importGraph,
530
+ maxClusterRisk,
531
+ });
532
+
533
+ for (const [groupKey, groupFindings] of groups) {
534
+ // Take the highest severity finding as primary
535
+ const primary = groupFindings[0]; // Already sorted by score
536
+ const related = groupFindings.slice(1, 5); // Limit related findings
537
+
538
+ missions.push(missionFromFinding(primary, related, { importGraph }));
539
+ }
540
+ } else {
541
+ missions = deduplicated.map(f => missionFromFinding(f));
542
+ }
543
+
544
+ // Step 5: Sort by priority and risk
545
+ missions.sort((a, b) => {
546
+ const prioA = MISSION_PRIORITY[a.type] || 50;
547
+ const prioB = MISSION_PRIORITY[b.type] || 50;
548
+ if (prioA !== prioB) return prioA - prioB;
549
+
550
+ // Secondary sort by risk level (lower risk first for safety)
551
+ const riskOrder = { low: 0, medium: 1, high: 2, critical: 3 };
552
+ const riskA = riskOrder[a.safety?.riskLevel] ?? 1;
553
+ const riskB = riskOrder[b.safety?.riskLevel] ?? 1;
554
+ if (riskA !== riskB) return riskA - riskB;
555
+
556
+ // Tertiary sort by confidence (higher first)
557
+ return (b.safety?.confidence || 0.5) - (a.safety?.confidence || 0.5);
558
+ });
559
+
560
+ const result = missions.slice(0, maxMissions);
561
+
562
+ // Log planning results
563
+ audit.info('plan_missions_complete', {
564
+ inputFindings: findings.length,
565
+ validFindings: validFindings.length,
566
+ deduplicated: deduplicated.length,
567
+ missions: result.length,
568
+ missionTypes: result.map(m => m.type),
569
+ });
570
+
571
+ return result;
572
+ }
573
+
574
+ /**
575
+ * Plan a single mission for a specific finding
576
+ * @param {object} finding - The finding to create a mission for
577
+ * @param {object} options - Planning options
578
+ * @returns {object} Mission object
579
+ */
580
+ function planSingleMission(finding, options = {}) {
581
+ return missionFromFinding(finding, [], options);
582
+ }
583
+
584
+ /**
585
+ * Get mission statistics
586
+ * @param {Array} missions - Array of missions
587
+ * @returns {object} Statistics object
588
+ */
589
+ function getMissionStats(missions) {
590
+ const stats = {
591
+ total: missions.length,
592
+ byType: {},
593
+ byRisk: { low: 0, medium: 0, high: 0, critical: 0 },
594
+ byBlastRadius: { low: 0, medium: 0, high: 0 },
595
+ totalFindings: 0,
596
+ avgConfidence: 0,
597
+ };
598
+
599
+ let totalConfidence = 0;
600
+
601
+ for (const m of missions) {
602
+ // By type
603
+ stats.byType[m.type] = (stats.byType[m.type] || 0) + 1;
604
+
605
+ // By risk
606
+ const risk = m.safety?.riskLevel || 'medium';
607
+ stats.byRisk[risk] = (stats.byRisk[risk] || 0) + 1;
608
+
609
+ // By blast radius
610
+ const blast = m.scope?.blastRadius || 'medium';
611
+ stats.byBlastRadius[blast] = (stats.byBlastRadius[blast] || 0) + 1;
612
+
613
+ // Finding count
614
+ stats.totalFindings += m.objective?.findingCount || 1;
615
+
616
+ // Confidence
617
+ totalConfidence += m.safety?.confidence || 0.5;
618
+ }
619
+
620
+ stats.avgConfidence = missions.length > 0
621
+ ? Math.round((totalConfidence / missions.length) * 100) / 100
622
+ : 0;
623
+
624
+ return stats;
625
+ }
626
+
627
+ module.exports = {
628
+ // Main planning functions
629
+ planMissions,
630
+ planSingleMission,
631
+ getMissionStats,
632
+
633
+ // Grouping functions
634
+ groupRelatedFindings,
635
+ groupWithBlastRadiusLimit,
636
+
637
+ // Utility functions
638
+ scoreFinding,
639
+ generateFingerprint,
640
+ extractFilesFromFindings,
641
+ buildImportGraph,
642
+ findConnectedFileClusters,
643
+ calculateClusterRisk,
644
+
645
+ // Constants
646
+ CATEGORY_TO_MISSION_TYPE,
647
+ MISSION_PRIORITY,
648
+ };