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,693 @@
1
+ /**
2
+ * Continuous Security Scanner
3
+ *
4
+ * Provides automated security scanning for repositories with:
5
+ * - Git clone → file walker → Circle-IR analysis pipeline
6
+ * - OWASP Top 10 category mapping
7
+ * - Summary report with severity, location, confidence
8
+ * - Trend tracking (store results, compare across runs)
9
+ */
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import { execSync } from 'child_process';
13
+ import { initAnalyzer, isAnalyzerInitialized, analyze, generateFindings, } from 'circle-ir';
14
+ import { getOWASPMapping } from './owasp-mapping.js';
15
+ // ============================================================================
16
+ // Scanner Implementation
17
+ // ============================================================================
18
+ export class SecurityScanner {
19
+ workDir;
20
+ verbose;
21
+ onProgress;
22
+ constructor() {
23
+ this.workDir = '';
24
+ this.verbose = false;
25
+ }
26
+ /**
27
+ * Run a security scan on a repository or local path.
28
+ */
29
+ async scan(options) {
30
+ const startTime = Date.now();
31
+ this.verbose = options.verbose ?? false;
32
+ this.onProgress = options.onProgress;
33
+ // Ensure analyzer is initialized
34
+ if (!isAnalyzerInitialized()) {
35
+ await initAnalyzer();
36
+ }
37
+ // Phase 1: Clone or locate repository
38
+ this.reportProgress({ phase: 'clone', filesProcessed: 0, totalFiles: 0, findingsCount: 0 });
39
+ const repoPath = await this.prepareRepository(options);
40
+ // Phase 2: Discover files
41
+ this.reportProgress({ phase: 'discover', filesProcessed: 0, totalFiles: 0, findingsCount: 0 });
42
+ const files = this.discoverFiles(repoPath, options);
43
+ // Phase 3: Analyze files
44
+ this.reportProgress({ phase: 'analyze', filesProcessed: 0, totalFiles: files.length, findingsCount: 0 });
45
+ const fileResults = await this.analyzeFiles(files, options);
46
+ // Phase 4: Generate report
47
+ this.reportProgress({ phase: 'report', filesProcessed: files.length, totalFiles: files.length, findingsCount: 0 });
48
+ const result = this.generateReport(fileResults, options, startTime);
49
+ // Save report if output directory specified
50
+ if (options.outputDir) {
51
+ await this.saveReport(result, options.outputDir);
52
+ }
53
+ return result;
54
+ }
55
+ /**
56
+ * Prepare repository for scanning.
57
+ */
58
+ async prepareRepository(options) {
59
+ const { target, branch, commit } = options;
60
+ // Check if target is a URL (Git clone needed)
61
+ if (target.startsWith('http://') || target.startsWith('https://') || target.startsWith('git@')) {
62
+ return this.cloneRepository(target, branch, commit);
63
+ }
64
+ // Target is a local path
65
+ if (!fs.existsSync(target)) {
66
+ throw new Error(`Target path does not exist: ${target}`);
67
+ }
68
+ return path.resolve(target);
69
+ }
70
+ /**
71
+ * Clone a Git repository.
72
+ */
73
+ cloneRepository(url, branch, commit) {
74
+ // Create temp directory for clone
75
+ const tmpDir = fs.mkdtempSync(path.join('/tmp', 'circle-scan-'));
76
+ this.workDir = tmpDir;
77
+ if (this.verbose) {
78
+ console.log(`Cloning ${url} to ${tmpDir}...`);
79
+ }
80
+ try {
81
+ // Clone with shallow depth for speed
82
+ const branchArg = branch ? `--branch ${branch}` : '';
83
+ execSync(`git clone --depth 1 ${branchArg} "${url}" "${tmpDir}"`, {
84
+ stdio: this.verbose ? 'inherit' : 'pipe',
85
+ });
86
+ // Checkout specific commit if specified
87
+ if (commit) {
88
+ execSync(`git -C "${tmpDir}" fetch --depth 1 origin ${commit}`, {
89
+ stdio: this.verbose ? 'inherit' : 'pipe',
90
+ });
91
+ execSync(`git -C "${tmpDir}" checkout ${commit}`, {
92
+ stdio: this.verbose ? 'inherit' : 'pipe',
93
+ });
94
+ }
95
+ return tmpDir;
96
+ }
97
+ catch (error) {
98
+ // Clean up on error
99
+ fs.rmSync(tmpDir, { recursive: true, force: true });
100
+ throw new Error(`Failed to clone repository: ${error}`);
101
+ }
102
+ }
103
+ /**
104
+ * Discover files to scan.
105
+ */
106
+ discoverFiles(repoPath, options) {
107
+ const { languages, maxFiles = 1000, includePatterns, excludePatterns, } = options;
108
+ const files = [];
109
+ const defaultExcludes = [
110
+ '**/node_modules/**',
111
+ '**/vendor/**',
112
+ '**/target/**',
113
+ '**/build/**',
114
+ '**/dist/**',
115
+ '**/.git/**',
116
+ '**/test/**',
117
+ '**/tests/**',
118
+ '**/__tests__/**',
119
+ '**/*.test.*',
120
+ '**/*.spec.*',
121
+ '**/.*',
122
+ ];
123
+ const excludes = [...defaultExcludes, ...(excludePatterns || [])];
124
+ const languageExtensions = {
125
+ java: ['.java'],
126
+ c: ['.c', '.h'],
127
+ cpp: ['.cpp', '.cc', '.cxx', '.hpp', '.hxx'],
128
+ javascript: ['.js', '.jsx', '.mjs', '.cjs'],
129
+ typescript: ['.ts', '.tsx', '.mts', '.cts'],
130
+ python: ['.py'],
131
+ rust: ['.rs'],
132
+ };
133
+ // Determine which extensions to look for
134
+ let extensions = [];
135
+ if (languages && languages.length > 0) {
136
+ for (const lang of languages) {
137
+ extensions.push(...(languageExtensions[lang] || []));
138
+ }
139
+ }
140
+ else {
141
+ // Auto-detect: include all supported languages
142
+ extensions = Object.values(languageExtensions).flat();
143
+ }
144
+ // Walk directory tree
145
+ const walk = (dir, depth = 0) => {
146
+ if (depth > 30 || files.length >= maxFiles)
147
+ return;
148
+ try {
149
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
150
+ for (const entry of entries) {
151
+ if (files.length >= maxFiles)
152
+ break;
153
+ const fullPath = path.join(dir, entry.name);
154
+ const relativePath = path.relative(repoPath, fullPath);
155
+ // Check excludes
156
+ if (this.matchesPattern(relativePath, excludes)) {
157
+ continue;
158
+ }
159
+ if (entry.isDirectory()) {
160
+ walk(fullPath, depth + 1);
161
+ }
162
+ else if (entry.isFile()) {
163
+ // Check extension
164
+ const ext = path.extname(entry.name).toLowerCase();
165
+ if (!extensions.includes(ext))
166
+ continue;
167
+ // Check includes if specified
168
+ if (includePatterns && includePatterns.length > 0) {
169
+ if (!this.matchesPattern(relativePath, includePatterns)) {
170
+ continue;
171
+ }
172
+ }
173
+ files.push(fullPath);
174
+ }
175
+ }
176
+ }
177
+ catch {
178
+ // Skip directories we can't read
179
+ }
180
+ };
181
+ walk(repoPath);
182
+ if (this.verbose) {
183
+ console.log(`Discovered ${files.length} files to scan`);
184
+ }
185
+ return files;
186
+ }
187
+ /**
188
+ * Check if a path matches any of the given glob patterns.
189
+ */
190
+ matchesPattern(filePath, patterns) {
191
+ const normalizedPath = filePath.replace(/\\/g, '/');
192
+ for (const pattern of patterns) {
193
+ // Simple glob matching (supports * and **)
194
+ const regex = pattern
195
+ .replace(/\*\*/g, '{{DOUBLESTAR}}')
196
+ .replace(/\*/g, '[^/]*')
197
+ .replace(/{{DOUBLESTAR}}/g, '.*')
198
+ .replace(/\?/g, '.');
199
+ if (new RegExp(`^${regex}$`).test(normalizedPath)) {
200
+ return true;
201
+ }
202
+ }
203
+ return false;
204
+ }
205
+ /**
206
+ * Analyze files.
207
+ */
208
+ async analyzeFiles(files, options) {
209
+ const { parallel = true, maxConcurrency = 10, minSeverity = 'low' } = options;
210
+ const results = [];
211
+ let filesProcessed = 0;
212
+ let totalFindings = 0;
213
+ const repoPath = this.workDir || path.dirname(files[0] || '');
214
+ if (parallel) {
215
+ // Parallel analysis
216
+ const queue = [...files];
217
+ const workers = [];
218
+ for (let i = 0; i < Math.min(maxConcurrency, files.length); i++) {
219
+ workers.push((async () => {
220
+ while (queue.length > 0) {
221
+ const file = queue.shift();
222
+ if (!file)
223
+ break;
224
+ const result = await this.analyzeFile(file, repoPath, minSeverity);
225
+ results.push(result);
226
+ filesProcessed++;
227
+ totalFindings += result.findings.length;
228
+ this.reportProgress({
229
+ phase: 'analyze',
230
+ currentFile: result.path,
231
+ filesProcessed,
232
+ totalFiles: files.length,
233
+ findingsCount: totalFindings,
234
+ });
235
+ }
236
+ })());
237
+ }
238
+ await Promise.all(workers);
239
+ }
240
+ else {
241
+ // Sequential analysis
242
+ for (const file of files) {
243
+ const result = await this.analyzeFile(file, repoPath, minSeverity);
244
+ results.push(result);
245
+ filesProcessed++;
246
+ totalFindings += result.findings.length;
247
+ this.reportProgress({
248
+ phase: 'analyze',
249
+ currentFile: result.path,
250
+ filesProcessed,
251
+ totalFiles: files.length,
252
+ findingsCount: totalFindings,
253
+ });
254
+ }
255
+ }
256
+ return results;
257
+ }
258
+ /**
259
+ * Analyze a single file.
260
+ */
261
+ async analyzeFile(filePath, repoPath, minSeverity) {
262
+ const startTime = Date.now();
263
+ const relativePath = path.relative(repoPath, filePath);
264
+ const language = this.detectLanguage(filePath);
265
+ const findings = [];
266
+ try {
267
+ const content = fs.readFileSync(filePath, 'utf-8');
268
+ const ir = await analyze(content, path.basename(filePath), language);
269
+ // Generate findings from taint analysis
270
+ const irFindings = generateFindings(ir.taint.sources, ir.taint.sinks, ir.dfg, path.basename(filePath));
271
+ // Convert findings to ScanFinding with OWASP mapping
272
+ for (const finding of irFindings) {
273
+ // Filter by severity
274
+ if (!this.meetsMinSeverity(finding.severity, minSeverity)) {
275
+ continue;
276
+ }
277
+ const owasp = getOWASPMapping(finding.cwe);
278
+ findings.push({
279
+ ...finding,
280
+ owasp,
281
+ filePath: relativePath,
282
+ });
283
+ }
284
+ return {
285
+ path: relativePath,
286
+ language,
287
+ loc: ir.meta.loc,
288
+ findings,
289
+ analysisTimeMs: Date.now() - startTime,
290
+ };
291
+ }
292
+ catch (error) {
293
+ if (this.verbose) {
294
+ console.error(`Error analyzing ${relativePath}: ${error}`);
295
+ }
296
+ return {
297
+ path: relativePath,
298
+ language,
299
+ loc: 0,
300
+ findings: [],
301
+ analysisTimeMs: Date.now() - startTime,
302
+ };
303
+ }
304
+ }
305
+ /**
306
+ * Detect language from file extension.
307
+ */
308
+ detectLanguage(filePath) {
309
+ const ext = path.extname(filePath).toLowerCase();
310
+ switch (ext) {
311
+ case '.java':
312
+ return 'java';
313
+ case '.c':
314
+ case '.h':
315
+ return 'c';
316
+ case '.cpp':
317
+ case '.cc':
318
+ case '.cxx':
319
+ case '.hpp':
320
+ case '.hxx':
321
+ return 'cpp';
322
+ case '.js':
323
+ case '.jsx':
324
+ case '.mjs':
325
+ case '.cjs':
326
+ return 'javascript';
327
+ case '.ts':
328
+ case '.tsx':
329
+ case '.mts':
330
+ case '.cts':
331
+ return 'typescript';
332
+ case '.py':
333
+ return 'python';
334
+ case '.rs':
335
+ return 'rust';
336
+ default:
337
+ return 'java';
338
+ }
339
+ }
340
+ /**
341
+ * Check if severity meets minimum threshold.
342
+ */
343
+ meetsMinSeverity(severity, minSeverity) {
344
+ const severityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
345
+ const actualLevel = severityOrder[severity] || 0;
346
+ const minLevel = severityOrder[minSeverity];
347
+ return actualLevel >= minLevel;
348
+ }
349
+ /**
350
+ * Generate scan report.
351
+ */
352
+ generateReport(fileResults, options, startTime) {
353
+ // Collect all findings
354
+ const allFindings = [];
355
+ for (const file of fileResults) {
356
+ allFindings.push(...file.findings);
357
+ }
358
+ // Group by OWASP category
359
+ const byOWASP = {};
360
+ for (const finding of allFindings) {
361
+ const category = finding.owasp.category;
362
+ if (!byOWASP[category]) {
363
+ byOWASP[category] = {
364
+ count: 0,
365
+ critical: 0,
366
+ high: 0,
367
+ medium: 0,
368
+ low: 0,
369
+ findings: [],
370
+ };
371
+ }
372
+ byOWASP[category].count++;
373
+ byOWASP[category][finding.severity]++;
374
+ byOWASP[category].findings.push(finding);
375
+ }
376
+ // Calculate summary
377
+ const bySeverity = { critical: 0, high: 0, medium: 0, low: 0 };
378
+ const byType = {};
379
+ for (const finding of allFindings) {
380
+ bySeverity[finding.severity]++;
381
+ byType[finding.type] = (byType[finding.type] || 0) + 1;
382
+ }
383
+ // Find top vulnerable files
384
+ const fileVulnCounts = fileResults
385
+ .map((f) => ({ file: f.path, count: f.findings.length }))
386
+ .filter((f) => f.count > 0)
387
+ .sort((a, b) => b.count - a.count)
388
+ .slice(0, 5);
389
+ const totalLOC = fileResults.reduce((sum, f) => sum + f.loc, 0);
390
+ // Get commit info if available
391
+ let commit;
392
+ let branch;
393
+ if (this.workDir && fs.existsSync(path.join(this.workDir, '.git'))) {
394
+ try {
395
+ commit = execSync(`git -C "${this.workDir}" rev-parse HEAD`, { encoding: 'utf-8' }).trim();
396
+ branch = execSync(`git -C "${this.workDir}" rev-parse --abbrev-ref HEAD`, { encoding: 'utf-8' }).trim();
397
+ }
398
+ catch {
399
+ // Ignore git errors
400
+ }
401
+ }
402
+ return {
403
+ meta: {
404
+ target: options.target,
405
+ branch: options.branch || branch,
406
+ commit: options.commit || commit,
407
+ timestamp: new Date().toISOString(),
408
+ durationMs: Date.now() - startTime,
409
+ version: '1.0.0', // TODO: Get from package.json
410
+ },
411
+ findings: allFindings,
412
+ byOWASP,
413
+ summary: {
414
+ totalFiles: fileResults.length,
415
+ totalLOC,
416
+ totalFindings: allFindings.length,
417
+ bySeverity,
418
+ byType,
419
+ topVulnerableFiles: fileVulnCounts,
420
+ },
421
+ files: fileResults,
422
+ };
423
+ }
424
+ /**
425
+ * Save report to output directory.
426
+ */
427
+ async saveReport(result, outputDir) {
428
+ // Ensure output directory exists
429
+ fs.mkdirSync(outputDir, { recursive: true });
430
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
431
+ // Save JSON report
432
+ const jsonPath = path.join(outputDir, `scan-${timestamp}.json`);
433
+ fs.writeFileSync(jsonPath, JSON.stringify(result, null, 2));
434
+ // Save SARIF report
435
+ const sarifPath = path.join(outputDir, `scan-${timestamp}.sarif`);
436
+ fs.writeFileSync(sarifPath, JSON.stringify(this.toSARIF(result), null, 2));
437
+ // Save summary report
438
+ const summaryPath = path.join(outputDir, `scan-${timestamp}.txt`);
439
+ fs.writeFileSync(summaryPath, this.toTextSummary(result));
440
+ if (this.verbose) {
441
+ console.log(`Reports saved to ${outputDir}`);
442
+ }
443
+ }
444
+ /**
445
+ * Convert result to SARIF format.
446
+ */
447
+ toSARIF(result) {
448
+ return {
449
+ $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
450
+ version: '2.1.0',
451
+ runs: [
452
+ {
453
+ tool: {
454
+ driver: {
455
+ name: 'Circle-IR',
456
+ version: result.meta.version,
457
+ informationUri: 'https://github.com/cognium/circle-ir',
458
+ rules: Object.entries(result.summary.byType).map(([type, _count]) => ({
459
+ id: type,
460
+ name: type.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()),
461
+ helpUri: `https://cwe.mitre.org/data/definitions/${type}.html`,
462
+ })),
463
+ },
464
+ },
465
+ results: result.findings.map((f) => ({
466
+ ruleId: f.type,
467
+ level: f.severity === 'critical' || f.severity === 'high' ? 'error' : 'warning',
468
+ message: {
469
+ text: f.explanation || `${f.type} vulnerability detected`,
470
+ },
471
+ locations: [
472
+ {
473
+ physicalLocation: {
474
+ artifactLocation: {
475
+ uri: f.filePath,
476
+ },
477
+ region: {
478
+ startLine: f.sink?.line || f.source?.line || 1,
479
+ },
480
+ },
481
+ },
482
+ ],
483
+ properties: {
484
+ cwe: f.cwe,
485
+ owasp: f.owasp.category,
486
+ severity: f.severity,
487
+ confidence: f.confidence,
488
+ },
489
+ })),
490
+ },
491
+ ],
492
+ };
493
+ }
494
+ /**
495
+ * Convert result to text summary.
496
+ */
497
+ toTextSummary(result) {
498
+ const lines = [
499
+ '='.repeat(70),
500
+ 'SECURITY SCAN REPORT',
501
+ '='.repeat(70),
502
+ '',
503
+ `Target: ${result.meta.target}`,
504
+ `Branch: ${result.meta.branch || 'N/A'}`,
505
+ `Commit: ${result.meta.commit || 'N/A'}`,
506
+ `Timestamp: ${result.meta.timestamp}`,
507
+ `Duration: ${(result.meta.durationMs / 1000).toFixed(2)}s`,
508
+ '',
509
+ '-'.repeat(70),
510
+ 'SUMMARY',
511
+ '-'.repeat(70),
512
+ '',
513
+ `Files Scanned: ${result.summary.totalFiles}`,
514
+ `Lines of Code: ${result.summary.totalLOC.toLocaleString()}`,
515
+ `Total Findings: ${result.summary.totalFindings}`,
516
+ '',
517
+ 'Severity Breakdown:',
518
+ ` Critical: ${result.summary.bySeverity.critical}`,
519
+ ` High: ${result.summary.bySeverity.high}`,
520
+ ` Medium: ${result.summary.bySeverity.medium}`,
521
+ ` Low: ${result.summary.bySeverity.low}`,
522
+ '',
523
+ '-'.repeat(70),
524
+ 'OWASP TOP 10 BREAKDOWN',
525
+ '-'.repeat(70),
526
+ '',
527
+ ];
528
+ // Sort OWASP categories by rank
529
+ const sortedOWASP = Object.entries(result.byOWASP)
530
+ .sort(([, a], [, b]) => b.count - a.count);
531
+ for (const [category, data] of sortedOWASP) {
532
+ if (data.count === 0)
533
+ continue;
534
+ lines.push(`${category}: ${data.count} findings`);
535
+ lines.push(` Critical: ${data.critical}, High: ${data.high}, Medium: ${data.medium}, Low: ${data.low}`);
536
+ lines.push('');
537
+ }
538
+ if (result.summary.topVulnerableFiles.length > 0) {
539
+ lines.push('-'.repeat(70));
540
+ lines.push('TOP VULNERABLE FILES');
541
+ lines.push('-'.repeat(70));
542
+ lines.push('');
543
+ for (const file of result.summary.topVulnerableFiles) {
544
+ lines.push(` ${file.file}: ${file.count} findings`);
545
+ }
546
+ lines.push('');
547
+ }
548
+ lines.push('='.repeat(70));
549
+ return lines.join('\n');
550
+ }
551
+ /**
552
+ * Report progress.
553
+ */
554
+ reportProgress(progress) {
555
+ if (this.onProgress) {
556
+ this.onProgress(progress);
557
+ }
558
+ if (this.verbose) {
559
+ const { phase, currentFile, filesProcessed, totalFiles, findingsCount } = progress;
560
+ if (currentFile) {
561
+ console.log(`[${phase}] ${filesProcessed}/${totalFiles} - ${currentFile} (${findingsCount} findings)`);
562
+ }
563
+ else {
564
+ console.log(`[${phase}] ${filesProcessed}/${totalFiles}`);
565
+ }
566
+ }
567
+ }
568
+ /**
569
+ * Clean up temporary files.
570
+ */
571
+ cleanup() {
572
+ if (this.workDir && fs.existsSync(this.workDir)) {
573
+ fs.rmSync(this.workDir, { recursive: true, force: true });
574
+ this.workDir = '';
575
+ }
576
+ }
577
+ }
578
+ // ============================================================================
579
+ // Convenience Functions
580
+ // ============================================================================
581
+ /**
582
+ * Run a security scan on a repository or local path.
583
+ */
584
+ export async function scanRepository(options) {
585
+ const scanner = new SecurityScanner();
586
+ try {
587
+ return await scanner.scan(options);
588
+ }
589
+ finally {
590
+ scanner.cleanup();
591
+ }
592
+ }
593
+ /**
594
+ * Scan a local directory.
595
+ */
596
+ export async function scanDirectory(directory, options) {
597
+ return scanRepository({ target: directory, ...options });
598
+ }
599
+ /**
600
+ * Quick scan with default options.
601
+ */
602
+ export async function quickScan(target) {
603
+ return scanRepository({
604
+ target,
605
+ parallel: true,
606
+ maxConcurrency: 10,
607
+ minSeverity: 'medium',
608
+ });
609
+ }
610
+ /**
611
+ * Format scan result as a human-readable report.
612
+ */
613
+ export function formatScanReport(result) {
614
+ const lines = [];
615
+ lines.push('═'.repeat(60));
616
+ lines.push('SECURITY SCAN REPORT');
617
+ lines.push('═'.repeat(60));
618
+ lines.push('');
619
+ lines.push(`Target: ${result.meta.target}`);
620
+ lines.push(`Timestamp: ${result.meta.timestamp}`);
621
+ lines.push(`Duration: ${(result.meta.durationMs / 1000).toFixed(2)}s`);
622
+ lines.push('');
623
+ // Summary
624
+ lines.push('─'.repeat(40));
625
+ lines.push('SUMMARY');
626
+ lines.push('─'.repeat(40));
627
+ lines.push(`Files scanned: ${result.summary.totalFiles}`);
628
+ lines.push(`Lines of code: ${result.summary.totalLOC.toLocaleString()}`);
629
+ lines.push(`Total findings: ${result.summary.totalFindings}`);
630
+ lines.push('');
631
+ // By severity
632
+ lines.push('By Severity:');
633
+ const { bySeverity } = result.summary;
634
+ if (bySeverity.critical > 0)
635
+ lines.push(` 🔴 Critical: ${bySeverity.critical}`);
636
+ if (bySeverity.high > 0)
637
+ lines.push(` 🟠 High: ${bySeverity.high}`);
638
+ if (bySeverity.medium > 0)
639
+ lines.push(` 🟡 Medium: ${bySeverity.medium}`);
640
+ if (bySeverity.low > 0)
641
+ lines.push(` 🟢 Low: ${bySeverity.low}`);
642
+ lines.push('');
643
+ // OWASP Top 10
644
+ const owaspEntries = Object.entries(result.byOWASP).filter(([_, v]) => v.count > 0);
645
+ if (owaspEntries.length > 0) {
646
+ lines.push('─'.repeat(40));
647
+ lines.push('OWASP TOP 10');
648
+ lines.push('─'.repeat(40));
649
+ for (const [category, data] of owaspEntries.sort((a, b) => b[1].count - a[1].count)) {
650
+ lines.push(`${category}: ${data.count} findings`);
651
+ if (data.critical > 0)
652
+ lines.push(` Critical: ${data.critical}`);
653
+ if (data.high > 0)
654
+ lines.push(` High: ${data.high}`);
655
+ if (data.medium > 0)
656
+ lines.push(` Medium: ${data.medium}`);
657
+ }
658
+ lines.push('');
659
+ }
660
+ // Top vulnerable files
661
+ if (result.summary.topVulnerableFiles.length > 0) {
662
+ lines.push('─'.repeat(40));
663
+ lines.push('TOP VULNERABLE FILES');
664
+ lines.push('─'.repeat(40));
665
+ for (const file of result.summary.topVulnerableFiles.slice(0, 5)) {
666
+ lines.push(` ${file.file}: ${file.count} findings`);
667
+ }
668
+ lines.push('');
669
+ }
670
+ // Detailed findings
671
+ if (result.findings.length > 0) {
672
+ lines.push('─'.repeat(40));
673
+ lines.push('FINDINGS');
674
+ lines.push('─'.repeat(40));
675
+ for (const finding of result.findings.slice(0, 20)) {
676
+ const sev = finding.severity?.toUpperCase() || 'INFO';
677
+ const icon = sev === 'CRITICAL' ? '🔴' : sev === 'HIGH' ? '🟠' : sev === 'MEDIUM' ? '🟡' : '🟢';
678
+ lines.push(`${icon} [${finding.cwe || 'N/A'}] ${finding.type}`);
679
+ lines.push(` File: ${finding.filePath}:${finding.source?.line || '?'}`);
680
+ if (finding.explanation) {
681
+ lines.push(` ${finding.explanation.substring(0, 80)}${finding.explanation.length > 80 ? '...' : ''}`);
682
+ }
683
+ lines.push('');
684
+ }
685
+ if (result.findings.length > 20) {
686
+ lines.push(`... and ${result.findings.length - 20} more findings`);
687
+ lines.push('');
688
+ }
689
+ }
690
+ lines.push('═'.repeat(60));
691
+ return lines.join('\n');
692
+ }
693
+ //# sourceMappingURL=scanner.js.map