circle-ir-ai 1.1.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 (420) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/LICENSE +15 -0
  3. package/README.md +336 -0
  4. package/dist/action-queue/aggregator.d.ts +40 -0
  5. package/dist/action-queue/aggregator.d.ts.map +1 -0
  6. package/dist/action-queue/aggregator.js +375 -0
  7. package/dist/action-queue/aggregator.js.map +1 -0
  8. package/dist/action-queue/index.d.ts +14 -0
  9. package/dist/action-queue/index.d.ts.map +1 -0
  10. package/dist/action-queue/index.js +17 -0
  11. package/dist/action-queue/index.js.map +1 -0
  12. package/dist/action-queue/queue.d.ts +74 -0
  13. package/dist/action-queue/queue.d.ts.map +1 -0
  14. package/dist/action-queue/queue.js +433 -0
  15. package/dist/action-queue/queue.js.map +1 -0
  16. package/dist/action-queue/types.d.ts +162 -0
  17. package/dist/action-queue/types.d.ts.map +1 -0
  18. package/dist/action-queue/types.js +44 -0
  19. package/dist/action-queue/types.js.map +1 -0
  20. package/dist/agents/enrichment-agent.d.ts +16 -0
  21. package/dist/agents/enrichment-agent.d.ts.map +1 -0
  22. package/dist/agents/enrichment-agent.js +102 -0
  23. package/dist/agents/enrichment-agent.js.map +1 -0
  24. package/dist/agents/index.d.ts +12 -0
  25. package/dist/agents/index.d.ts.map +1 -0
  26. package/dist/agents/index.js +15 -0
  27. package/dist/agents/index.js.map +1 -0
  28. package/dist/agents/mastra/agents.d.ts +373 -0
  29. package/dist/agents/mastra/agents.d.ts.map +1 -0
  30. package/dist/agents/mastra/agents.js +347 -0
  31. package/dist/agents/mastra/agents.js.map +1 -0
  32. package/dist/agents/mastra/index.d.ts +12 -0
  33. package/dist/agents/mastra/index.d.ts.map +1 -0
  34. package/dist/agents/mastra/index.js +17 -0
  35. package/dist/agents/mastra/index.js.map +1 -0
  36. package/dist/agents/mastra/instance.d.ts +383 -0
  37. package/dist/agents/mastra/instance.d.ts.map +1 -0
  38. package/dist/agents/mastra/instance.js +37 -0
  39. package/dist/agents/mastra/instance.js.map +1 -0
  40. package/dist/agents/mastra/steps.d.ts +300 -0
  41. package/dist/agents/mastra/steps.d.ts.map +1 -0
  42. package/dist/agents/mastra/steps.js +468 -0
  43. package/dist/agents/mastra/steps.js.map +1 -0
  44. package/dist/agents/mastra/swarm.d.ts +106 -0
  45. package/dist/agents/mastra/swarm.d.ts.map +1 -0
  46. package/dist/agents/mastra/swarm.js +501 -0
  47. package/dist/agents/mastra/swarm.js.map +1 -0
  48. package/dist/agents/mastra/workflow.d.ts +81 -0
  49. package/dist/agents/mastra/workflow.d.ts.map +1 -0
  50. package/dist/agents/mastra/workflow.js +460 -0
  51. package/dist/agents/mastra/workflow.js.map +1 -0
  52. package/dist/agents/multi/agents/security.d.ts +29 -0
  53. package/dist/agents/multi/agents/security.d.ts.map +1 -0
  54. package/dist/agents/multi/agents/security.js +830 -0
  55. package/dist/agents/multi/agents/security.js.map +1 -0
  56. package/dist/agents/multi/extractor.d.ts +21 -0
  57. package/dist/agents/multi/extractor.d.ts.map +1 -0
  58. package/dist/agents/multi/extractor.js +483 -0
  59. package/dist/agents/multi/extractor.js.map +1 -0
  60. package/dist/agents/multi/index.d.ts +32 -0
  61. package/dist/agents/multi/index.d.ts.map +1 -0
  62. package/dist/agents/multi/index.js +34 -0
  63. package/dist/agents/multi/index.js.map +1 -0
  64. package/dist/agents/multi/runner.d.ts +79 -0
  65. package/dist/agents/multi/runner.d.ts.map +1 -0
  66. package/dist/agents/multi/runner.js +323 -0
  67. package/dist/agents/multi/runner.js.map +1 -0
  68. package/dist/agents/security-agent.d.ts +16 -0
  69. package/dist/agents/security-agent.d.ts.map +1 -0
  70. package/dist/agents/security-agent.js +299 -0
  71. package/dist/agents/security-agent.js.map +1 -0
  72. package/dist/agents/types.d.ts +373 -0
  73. package/dist/agents/types.d.ts.map +1 -0
  74. package/dist/agents/types.js +14 -0
  75. package/dist/agents/types.js.map +1 -0
  76. package/dist/agents/verification-agent.d.ts +23 -0
  77. package/dist/agents/verification-agent.d.ts.map +1 -0
  78. package/dist/agents/verification-agent.js +217 -0
  79. package/dist/agents/verification-agent.js.map +1 -0
  80. package/dist/agents/workflow.d.ts +30 -0
  81. package/dist/agents/workflow.d.ts.map +1 -0
  82. package/dist/agents/workflow.js +79 -0
  83. package/dist/agents/workflow.js.map +1 -0
  84. package/dist/analysis/enriched.d.ts +16 -0
  85. package/dist/analysis/enriched.d.ts.map +1 -0
  86. package/dist/analysis/enriched.js +297 -0
  87. package/dist/analysis/enriched.js.map +1 -0
  88. package/dist/analysis/llm-correlated-predicates.d.ts +80 -0
  89. package/dist/analysis/llm-correlated-predicates.d.ts.map +1 -0
  90. package/dist/analysis/llm-correlated-predicates.js +255 -0
  91. package/dist/analysis/llm-correlated-predicates.js.map +1 -0
  92. package/dist/analysis/llm-cross-file-taint.d.ts +86 -0
  93. package/dist/analysis/llm-cross-file-taint.d.ts.map +1 -0
  94. package/dist/analysis/llm-cross-file-taint.js +264 -0
  95. package/dist/analysis/llm-cross-file-taint.js.map +1 -0
  96. package/dist/analysis/pattern-discovery.d.ts +79 -0
  97. package/dist/analysis/pattern-discovery.d.ts.map +1 -0
  98. package/dist/analysis/pattern-discovery.js +447 -0
  99. package/dist/analysis/pattern-discovery.js.map +1 -0
  100. package/dist/cache/file-cache.d.ts +89 -0
  101. package/dist/cache/file-cache.d.ts.map +1 -0
  102. package/dist/cache/file-cache.js +208 -0
  103. package/dist/cache/file-cache.js.map +1 -0
  104. package/dist/cache/index.d.ts +6 -0
  105. package/dist/cache/index.d.ts.map +1 -0
  106. package/dist/cache/index.js +5 -0
  107. package/dist/cache/index.js.map +1 -0
  108. package/dist/cli/args.d.ts +52 -0
  109. package/dist/cli/args.d.ts.map +1 -0
  110. package/dist/cli/args.js +422 -0
  111. package/dist/cli/args.js.map +1 -0
  112. package/dist/cli/colors.d.ts +31 -0
  113. package/dist/cli/colors.d.ts.map +1 -0
  114. package/dist/cli/colors.js +80 -0
  115. package/dist/cli/colors.js.map +1 -0
  116. package/dist/cli/commands/analyze-skill.d.ts +33 -0
  117. package/dist/cli/commands/analyze-skill.d.ts.map +1 -0
  118. package/dist/cli/commands/analyze-skill.js +217 -0
  119. package/dist/cli/commands/analyze-skill.js.map +1 -0
  120. package/dist/cli/commands/analyze.d.ts +18 -0
  121. package/dist/cli/commands/analyze.d.ts.map +1 -0
  122. package/dist/cli/commands/analyze.js +30 -0
  123. package/dist/cli/commands/analyze.js.map +1 -0
  124. package/dist/cli/commands/benchmark-runner.d.ts +42 -0
  125. package/dist/cli/commands/benchmark-runner.d.ts.map +1 -0
  126. package/dist/cli/commands/benchmark-runner.js +18 -0
  127. package/dist/cli/commands/benchmark-runner.js.map +1 -0
  128. package/dist/cli/commands/benchmark.d.ts +11 -0
  129. package/dist/cli/commands/benchmark.d.ts.map +1 -0
  130. package/dist/cli/commands/benchmark.js +90 -0
  131. package/dist/cli/commands/benchmark.js.map +1 -0
  132. package/dist/cli/commands/dead-code.d.ts +11 -0
  133. package/dist/cli/commands/dead-code.d.ts.map +1 -0
  134. package/dist/cli/commands/dead-code.js +65 -0
  135. package/dist/cli/commands/dead-code.js.map +1 -0
  136. package/dist/cli/commands/generate-spec.d.ts +11 -0
  137. package/dist/cli/commands/generate-spec.d.ts.map +1 -0
  138. package/dist/cli/commands/generate-spec.js +67 -0
  139. package/dist/cli/commands/generate-spec.js.map +1 -0
  140. package/dist/cli/commands/health.d.ts +11 -0
  141. package/dist/cli/commands/health.d.ts.map +1 -0
  142. package/dist/cli/commands/health.js +67 -0
  143. package/dist/cli/commands/health.js.map +1 -0
  144. package/dist/cli/commands/project.d.ts +21 -0
  145. package/dist/cli/commands/project.d.ts.map +1 -0
  146. package/dist/cli/commands/project.js +92 -0
  147. package/dist/cli/commands/project.js.map +1 -0
  148. package/dist/cli/commands/scan.d.ts +11 -0
  149. package/dist/cli/commands/scan.d.ts.map +1 -0
  150. package/dist/cli/commands/scan.js +68 -0
  151. package/dist/cli/commands/scan.js.map +1 -0
  152. package/dist/cli/commands/secrets.d.ts +11 -0
  153. package/dist/cli/commands/secrets.d.ts.map +1 -0
  154. package/dist/cli/commands/secrets.js +71 -0
  155. package/dist/cli/commands/secrets.js.map +1 -0
  156. package/dist/cli/commands/swarm.d.ts +20 -0
  157. package/dist/cli/commands/swarm.d.ts.map +1 -0
  158. package/dist/cli/commands/swarm.js +174 -0
  159. package/dist/cli/commands/swarm.js.map +1 -0
  160. package/dist/cli/config.d.ts +103 -0
  161. package/dist/cli/config.d.ts.map +1 -0
  162. package/dist/cli/config.js +307 -0
  163. package/dist/cli/config.js.map +1 -0
  164. package/dist/cli/discovery.d.ts +31 -0
  165. package/dist/cli/discovery.d.ts.map +1 -0
  166. package/dist/cli/discovery.js +212 -0
  167. package/dist/cli/discovery.js.map +1 -0
  168. package/dist/cli/formatters/index.d.ts +15 -0
  169. package/dist/cli/formatters/index.d.ts.map +1 -0
  170. package/dist/cli/formatters/index.js +51 -0
  171. package/dist/cli/formatters/index.js.map +1 -0
  172. package/dist/cli/formatters/json.d.ts +11 -0
  173. package/dist/cli/formatters/json.d.ts.map +1 -0
  174. package/dist/cli/formatters/json.js +12 -0
  175. package/dist/cli/formatters/json.js.map +1 -0
  176. package/dist/cli/formatters/project-json.d.ts +11 -0
  177. package/dist/cli/formatters/project-json.d.ts.map +1 -0
  178. package/dist/cli/formatters/project-json.js +12 -0
  179. package/dist/cli/formatters/project-json.js.map +1 -0
  180. package/dist/cli/formatters/project-sarif.d.ts +11 -0
  181. package/dist/cli/formatters/project-sarif.d.ts.map +1 -0
  182. package/dist/cli/formatters/project-sarif.js +127 -0
  183. package/dist/cli/formatters/project-sarif.js.map +1 -0
  184. package/dist/cli/formatters/project-summary.d.ts +11 -0
  185. package/dist/cli/formatters/project-summary.d.ts.map +1 -0
  186. package/dist/cli/formatters/project-summary.js +202 -0
  187. package/dist/cli/formatters/project-summary.js.map +1 -0
  188. package/dist/cli/formatters/sarif-shared.d.ts +101 -0
  189. package/dist/cli/formatters/sarif-shared.d.ts.map +1 -0
  190. package/dist/cli/formatters/sarif-shared.js +57 -0
  191. package/dist/cli/formatters/sarif-shared.js.map +1 -0
  192. package/dist/cli/formatters/sarif.d.ts +12 -0
  193. package/dist/cli/formatters/sarif.d.ts.map +1 -0
  194. package/dist/cli/formatters/sarif.js +92 -0
  195. package/dist/cli/formatters/sarif.js.map +1 -0
  196. package/dist/cli/formatters/summary.d.ts +11 -0
  197. package/dist/cli/formatters/summary.d.ts.map +1 -0
  198. package/dist/cli/formatters/summary.js +240 -0
  199. package/dist/cli/formatters/summary.js.map +1 -0
  200. package/dist/cli/formatters/two-phase-summary.d.ts +11 -0
  201. package/dist/cli/formatters/two-phase-summary.d.ts.map +1 -0
  202. package/dist/cli/formatters/two-phase-summary.js +188 -0
  203. package/dist/cli/formatters/two-phase-summary.js.map +1 -0
  204. package/dist/cli/index.d.ts +15 -0
  205. package/dist/cli/index.d.ts.map +1 -0
  206. package/dist/cli/index.js +555 -0
  207. package/dist/cli/index.js.map +1 -0
  208. package/dist/components/clustering.d.ts +60 -0
  209. package/dist/components/clustering.d.ts.map +1 -0
  210. package/dist/components/clustering.js +129 -0
  211. package/dist/components/clustering.js.map +1 -0
  212. package/dist/components/enrichment.d.ts +45 -0
  213. package/dist/components/enrichment.d.ts.map +1 -0
  214. package/dist/components/enrichment.js +193 -0
  215. package/dist/components/enrichment.js.map +1 -0
  216. package/dist/components/index.d.ts +29 -0
  217. package/dist/components/index.d.ts.map +1 -0
  218. package/dist/components/index.js +56 -0
  219. package/dist/components/index.js.map +1 -0
  220. package/dist/dead-code/detector.d.ts +200 -0
  221. package/dist/dead-code/detector.d.ts.map +1 -0
  222. package/dist/dead-code/detector.js +1003 -0
  223. package/dist/dead-code/detector.js.map +1 -0
  224. package/dist/dead-code/index.d.ts +7 -0
  225. package/dist/dead-code/index.d.ts.map +1 -0
  226. package/dist/dead-code/index.js +7 -0
  227. package/dist/dead-code/index.js.map +1 -0
  228. package/dist/extractors/index.d.ts +15 -0
  229. package/dist/extractors/index.d.ts.map +1 -0
  230. package/dist/extractors/index.js +14 -0
  231. package/dist/extractors/index.js.map +1 -0
  232. package/dist/extractors/natural-language.d.ts +46 -0
  233. package/dist/extractors/natural-language.d.ts.map +1 -0
  234. package/dist/extractors/natural-language.js +228 -0
  235. package/dist/extractors/natural-language.js.map +1 -0
  236. package/dist/extractors/tree-sitter.d.ts +33 -0
  237. package/dist/extractors/tree-sitter.d.ts.map +1 -0
  238. package/dist/extractors/tree-sitter.js +69 -0
  239. package/dist/extractors/tree-sitter.js.map +1 -0
  240. package/dist/extractors/types.d.ts +62 -0
  241. package/dist/extractors/types.d.ts.map +1 -0
  242. package/dist/extractors/types.js +54 -0
  243. package/dist/extractors/types.js.map +1 -0
  244. package/dist/health-score/calculator.d.ts +123 -0
  245. package/dist/health-score/calculator.d.ts.map +1 -0
  246. package/dist/health-score/calculator.js +444 -0
  247. package/dist/health-score/calculator.js.map +1 -0
  248. package/dist/health-score/index.d.ts +12 -0
  249. package/dist/health-score/index.d.ts.map +1 -0
  250. package/dist/health-score/index.js +14 -0
  251. package/dist/health-score/index.js.map +1 -0
  252. package/dist/health-score/metrics.d.ts +142 -0
  253. package/dist/health-score/metrics.d.ts.map +1 -0
  254. package/dist/health-score/metrics.js +332 -0
  255. package/dist/health-score/metrics.js.map +1 -0
  256. package/dist/index.d.ts +26 -0
  257. package/dist/index.d.ts.map +1 -0
  258. package/dist/index.js +43 -0
  259. package/dist/index.js.map +1 -0
  260. package/dist/llm/ax-client.d.ts +477 -0
  261. package/dist/llm/ax-client.d.ts.map +1 -0
  262. package/dist/llm/ax-client.js +1641 -0
  263. package/dist/llm/ax-client.js.map +1 -0
  264. package/dist/llm/config.d.ts +58 -0
  265. package/dist/llm/config.d.ts.map +1 -0
  266. package/dist/llm/config.js +97 -0
  267. package/dist/llm/config.js.map +1 -0
  268. package/dist/llm/discovery.d.ts +123 -0
  269. package/dist/llm/discovery.d.ts.map +1 -0
  270. package/dist/llm/discovery.js +505 -0
  271. package/dist/llm/discovery.js.map +1 -0
  272. package/dist/llm/enrichment.d.ts +108 -0
  273. package/dist/llm/enrichment.d.ts.map +1 -0
  274. package/dist/llm/enrichment.js +312 -0
  275. package/dist/llm/enrichment.js.map +1 -0
  276. package/dist/llm/index.d.ts +13 -0
  277. package/dist/llm/index.d.ts.map +1 -0
  278. package/dist/llm/index.js +22 -0
  279. package/dist/llm/index.js.map +1 -0
  280. package/dist/llm/language-context.d.ts +64 -0
  281. package/dist/llm/language-context.d.ts.map +1 -0
  282. package/dist/llm/language-context.js +492 -0
  283. package/dist/llm/language-context.js.map +1 -0
  284. package/dist/llm/pattern-verification.d.ts +39 -0
  285. package/dist/llm/pattern-verification.d.ts.map +1 -0
  286. package/dist/llm/pattern-verification.js +127 -0
  287. package/dist/llm/pattern-verification.js.map +1 -0
  288. package/dist/llm/prompt-security.d.ts +120 -0
  289. package/dist/llm/prompt-security.d.ts.map +1 -0
  290. package/dist/llm/prompt-security.js +301 -0
  291. package/dist/llm/prompt-security.js.map +1 -0
  292. package/dist/llm/prompts/index.d.ts +31 -0
  293. package/dist/llm/prompts/index.d.ts.map +1 -0
  294. package/dist/llm/prompts/index.js +92 -0
  295. package/dist/llm/prompts/index.js.map +1 -0
  296. package/dist/llm/prompts/rust.d.ts +30 -0
  297. package/dist/llm/prompts/rust.d.ts.map +1 -0
  298. package/dist/llm/prompts/rust.js +121 -0
  299. package/dist/llm/prompts/rust.js.map +1 -0
  300. package/dist/llm/schemas.d.ts +892 -0
  301. package/dist/llm/schemas.d.ts.map +1 -0
  302. package/dist/llm/schemas.js +258 -0
  303. package/dist/llm/schemas.js.map +1 -0
  304. package/dist/llm/verification.d.ts +127 -0
  305. package/dist/llm/verification.d.ts.map +1 -0
  306. package/dist/llm/verification.js +394 -0
  307. package/dist/llm/verification.js.map +1 -0
  308. package/dist/project/analyzer.d.ts +30 -0
  309. package/dist/project/analyzer.d.ts.map +1 -0
  310. package/dist/project/analyzer.js +358 -0
  311. package/dist/project/analyzer.js.map +1 -0
  312. package/dist/project/call-graph.d.ts +22 -0
  313. package/dist/project/call-graph.d.ts.map +1 -0
  314. package/dist/project/call-graph.js +246 -0
  315. package/dist/project/call-graph.js.map +1 -0
  316. package/dist/project/index.d.ts +18 -0
  317. package/dist/project/index.d.ts.map +1 -0
  318. package/dist/project/index.js +20 -0
  319. package/dist/project/index.js.map +1 -0
  320. package/dist/project/taint-paths.d.ts +22 -0
  321. package/dist/project/taint-paths.d.ts.map +1 -0
  322. package/dist/project/taint-paths.js +265 -0
  323. package/dist/project/taint-paths.js.map +1 -0
  324. package/dist/project/two-phase-analyzer.d.ts +143 -0
  325. package/dist/project/two-phase-analyzer.d.ts.map +1 -0
  326. package/dist/project/two-phase-analyzer.js +646 -0
  327. package/dist/project/two-phase-analyzer.js.map +1 -0
  328. package/dist/project/type-hierarchy.d.ts +28 -0
  329. package/dist/project/type-hierarchy.d.ts.map +1 -0
  330. package/dist/project/type-hierarchy.js +218 -0
  331. package/dist/project/type-hierarchy.js.map +1 -0
  332. package/dist/secret-scan/index.d.ts +12 -0
  333. package/dist/secret-scan/index.d.ts.map +1 -0
  334. package/dist/secret-scan/index.js +14 -0
  335. package/dist/secret-scan/index.js.map +1 -0
  336. package/dist/secret-scan/patterns.d.ts +38 -0
  337. package/dist/secret-scan/patterns.d.ts.map +1 -0
  338. package/dist/secret-scan/patterns.js +473 -0
  339. package/dist/secret-scan/patterns.js.map +1 -0
  340. package/dist/secret-scan/scanner.d.ts +162 -0
  341. package/dist/secret-scan/scanner.d.ts.map +1 -0
  342. package/dist/secret-scan/scanner.js +511 -0
  343. package/dist/secret-scan/scanner.js.map +1 -0
  344. package/dist/security-scan/index.d.ts +12 -0
  345. package/dist/security-scan/index.d.ts.map +1 -0
  346. package/dist/security-scan/index.js +15 -0
  347. package/dist/security-scan/index.js.map +1 -0
  348. package/dist/security-scan/owasp-mapping.d.ts +29 -0
  349. package/dist/security-scan/owasp-mapping.d.ts.map +1 -0
  350. package/dist/security-scan/owasp-mapping.js +246 -0
  351. package/dist/security-scan/owasp-mapping.js.map +1 -0
  352. package/dist/security-scan/scanner.d.ts +204 -0
  353. package/dist/security-scan/scanner.d.ts.map +1 -0
  354. package/dist/security-scan/scanner.js +693 -0
  355. package/dist/security-scan/scanner.js.map +1 -0
  356. package/dist/security-scan/trend-tracker.d.ts +150 -0
  357. package/dist/security-scan/trend-tracker.d.ts.map +1 -0
  358. package/dist/security-scan/trend-tracker.js +299 -0
  359. package/dist/security-scan/trend-tracker.js.map +1 -0
  360. package/dist/skills/bundle-loader.d.ts +26 -0
  361. package/dist/skills/bundle-loader.d.ts.map +1 -0
  362. package/dist/skills/bundle-loader.js +284 -0
  363. package/dist/skills/bundle-loader.js.map +1 -0
  364. package/dist/skills/capability-mismatch.d.ts +21 -0
  365. package/dist/skills/capability-mismatch.d.ts.map +1 -0
  366. package/dist/skills/capability-mismatch.js +188 -0
  367. package/dist/skills/capability-mismatch.js.map +1 -0
  368. package/dist/skills/index.d.ts +10 -0
  369. package/dist/skills/index.d.ts.map +1 -0
  370. package/dist/skills/index.js +9 -0
  371. package/dist/skills/index.js.map +1 -0
  372. package/dist/skills/skill-analyzer.d.ts +16 -0
  373. package/dist/skills/skill-analyzer.d.ts.map +1 -0
  374. package/dist/skills/skill-analyzer.js +361 -0
  375. package/dist/skills/skill-analyzer.js.map +1 -0
  376. package/dist/skills/types.d.ts +195 -0
  377. package/dist/skills/types.d.ts.map +1 -0
  378. package/dist/skills/types.js +7 -0
  379. package/dist/skills/types.js.map +1 -0
  380. package/dist/specifica/conflict-resolver.d.ts +23 -0
  381. package/dist/specifica/conflict-resolver.d.ts.map +1 -0
  382. package/dist/specifica/conflict-resolver.js +129 -0
  383. package/dist/specifica/conflict-resolver.js.map +1 -0
  384. package/dist/specifica/evidence-aggregator.d.ts +33 -0
  385. package/dist/specifica/evidence-aggregator.d.ts.map +1 -0
  386. package/dist/specifica/evidence-aggregator.js +236 -0
  387. package/dist/specifica/evidence-aggregator.js.map +1 -0
  388. package/dist/specifica/evidence-extractor.d.ts +13 -0
  389. package/dist/specifica/evidence-extractor.d.ts.map +1 -0
  390. package/dist/specifica/evidence-extractor.js +431 -0
  391. package/dist/specifica/evidence-extractor.js.map +1 -0
  392. package/dist/specifica/feature-clustering.d.ts +19 -0
  393. package/dist/specifica/feature-clustering.d.ts.map +1 -0
  394. package/dist/specifica/feature-clustering.js +231 -0
  395. package/dist/specifica/feature-clustering.js.map +1 -0
  396. package/dist/specifica/generator.d.ts +16 -0
  397. package/dist/specifica/generator.d.ts.map +1 -0
  398. package/dist/specifica/generator.js +277 -0
  399. package/dist/specifica/generator.js.map +1 -0
  400. package/dist/specifica/index.d.ts +15 -0
  401. package/dist/specifica/index.d.ts.map +1 -0
  402. package/dist/specifica/index.js +18 -0
  403. package/dist/specifica/index.js.map +1 -0
  404. package/dist/specifica/prompts.d.ts +21 -0
  405. package/dist/specifica/prompts.d.ts.map +1 -0
  406. package/dist/specifica/prompts.js +196 -0
  407. package/dist/specifica/prompts.js.map +1 -0
  408. package/dist/specifica/spec-generator.d.ts +22 -0
  409. package/dist/specifica/spec-generator.d.ts.map +1 -0
  410. package/dist/specifica/spec-generator.js +229 -0
  411. package/dist/specifica/spec-generator.js.map +1 -0
  412. package/dist/specifica/types.d.ts +213 -0
  413. package/dist/specifica/types.d.ts.map +1 -0
  414. package/dist/specifica/types.js +7 -0
  415. package/dist/specifica/types.js.map +1 -0
  416. package/dist/utils/logger.d.ts +17 -0
  417. package/dist/utils/logger.d.ts.map +1 -0
  418. package/dist/utils/logger.js +51 -0
  419. package/dist/utils/logger.js.map +1 -0
  420. package/package.json +99 -0
@@ -0,0 +1,646 @@
1
+ /**
2
+ * Two-Phase Project Analyzer
3
+ *
4
+ * Phase 1: Per-file analysis (parallelizable)
5
+ * - Static analysis (circle-ir)
6
+ * - LLM enrichment (sources, sinks, roles)
7
+ * - CFG/DFG extraction
8
+ *
9
+ * Phase 2: Cross-file LLM analysis
10
+ * - Sees ALL enriched IRs
11
+ * - Cross-file taint path detection
12
+ * - Virtual dispatch resolution across files
13
+ * - Final vulnerability verification
14
+ */
15
+ import { analyze, initAnalyzer, isAnalyzerInitialized, createWithJdkTypes, SymbolTable, CrossFileResolver, } from 'circle-ir';
16
+ import { buildTypeHierarchy } from './type-hierarchy.js';
17
+ import { buildCrossFileCalls } from './call-graph.js';
18
+ import { findTaintPaths } from './taint-paths.js';
19
+ import { runSecurityAnalysis } from '../agents/security-agent.js';
20
+ import { getAxLLMClient } from '../llm/ax-client.js';
21
+ // ============================================================================
22
+ // Phase 1: Per-File Analysis
23
+ // ============================================================================
24
+ async function analyzeFilePhase1(file, options) {
25
+ const startTime = Date.now();
26
+ // Detect language
27
+ const language = detectLanguage(file.path);
28
+ // Static analysis with circle-ir
29
+ const staticAnalysis = await analyze(file.content, file.path, language);
30
+ // Prepare result
31
+ const result = {
32
+ file: file.path,
33
+ staticAnalysis,
34
+ allSources: [...staticAnalysis.taint.sources],
35
+ allSinks: [...staticAnalysis.taint.sinks],
36
+ intraFileFlows: [],
37
+ analysisTimeMs: 0,
38
+ };
39
+ // LLM enrichment (if enabled)
40
+ if (options.enableEnrichment !== false) {
41
+ const enrichmentStart = Date.now();
42
+ // Reset circuit breaker per file so one file's LLM failures
43
+ // don't disable LLM for the rest of the project
44
+ try {
45
+ getAxLLMClient().resetCircuitBreaker();
46
+ }
47
+ catch { /* client not initialized */ }
48
+ try {
49
+ const securityOutput = await runSecurityAnalysis({
50
+ filePath: file.path,
51
+ sourceCode: file.content,
52
+ language,
53
+ options: {
54
+ enableEnrichment: true,
55
+ enableVerification: false, // Phase 2 handles verification
56
+ confidenceThreshold: options.enrichmentConfidence ?? 0.7,
57
+ },
58
+ }, staticAnalysis.taint.sources, staticAnalysis.taint.sinks, staticAnalysis.types, staticAnalysis.imports.map(i => i.from_package || ''));
59
+ // Extract enrichment results
60
+ result.enrichment = {
61
+ role: securityOutput.context.enrichmentResult?.role,
62
+ additionalSources: securityOutput.context.enrichmentResult?.additionalSources ?? [],
63
+ additionalSinks: securityOutput.context.enrichmentResult?.additionalSinks ?? [],
64
+ framework: securityOutput.context.enrichmentResult?.framework,
65
+ };
66
+ // Merge enriched sources/sinks
67
+ const minConfidence = options.enrichmentConfidence ?? 0.7;
68
+ for (const src of result.enrichment.additionalSources) {
69
+ if (src.confidence >= minConfidence) {
70
+ result.allSources.push({
71
+ line: src.line,
72
+ location: `${src.variable} in ${file.path}`,
73
+ type: src.type,
74
+ severity: 'medium', // Default severity for LLM-discovered sources
75
+ confidence: src.confidence,
76
+ });
77
+ }
78
+ }
79
+ for (const sink of result.enrichment.additionalSinks) {
80
+ if (sink.confidence >= minConfidence) {
81
+ result.allSinks.push({
82
+ line: sink.line,
83
+ location: `${sink.method} in ${file.path}`,
84
+ type: sink.type,
85
+ cwe: sink.cwe,
86
+ confidence: sink.confidence,
87
+ });
88
+ }
89
+ }
90
+ result.enrichmentTimeMs = Date.now() - enrichmentStart;
91
+ }
92
+ catch (error) {
93
+ console.warn(`[Phase1] Enrichment failed for ${file.path}:`, error);
94
+ }
95
+ }
96
+ // Extract intra-file flows from static analysis
97
+ if (staticAnalysis.taint.flows) {
98
+ for (const flow of staticAnalysis.taint.flows) {
99
+ const sourceIndex = result.allSources.findIndex(s => s.line === flow.source_line);
100
+ const sinkIndex = result.allSinks.findIndex(s => s.line === flow.sink_line);
101
+ if (sourceIndex >= 0 && sinkIndex >= 0) {
102
+ result.intraFileFlows.push({
103
+ sourceIndex,
104
+ sinkIndex,
105
+ confidence: flow.confidence,
106
+ sanitized: flow.sanitized,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ result.analysisTimeMs = Date.now() - startTime;
112
+ return result;
113
+ }
114
+ /**
115
+ * Run Phase 1 on all files (with optional parallelization)
116
+ */
117
+ async function runPhase1(files, options) {
118
+ const results = [];
119
+ if (options.parallelPhase1 !== false) {
120
+ // Parallel execution
121
+ const maxConcurrency = options.maxConcurrency ?? 10;
122
+ const queue = [...files];
123
+ let index = 0;
124
+ const workers = [];
125
+ for (let i = 0; i < Math.min(maxConcurrency, files.length); i++) {
126
+ workers.push((async () => {
127
+ while (queue.length > 0) {
128
+ const file = queue.shift();
129
+ if (!file)
130
+ break;
131
+ const currentIndex = index++;
132
+ options.onFileStart?.(file.path, currentIndex, files.length);
133
+ const result = await analyzeFilePhase1(file, options);
134
+ results[currentIndex] = result;
135
+ options.onFileComplete?.(file.path, currentIndex, files.length);
136
+ }
137
+ })());
138
+ }
139
+ await Promise.all(workers);
140
+ }
141
+ else {
142
+ // Sequential execution
143
+ for (let i = 0; i < files.length; i++) {
144
+ const file = files[i];
145
+ options.onFileStart?.(file.path, i, files.length);
146
+ const result = await analyzeFilePhase1(file, options);
147
+ results.push(result);
148
+ options.onFileComplete?.(file.path, i, files.length);
149
+ }
150
+ }
151
+ return results;
152
+ }
153
+ // ============================================================================
154
+ // Aggregation: Build Project Context
155
+ // ============================================================================
156
+ function buildProjectContext(files, typeHierarchy, crossFileCalls) {
157
+ // Collect all sources and sinks with file info
158
+ const allSources = [];
159
+ const allSinks = [];
160
+ let totalLoc = 0;
161
+ for (const fileAnalysis of files) {
162
+ totalLoc += fileAnalysis.staticAnalysis.meta.loc;
163
+ for (const source of fileAnalysis.allSources) {
164
+ allSources.push({ ...source, file: fileAnalysis.file });
165
+ }
166
+ for (const sink of fileAnalysis.allSinks) {
167
+ allSinks.push({ ...sink, file: fileAnalysis.file });
168
+ }
169
+ }
170
+ // Find candidate cross-file paths
171
+ const candidatePaths = [];
172
+ // Look for sources in one file that could reach sinks in another file
173
+ // via the cross-file call graph
174
+ for (const source of allSources) {
175
+ for (const sink of allSinks) {
176
+ if (source.file === sink.file)
177
+ continue; // Intra-file handled separately
178
+ // Check if there's a call path from source file to sink file
179
+ const pathExists = crossFileCalls.some(call => call.from.file === source.file && call.to.file === sink.file);
180
+ if (pathExists) {
181
+ candidatePaths.push({
182
+ id: `candidate-${source.file}:${source.line}-${sink.file}:${sink.line}`,
183
+ source: {
184
+ file: source.file,
185
+ line: source.line,
186
+ type: source.type,
187
+ code: source.location,
188
+ },
189
+ sink: {
190
+ file: sink.file,
191
+ line: sink.line,
192
+ type: sink.type,
193
+ cwe: sink.cwe || 'CWE-unknown',
194
+ code: sink.location,
195
+ },
196
+ hops: [],
197
+ path_exists: true,
198
+ sanitizers_in_path: [],
199
+ confidence: 0.5, // Will be updated by Phase 2
200
+ });
201
+ }
202
+ }
203
+ }
204
+ // Detect framework from enrichment results
205
+ let framework;
206
+ for (const fileAnalysis of files) {
207
+ const confidence = fileAnalysis.enrichment?.framework?.confidence;
208
+ if (confidence !== undefined && confidence > 0.8) {
209
+ framework = fileAnalysis.enrichment?.framework?.name;
210
+ break;
211
+ }
212
+ }
213
+ return {
214
+ files,
215
+ typeHierarchy,
216
+ crossFileCalls,
217
+ allSources,
218
+ allSinks,
219
+ candidatePaths,
220
+ meta: {
221
+ totalFiles: files.length,
222
+ totalLoc,
223
+ totalSources: allSources.length,
224
+ totalSinks: allSinks.length,
225
+ framework,
226
+ },
227
+ };
228
+ }
229
+ // ============================================================================
230
+ // Phase 2: Cross-File LLM Analysis
231
+ // ============================================================================
232
+ /**
233
+ * Extract keywords from a symbol description for fuzzy matching.
234
+ * E.g., "request.getParameter(\"id\") in getUser" -> ["getParameter", "getUser", "id"]
235
+ */
236
+ function extractKeywords(symbol) {
237
+ const keywords = [];
238
+ // Extract method names (e.g., getParameter, findById)
239
+ const methodMatches = symbol.match(/\b[a-z][a-zA-Z0-9]*\(/g);
240
+ if (methodMatches) {
241
+ keywords.push(...methodMatches.map(m => m.slice(0, -1))); // Remove trailing (
242
+ }
243
+ // Extract identifiers after "in" (e.g., "in getUser" -> "getUser")
244
+ const inMatch = symbol.match(/\bin\s+(\w+)/);
245
+ if (inMatch) {
246
+ keywords.push(inMatch[1]);
247
+ }
248
+ // Extract identifiers that look like variable/param names
249
+ const identifiers = symbol.match(/\b[a-z][a-zA-Z0-9]*\b/g);
250
+ if (identifiers) {
251
+ // Filter out common words
252
+ const commonWords = ['in', 'the', 'to', 'from', 'with', 'for', 'and', 'or', 'of'];
253
+ keywords.push(...identifiers.filter(id => !commonWords.includes(id) && id.length > 2));
254
+ }
255
+ // Remove duplicates and return
256
+ return [...new Set(keywords)];
257
+ }
258
+ async function runPhase2(context, files, options) {
259
+ if (options.enablePhase2 === false) {
260
+ return [];
261
+ }
262
+ if (context.candidatePaths.length === 0) {
263
+ return [];
264
+ }
265
+ const crossFileFlows = [];
266
+ try {
267
+ const client = getAxLLMClient();
268
+ // Group candidate paths by source-target file pairs
269
+ const filePairs = new Map();
270
+ for (const path of context.candidatePaths) {
271
+ const key = `${path.source.file}::${path.sink.file}`;
272
+ if (!filePairs.has(key)) {
273
+ filePairs.set(key, []);
274
+ }
275
+ filePairs.get(key).push(path);
276
+ }
277
+ // Call LLM for each file pair
278
+ for (const [pairKey, paths] of filePairs) {
279
+ const [sourceFilePath, targetFilePath] = pairKey.split('::');
280
+ const sourceFile = files.find(f => f.path === sourceFilePath);
281
+ const targetFile = files.find(f => f.path === targetFilePath);
282
+ if (!sourceFile || !targetFile)
283
+ continue;
284
+ // Extract exported taint from source file
285
+ const sourceAnalysis = context.files.find(f => f.file === sourceFilePath);
286
+ const exportedTaint = sourceAnalysis?.allSources.map(s => ({
287
+ symbol: s.location,
288
+ type: s.type,
289
+ line: s.line,
290
+ })) || [];
291
+ // Extract imported symbols in target file
292
+ const targetAnalysis = context.files.find(f => f.file === targetFilePath);
293
+ const importedSymbols = targetAnalysis?.staticAnalysis.imports
294
+ .map(i => i.imported_name) || [];
295
+ // Build code context around candidate source/sink locations for this file pair
296
+ const sourceLines = sourceFile.content.split('\n');
297
+ const targetLines = targetFile.content.split('\n');
298
+ const candidateContext = paths.slice(0, 10).map(p => {
299
+ const srcCtx = sourceLines.slice(Math.max(0, p.source.line - 5), p.source.line + 5).join('\n');
300
+ const sinkCtx = targetLines.slice(Math.max(0, p.sink.line - 5), p.sink.line + 5).join('\n');
301
+ return `Path: ${p.source.type}@${p.source.file}:${p.source.line} -> ${p.sink.type}@${p.sink.file}:${p.sink.line}\nSource context:\n${srcCtx}\nSink context:\n${sinkCtx}`;
302
+ }).join('\n---\n');
303
+ try {
304
+ const response = await client.analyzeCrossFileTaint({
305
+ sourceFile: sourceFilePath,
306
+ sourceCode: sourceFile.content,
307
+ targetFile: targetFilePath,
308
+ targetCode: targetFile.content,
309
+ exportedTaint,
310
+ importedSymbols,
311
+ candidateContext,
312
+ });
313
+ // Process LLM response into CrossFileTaintFlow objects
314
+ for (const flow of response.taintFlows) {
315
+ // Find matching candidate paths with fuzzy matching
316
+ // Extract key parts from symbols (method names, variable names)
317
+ const sourceKeywords = extractKeywords(flow.sourceSymbol);
318
+ const targetKeywords = extractKeywords(flow.targetSymbol);
319
+ const candidatePath = paths.find(p => {
320
+ const sourceMatches = sourceKeywords.some(kw => p.source.code.toLowerCase().includes(kw.toLowerCase()));
321
+ const sinkMatches = targetKeywords.some(kw => p.sink.code.toLowerCase().includes(kw.toLowerCase()));
322
+ // Match if source keywords match source OR target keywords match sink
323
+ return sourceMatches || sinkMatches;
324
+ });
325
+ if (candidatePath) {
326
+ crossFileFlows.push({
327
+ id: candidatePath.id,
328
+ source: {
329
+ file: candidatePath.source.file,
330
+ line: candidatePath.source.line,
331
+ type: candidatePath.source.type,
332
+ code: candidatePath.source.code,
333
+ },
334
+ sink: {
335
+ file: candidatePath.sink.file,
336
+ line: candidatePath.sink.line,
337
+ type: candidatePath.sink.type,
338
+ cwe: candidatePath.sink.cwe,
339
+ code: candidatePath.sink.code,
340
+ },
341
+ path: [{
342
+ file: targetFilePath,
343
+ line: 0,
344
+ variable: flow.targetSymbol,
345
+ operation: flow.flowType,
346
+ }],
347
+ verified: flow.confidence > (options.crossFileConfidence ?? 0.8),
348
+ confidence: flow.confidence,
349
+ exploitability: flow.confidence > 0.8 ? 'high' : flow.confidence > 0.5 ? 'medium' : 'low',
350
+ reasoning: response.reasoning || 'Cross-file taint flow detected',
351
+ });
352
+ }
353
+ }
354
+ }
355
+ catch (pairError) {
356
+ console.warn(`[Phase2] Analysis failed for ${pairKey}:`, pairError);
357
+ }
358
+ }
359
+ }
360
+ catch (error) {
361
+ console.warn('[Phase2] Cross-file analysis failed:', error);
362
+ }
363
+ return crossFileFlows;
364
+ }
365
+ // ============================================================================
366
+ // Main Entry Point
367
+ // ============================================================================
368
+ /**
369
+ * Analyze a project using two-phase LLM-enhanced analysis.
370
+ *
371
+ * Phase 1: Per-file static analysis + LLM enrichment (parallelizable)
372
+ * Phase 2: Cross-file LLM analysis with full project context
373
+ */
374
+ export async function analyzeProjectTwoPhase(files, options = {}) {
375
+ const totalStartTime = Date.now();
376
+ // Ensure analyzer is initialized
377
+ if (!isAnalyzerInitialized()) {
378
+ await initAnalyzer();
379
+ }
380
+ // =========================================================================
381
+ // PHASE 1: Per-File Analysis
382
+ // =========================================================================
383
+ const phase1Start = Date.now();
384
+ const enrichedFiles = await runPhase1(files, options);
385
+ const phase1Time = Date.now() - phase1Start;
386
+ options.onPhase1Complete?.(enrichedFiles);
387
+ // Convert to FileAnalysis for compatibility
388
+ const fileAnalyses = enrichedFiles.map(ef => ({
389
+ file: ef.file,
390
+ analysis: ef.staticAnalysis,
391
+ }));
392
+ // =========================================================================
393
+ // AGGREGATION: Build Project Context
394
+ // =========================================================================
395
+ // Initialize cross-file resolution infrastructure
396
+ const typeResolver = createWithJdkTypes();
397
+ const symbolTable = new SymbolTable();
398
+ const crossFileResolver = new CrossFileResolver(symbolTable, typeResolver);
399
+ // Register files with resolver
400
+ for (const ef of enrichedFiles) {
401
+ crossFileResolver.addFile(ef.file, ef.staticAnalysis);
402
+ }
403
+ // Build type hierarchy
404
+ const typeHierarchy = buildTypeHierarchy(fileAnalyses);
405
+ // Merge type hierarchy from resolver
406
+ for (const type of typeResolver.getAllTypes()) {
407
+ if (type.kind === 'class' || type.kind === 'enum') {
408
+ if (!typeHierarchy.classes[type.fqn]) {
409
+ typeHierarchy.classes[type.fqn] = {
410
+ file: type.file,
411
+ extends: type.extends || null,
412
+ implements: type.implements,
413
+ subclasses: typeResolver.getDirectSubtypes(type.fqn),
414
+ };
415
+ }
416
+ }
417
+ else if (type.kind === 'interface') {
418
+ if (!typeHierarchy.interfaces[type.fqn]) {
419
+ typeHierarchy.interfaces[type.fqn] = {
420
+ file: type.file,
421
+ extends: type.extendsInterfaces,
422
+ implementations: typeResolver.getDirectImplementations(type.fqn),
423
+ };
424
+ }
425
+ }
426
+ }
427
+ // Build cross-file call graph
428
+ const crossFileCalls = buildCrossFileCalls(fileAnalyses, typeHierarchy);
429
+ // Build project context for Phase 2
430
+ const projectContext = buildProjectContext(enrichedFiles, typeHierarchy, crossFileCalls);
431
+ // =========================================================================
432
+ // PHASE 2: Cross-File LLM Analysis
433
+ // =========================================================================
434
+ options.onPhase2Start?.();
435
+ const phase2Start = Date.now();
436
+ const crossFileFlows = await runPhase2(projectContext, files, options);
437
+ const phase2Time = Date.now() - phase2Start;
438
+ // =========================================================================
439
+ // Generate Final Results
440
+ // =========================================================================
441
+ // Find intra-file taint paths
442
+ let taintPaths = findTaintPaths(fileAnalyses, crossFileCalls);
443
+ // Add verified cross-file flows to taint paths
444
+ for (const flow of crossFileFlows) {
445
+ if (flow.verified) {
446
+ taintPaths.push({
447
+ id: flow.id,
448
+ source: {
449
+ file: flow.source.file,
450
+ line: flow.source.line,
451
+ type: flow.source.type,
452
+ code: flow.source.code,
453
+ },
454
+ sink: {
455
+ file: flow.sink.file,
456
+ line: flow.sink.line,
457
+ type: flow.sink.type,
458
+ cwe: flow.sink.cwe,
459
+ code: flow.sink.code,
460
+ },
461
+ hops: flow.path.map(p => ({
462
+ file: p.file,
463
+ method: 'cross-file',
464
+ line: p.line,
465
+ code: p.operation,
466
+ variable: p.variable,
467
+ })),
468
+ path_exists: true,
469
+ sanitizers_in_path: [],
470
+ confidence: flow.confidence,
471
+ });
472
+ }
473
+ }
474
+ // Aggregate findings
475
+ const findings = aggregateFindings(fileAnalyses, taintPaths, crossFileFlows);
476
+ // Build project metadata
477
+ const meta = {
478
+ name: options.name ?? extractProjectName(files),
479
+ root: options.root ?? extractRoot(files),
480
+ language: options.language ?? detectPrimaryLanguage(files),
481
+ framework: options.framework ?? projectContext.meta.framework,
482
+ framework_version: options.frameworkVersion,
483
+ total_files: files.length,
484
+ total_loc: projectContext.meta.totalLoc,
485
+ analyzed_at: new Date().toISOString(),
486
+ };
487
+ const totalTime = Date.now() - totalStartTime;
488
+ return {
489
+ meta,
490
+ files: fileAnalyses,
491
+ type_hierarchy: typeHierarchy,
492
+ cross_file_calls: crossFileCalls,
493
+ taint_paths: taintPaths,
494
+ findings,
495
+ // Two-phase specific additions
496
+ enrichedFiles,
497
+ crossFileFlows,
498
+ timing: {
499
+ phase1TotalMs: phase1Time,
500
+ phase2TotalMs: phase2Time,
501
+ totalMs: totalTime,
502
+ },
503
+ };
504
+ }
505
+ // ============================================================================
506
+ // Helper Functions
507
+ // ============================================================================
508
+ function detectLanguage(filePath) {
509
+ if (filePath.endsWith('.java'))
510
+ return 'java';
511
+ if (filePath.endsWith('.c') || filePath.endsWith('.h'))
512
+ return 'c';
513
+ if (filePath.endsWith('.cpp') || filePath.endsWith('.cc') ||
514
+ filePath.endsWith('.cxx') || filePath.endsWith('.hpp'))
515
+ return 'cpp';
516
+ if (filePath.endsWith('.js') || filePath.endsWith('.jsx') ||
517
+ filePath.endsWith('.mjs') || filePath.endsWith('.cjs'))
518
+ return 'javascript';
519
+ if (filePath.endsWith('.ts') || filePath.endsWith('.tsx') ||
520
+ filePath.endsWith('.mts') || filePath.endsWith('.cts'))
521
+ return 'typescript';
522
+ if (filePath.endsWith('.py'))
523
+ return 'python';
524
+ return 'java';
525
+ }
526
+ function detectPrimaryLanguage(files) {
527
+ const counts = { java: 0, c: 0, cpp: 0, javascript: 0, typescript: 0, python: 0, rust: 0 };
528
+ for (const file of files) {
529
+ counts[detectLanguage(file.path)]++;
530
+ }
531
+ return Object.entries(counts).sort((a, b) => b[1] - a[1])[0][0];
532
+ }
533
+ function extractProjectName(files) {
534
+ if (files.length === 0)
535
+ return 'unknown';
536
+ const paths = files.map(f => f.path.split('/'));
537
+ let commonPrefix = [];
538
+ for (let i = 0; i < paths[0].length; i++) {
539
+ if (paths.every(p => p[i] === paths[0][i])) {
540
+ commonPrefix.push(paths[0][i]);
541
+ }
542
+ else
543
+ break;
544
+ }
545
+ return commonPrefix.length > 0 ? commonPrefix[commonPrefix.length - 1] : 'unknown';
546
+ }
547
+ function extractRoot(files) {
548
+ if (files.length === 0)
549
+ return '/';
550
+ const paths = files.map(f => f.path.split('/'));
551
+ const commonPrefix = [];
552
+ for (let i = 0; i < paths[0].length - 1; i++) {
553
+ if (paths.every(p => p[i] === paths[0][i])) {
554
+ commonPrefix.push(paths[0][i]);
555
+ }
556
+ else
557
+ break;
558
+ }
559
+ return commonPrefix.join('/') || '/';
560
+ }
561
+ function calculateSeverity(input) {
562
+ const criticalSinks = ['sql_injection', 'command_injection', 'code_injection', 'deserialization'];
563
+ const highSinks = ['xss', 'path_traversal', 'xxe', 'ssrf', 'ldap_injection'];
564
+ if (criticalSinks.some(s => input.sinkType.includes(s))) {
565
+ return input.pathExists ? 'critical' : 'high';
566
+ }
567
+ if (highSinks.some(s => input.sinkType.includes(s))) {
568
+ return input.pathExists ? 'high' : 'medium';
569
+ }
570
+ return input.pathExists ? 'medium' : 'low';
571
+ }
572
+ function getRemediation(sinkType) {
573
+ const remediations = {
574
+ sql_injection: 'Use parameterized queries or prepared statements',
575
+ command_injection: 'Avoid shell execution; use array-based APIs with validated input',
576
+ xss: 'Encode output using context-appropriate encoding (HTML, JavaScript, URL)',
577
+ path_traversal: 'Validate and canonicalize paths; use allowlists',
578
+ xxe: 'Disable external entity processing in XML parsers',
579
+ ssrf: 'Validate URLs against allowlist; block internal network access',
580
+ deserialization: 'Avoid deserializing untrusted data; use allowlists',
581
+ ldap_injection: 'Use parameterized LDAP queries; escape special characters',
582
+ };
583
+ for (const [key, value] of Object.entries(remediations)) {
584
+ if (sinkType.includes(key))
585
+ return value;
586
+ }
587
+ return 'Validate and sanitize all user input before use';
588
+ }
589
+ function aggregateFindings(fileAnalyses, taintPaths, crossFileFlows) {
590
+ const findings = [];
591
+ const seenIds = new Set();
592
+ // Generate findings from taint paths
593
+ for (const path of taintPaths) {
594
+ if (path.path_exists && path.sanitizers_in_path.length === 0) {
595
+ const id = `${path.source.file}:${path.source.line}-${path.sink.file}:${path.sink.line}`;
596
+ if (!seenIds.has(id)) {
597
+ seenIds.add(id);
598
+ const crossFileFlow = crossFileFlows.find(f => f.id === path.id);
599
+ findings.push({
600
+ id,
601
+ type: path.sink.type,
602
+ cwe: path.sink.cwe,
603
+ severity: calculateSeverity({
604
+ sourceType: path.source.type,
605
+ sinkType: path.sink.type,
606
+ pathExists: path.path_exists,
607
+ confidence: path.confidence,
608
+ }),
609
+ confidence: path.confidence,
610
+ source: {
611
+ file: path.source.file,
612
+ line: path.source.line,
613
+ code: path.source.code,
614
+ },
615
+ sink: {
616
+ file: path.sink.file,
617
+ line: path.sink.line,
618
+ code: path.sink.code,
619
+ },
620
+ path: path.hops,
621
+ exploitable: crossFileFlow?.exploitability === 'high' || (path.path_exists && path.confidence > 0.7),
622
+ explanation: generateExplanation(path),
623
+ remediation: getRemediation(path.sink.type),
624
+ verification: {
625
+ graph_path_exists: path.path_exists,
626
+ llm_verified: crossFileFlow?.verified ?? false,
627
+ llm_confidence: crossFileFlow?.confidence ?? 0,
628
+ },
629
+ });
630
+ }
631
+ }
632
+ }
633
+ // Sort by severity
634
+ const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
635
+ findings.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
636
+ return findings;
637
+ }
638
+ function generateExplanation(path) {
639
+ const sourceDesc = `User-controlled data from ${path.source.type} at ${path.source.file}:${path.source.line}`;
640
+ const sinkDesc = `reaches a ${path.sink.type} sink at ${path.sink.file}:${path.sink.line}`;
641
+ const hopDesc = path.hops.length > 0
642
+ ? ` through ${path.hops.length} intermediate step(s)`
643
+ : ' directly';
644
+ return `${sourceDesc}${hopDesc} and ${sinkDesc}. ${path.sink.cwe}`;
645
+ }
646
+ //# sourceMappingURL=two-phase-analyzer.js.map