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,1003 @@
1
+ /**
2
+ * Dead Code Detector
3
+ *
4
+ * Detects unreachable code in a codebase by:
5
+ * 1. Identifying entry points (main methods, exports, HTTP handlers, etc.)
6
+ * 2. Building a call graph from those entry points
7
+ * 3. Finding functions/classes that are never reached
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import { initAnalyzer, isAnalyzerInitialized, analyze, } from 'circle-ir';
12
+ // ============================================================================
13
+ // Entry Point Detection Patterns
14
+ // ============================================================================
15
+ /** Method names that indicate entry points */
16
+ const ENTRY_POINT_METHODS = new Set([
17
+ // Java main
18
+ 'main',
19
+ // Servlet lifecycle
20
+ 'init', 'destroy', 'service',
21
+ 'doGet', 'doPost', 'doPut', 'doDelete', 'doHead', 'doOptions', 'doTrace',
22
+ // Spring lifecycle
23
+ 'afterPropertiesSet', 'postConstruct', 'preDestroy',
24
+ // JUnit test methods (if includeTests is true)
25
+ 'setUp', 'tearDown', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll',
26
+ ]);
27
+ /** Annotations that indicate entry points */
28
+ const ENTRY_POINT_ANNOTATIONS = new Set([
29
+ // Spring Web
30
+ 'GetMapping', 'PostMapping', 'PutMapping', 'DeleteMapping', 'PatchMapping',
31
+ 'RequestMapping', 'RestController', 'Controller',
32
+ // Spring lifecycle
33
+ 'PostConstruct', 'PreDestroy', 'Bean', 'EventListener', 'Scheduled',
34
+ // JAX-RS
35
+ 'GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'Path',
36
+ // JUnit (if includeTests is true)
37
+ 'Test', 'BeforeEach', 'AfterEach', 'BeforeAll', 'AfterAll', 'Before', 'After',
38
+ // Servlet
39
+ 'WebServlet', 'WebFilter', 'WebListener',
40
+ // EJB
41
+ 'Stateless', 'Stateful', 'Singleton', 'MessageDriven',
42
+ ]);
43
+ /** Class-level annotations that make all public methods entry points */
44
+ const CLASS_ENTRY_POINT_ANNOTATIONS = new Set([
45
+ 'RestController', 'Controller', 'Service', 'Component', 'Repository',
46
+ 'Stateless', 'Stateful', 'Singleton',
47
+ 'WebServlet', 'WebFilter',
48
+ ]);
49
+ /** HTTP verbs used with framework receivers (JS/TS) */
50
+ const HTTP_VERB_METHODS = new Set([
51
+ 'get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'use', 'all', 'route',
52
+ ]);
53
+ /** Event emitter methods that take callback entry points (JS/TS) */
54
+ const EVENT_LISTENER_METHODS = new Set([
55
+ 'on', 'once', 'addEventListener', 'addListener',
56
+ ]);
57
+ // ============================================================================
58
+ // Dead Code Detector Implementation
59
+ // ============================================================================
60
+ export class DeadCodeDetector {
61
+ verbose = false;
62
+ onProgress;
63
+ methodMap = new Map();
64
+ callGraph = new Map();
65
+ reverseCallGraph = new Map();
66
+ entryPoints = new Set();
67
+ reachable = new Set();
68
+ /**
69
+ * Detect dead code in a codebase.
70
+ */
71
+ async detect(options) {
72
+ const startTime = Date.now();
73
+ this.verbose = options.verbose ?? false;
74
+ this.onProgress = options.onProgress;
75
+ // Reset state
76
+ this.methodMap.clear();
77
+ this.callGraph.clear();
78
+ this.reverseCallGraph.clear();
79
+ this.entryPoints.clear();
80
+ this.reachable.clear();
81
+ // Ensure analyzer is initialized
82
+ if (!isAnalyzerInitialized()) {
83
+ await initAnalyzer();
84
+ }
85
+ // Phase 1: Discover files
86
+ this.reportProgress({ phase: 'discover', filesProcessed: 0, totalFiles: 0 });
87
+ const files = this.discoverFiles(options);
88
+ // Phase 2: Analyze files
89
+ this.reportProgress({ phase: 'analyze', filesProcessed: 0, totalFiles: files.length });
90
+ const fileResults = await this.analyzeFiles(files, options);
91
+ // Phase 3: Build call graph
92
+ this.reportProgress({ phase: 'build-graph', filesProcessed: files.length, totalFiles: files.length });
93
+ this.buildCallGraph(fileResults, options);
94
+ // Phase 4: Detect dead code
95
+ this.reportProgress({ phase: 'detect', filesProcessed: files.length, totalFiles: files.length });
96
+ const deadCode = this.detectDeadCode(fileResults, options);
97
+ // Generate result
98
+ const result = this.generateResult(fileResults, deadCode, options, startTime);
99
+ return result;
100
+ }
101
+ /**
102
+ * Discover files to analyze.
103
+ */
104
+ discoverFiles(options) {
105
+ const { target, includeTests = false, includePatterns, excludePatterns } = options;
106
+ const files = [];
107
+ const defaultExcludes = [
108
+ '**/node_modules/**',
109
+ '**/vendor/**',
110
+ '**/target/**',
111
+ '**/build/**',
112
+ '**/dist/**',
113
+ '**/.git/**',
114
+ '**/.*',
115
+ ];
116
+ if (!includeTests) {
117
+ defaultExcludes.push('**/test/**', '**/tests/**', '**/__tests__/**', '**/*.test.*', '**/*.spec.*', '**/*Test.java', '**/*Tests.java', '**/src/test/**');
118
+ }
119
+ const excludes = [...defaultExcludes, ...(excludePatterns || [])];
120
+ const languageExtensions = {
121
+ java: ['.java'],
122
+ c: ['.c', '.h'],
123
+ cpp: ['.cpp', '.cc', '.cxx', '.hpp', '.hxx'],
124
+ javascript: ['.js', '.jsx', '.mjs', '.cjs'],
125
+ typescript: ['.ts', '.tsx', '.mts', '.cts'],
126
+ python: ['.py'],
127
+ rust: ['.rs'],
128
+ };
129
+ const extensions = options.languages
130
+ ? options.languages.flatMap(l => languageExtensions[l] || [])
131
+ : Object.values(languageExtensions).flat();
132
+ // Handle single file
133
+ if (fs.statSync(target).isFile()) {
134
+ return [path.resolve(target)];
135
+ }
136
+ // Walk directory
137
+ const walk = (dir, depth = 0) => {
138
+ if (depth > 30)
139
+ return;
140
+ try {
141
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
142
+ for (const entry of entries) {
143
+ const fullPath = path.join(dir, entry.name);
144
+ const relativePath = path.relative(target, fullPath);
145
+ if (this.matchesPattern(relativePath, excludes)) {
146
+ continue;
147
+ }
148
+ if (entry.isDirectory()) {
149
+ walk(fullPath, depth + 1);
150
+ }
151
+ else if (entry.isFile()) {
152
+ const ext = path.extname(entry.name).toLowerCase();
153
+ if (!extensions.includes(ext))
154
+ continue;
155
+ if (includePatterns && includePatterns.length > 0) {
156
+ if (!this.matchesPattern(relativePath, includePatterns)) {
157
+ continue;
158
+ }
159
+ }
160
+ files.push(fullPath);
161
+ }
162
+ }
163
+ }
164
+ catch {
165
+ // Skip unreadable directories
166
+ }
167
+ };
168
+ walk(path.resolve(target));
169
+ if (this.verbose) {
170
+ console.log(`Discovered ${files.length} files to analyze`);
171
+ }
172
+ return files;
173
+ }
174
+ /**
175
+ * Check if path matches glob patterns.
176
+ */
177
+ matchesPattern(filePath, patterns) {
178
+ const normalized = filePath.replace(/\\/g, '/');
179
+ for (const pattern of patterns) {
180
+ // Convert glob pattern to regex:
181
+ // 1. Escape regex special chars except glob chars (*, ?, [, ])
182
+ // 2. Convert glob patterns to regex equivalents
183
+ const regex = pattern
184
+ .replace(/\*\*/g, '{{DOUBLESTAR}}')
185
+ .replace(/\*/g, '{{STAR}}')
186
+ .replace(/\?/g, '{{QUESTION}}')
187
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex special chars
188
+ .replace(/{{DOUBLESTAR}}/g, '.*')
189
+ .replace(/{{STAR}}/g, '[^/]*')
190
+ .replace(/{{QUESTION}}/g, '.');
191
+ if (new RegExp(`^${regex}$`).test(normalized)) {
192
+ return true;
193
+ }
194
+ }
195
+ return false;
196
+ }
197
+ /**
198
+ * Analyze files and extract methods.
199
+ */
200
+ async analyzeFiles(files, options) {
201
+ const results = [];
202
+ let processed = 0;
203
+ for (const file of files) {
204
+ try {
205
+ const content = fs.readFileSync(file, 'utf-8');
206
+ const language = this.detectLanguage(file);
207
+ const ir = await analyze(content, path.basename(file), language);
208
+ results.push({
209
+ file: path.relative(options.target, file),
210
+ ir,
211
+ loc: ir.meta.loc,
212
+ });
213
+ processed++;
214
+ this.reportProgress({
215
+ phase: 'analyze',
216
+ filesProcessed: processed,
217
+ totalFiles: files.length,
218
+ message: path.basename(file),
219
+ });
220
+ }
221
+ catch (error) {
222
+ if (this.verbose) {
223
+ console.error(`Error analyzing ${file}: ${error}`);
224
+ }
225
+ }
226
+ }
227
+ return results;
228
+ }
229
+ /**
230
+ * Build call graph from analyzed files.
231
+ */
232
+ buildCallGraph(files, options) {
233
+ const { additionalEntryPoints = [], publicMethodsAsEntryPoints = false, includeTests = false } = options;
234
+ const additionalEntryPointSet = new Set(additionalEntryPoints);
235
+ // First pass: register all methods
236
+ for (const { file, ir } of files) {
237
+ const language = ir.meta.language;
238
+ for (const type of ir.types) {
239
+ if (type.kind !== 'class' && type.kind !== 'interface')
240
+ continue;
241
+ const classAnnotations = type.annotations || [];
242
+ const isEntryPointClass = classAnnotations.some(a => CLASS_ENTRY_POINT_ANNOTATIONS.has(a));
243
+ for (const method of type.methods) {
244
+ const methodId = this.getMethodId(file, type.name, method.name);
245
+ this.methodMap.set(methodId, {
246
+ id: methodId,
247
+ file,
248
+ className: type.name,
249
+ methodName: method.name,
250
+ startLine: method.start_line,
251
+ endLine: method.end_line,
252
+ lineCount: method.end_line - method.start_line + 1,
253
+ modifiers: method.modifiers,
254
+ annotations: method.annotations || [],
255
+ language,
256
+ });
257
+ this.callGraph.set(methodId, new Set());
258
+ this.reverseCallGraph.set(methodId, new Set());
259
+ // Check if this is an entry point
260
+ if (this.isEntryPoint(type, method, isEntryPointClass, additionalEntryPointSet, publicMethodsAsEntryPoints, includeTests, language)) {
261
+ this.entryPoints.add(methodId);
262
+ }
263
+ }
264
+ // Track constructors (skip <module> in JS/TS/Python — it's not a real class)
265
+ if (type.kind === 'class' && !(this.isModuleBasedLanguage(language) && type.name === '<module>')) {
266
+ const constructorId = this.getMethodId(file, type.name, '<init>');
267
+ this.methodMap.set(constructorId, {
268
+ id: constructorId,
269
+ file,
270
+ className: type.name,
271
+ methodName: '<init>',
272
+ startLine: type.start_line,
273
+ endLine: type.end_line,
274
+ lineCount: type.end_line - type.start_line + 1,
275
+ modifiers: [],
276
+ annotations: [],
277
+ language,
278
+ });
279
+ this.callGraph.set(constructorId, new Set());
280
+ this.reverseCallGraph.set(constructorId, new Set());
281
+ // Constructors are entry points if class is instantiable from outside
282
+ if (isEntryPointClass || publicMethodsAsEntryPoints) {
283
+ this.entryPoints.add(constructorId);
284
+ }
285
+ }
286
+ }
287
+ }
288
+ // Second pass: build call edges
289
+ for (const { file, ir } of files) {
290
+ for (const call of ir.calls) {
291
+ // Find the containing method
292
+ const containingMethod = this.findContainingMethod(file, ir, call.location.line);
293
+ if (!containingMethod)
294
+ continue;
295
+ // Resolve the target method
296
+ const targetMethods = this.resolveCallTarget(call, ir.types, files);
297
+ for (const targetId of targetMethods) {
298
+ // Add edge from caller to callee
299
+ this.callGraph.get(containingMethod)?.add(targetId);
300
+ // Add reverse edge
301
+ this.reverseCallGraph.get(targetId)?.add(containingMethod);
302
+ }
303
+ }
304
+ }
305
+ // Third pass: JS/TS/Python module-level entry points
306
+ for (const { file, ir } of files) {
307
+ const language = ir.meta.language;
308
+ if (!this.isModuleBasedLanguage(language))
309
+ continue;
310
+ // Register <module-init> as synthetic entry point for top-level code
311
+ const moduleType = ir.types.find(t => t.name === '<module>');
312
+ if (!moduleType)
313
+ continue;
314
+ const moduleInitId = this.getMethodId(file, '<module>', '<module-init>');
315
+ this.methodMap.set(moduleInitId, {
316
+ id: moduleInitId,
317
+ file,
318
+ className: '<module>',
319
+ methodName: '<module-init>',
320
+ startLine: 1,
321
+ endLine: moduleType.end_line,
322
+ lineCount: 0, // synthetic, don't count LOC
323
+ modifiers: [],
324
+ annotations: [],
325
+ language,
326
+ });
327
+ this.callGraph.set(moduleInitId, new Set());
328
+ this.reverseCallGraph.set(moduleInitId, new Set());
329
+ this.entryPoints.add(moduleInitId);
330
+ // Assign orphan calls (top-level + anonymous callbacks) to <module-init>
331
+ for (const call of ir.calls) {
332
+ const containingMethod = this.findContainingMethod(file, ir, call.location.line);
333
+ if (containingMethod === null) {
334
+ const targetMethods = this.resolveCallTarget(call, ir.types, files);
335
+ for (const targetId of targetMethods) {
336
+ this.callGraph.get(moduleInitId)?.add(targetId);
337
+ this.reverseCallGraph.get(targetId)?.add(moduleInitId);
338
+ }
339
+ }
340
+ }
341
+ }
342
+ }
343
+ /**
344
+ * Check if a method is an entry point.
345
+ */
346
+ isEntryPoint(type, method, isEntryPointClass, additionalEntryPoints, publicMethodsAsEntryPoints, includeTests, language) {
347
+ // JS/TS: entry points are determined by <module-init> reachability,
348
+ // NOT by method-level patterns. The third pass in buildCallGraph handles this.
349
+ // Here we only mark explicit framework patterns.
350
+ if (this.isJSTS(language)) {
351
+ // HTTP handler synthetic methods (get_handler, post_handler, etc.)
352
+ if (method.name.endsWith('_handler')) {
353
+ const verb = method.name.replace('_handler', '');
354
+ if (HTTP_VERB_METHODS.has(verb) || EVENT_LISTENER_METHODS.has(verb)) {
355
+ return true;
356
+ }
357
+ }
358
+ // Additional user-specified entry points
359
+ if (additionalEntryPoints.has(method.name)) {
360
+ return true;
361
+ }
362
+ // Don't auto-mark all <module> functions — let call graph decide
363
+ return false;
364
+ }
365
+ // Python: similar to JS/TS, module-level code is the entry point.
366
+ // Here we mark Flask/Django route handlers and other framework patterns.
367
+ if (this.isPython(language)) {
368
+ const annotations = method.annotations || [];
369
+ // Flask/Django route decorators
370
+ if (annotations.some(a => a.startsWith('route') || a.startsWith('app.route') ||
371
+ a === 'get' || a === 'post' || a === 'put' || a === 'delete' || a === 'patch')) {
372
+ return true;
373
+ }
374
+ // Django class-based views
375
+ if (annotations.includes('api_view') || annotations.includes('action')) {
376
+ return true;
377
+ }
378
+ // pytest/unittest markers
379
+ if (includeTests && annotations.some(a => a.startsWith('pytest') || a === 'test')) {
380
+ return true;
381
+ }
382
+ // Additional user-specified entry points
383
+ if (additionalEntryPoints.has(method.name)) {
384
+ return true;
385
+ }
386
+ // Don't auto-mark all <module> functions — let call graph decide
387
+ return false;
388
+ }
389
+ // Rust: entry points include main, async runtime entry points, test functions, and pub fns
390
+ if (this.isRust(language)) {
391
+ const annotations = method.annotations || [];
392
+ // main function is always an entry point
393
+ if (method.name === 'main') {
394
+ return true;
395
+ }
396
+ // Async runtime entry points
397
+ if (annotations.some(a => a.includes('tokio::main') || a.includes('tokio::test') ||
398
+ a.includes('actix_web::main') || a.includes('actix_rt::main') ||
399
+ a.includes('async_std::main') || a.includes('rocket::launch') ||
400
+ a === 'main' || a === 'launch')) {
401
+ return true;
402
+ }
403
+ // Test functions
404
+ if (includeTests && (annotations.includes('test') ||
405
+ annotations.includes('tokio::test') ||
406
+ annotations.includes('async_std::test') ||
407
+ method.name.startsWith('test_'))) {
408
+ return true;
409
+ }
410
+ // Actix-web route handlers
411
+ if (annotations.some(a => a.includes('get') || a.includes('post') || a.includes('put') ||
412
+ a.includes('delete') || a.includes('patch') || a.includes('route'))) {
413
+ return true;
414
+ }
415
+ // Additional user-specified entry points
416
+ if (additionalEntryPoints.has(method.name)) {
417
+ return true;
418
+ }
419
+ // Public functions in lib.rs are potential entry points (library API)
420
+ if (method.modifiers.includes('pub') && publicMethodsAsEntryPoints) {
421
+ return true;
422
+ }
423
+ return false;
424
+ }
425
+ // Java logic
426
+ const methodAnnotations = method.annotations || [];
427
+ // Check explicit entry point methods
428
+ if (ENTRY_POINT_METHODS.has(method.name)) {
429
+ // For main, verify signature
430
+ if (method.name === 'main') {
431
+ const isPublic = method.modifiers.includes('public');
432
+ const isStatic = method.modifiers.includes('static');
433
+ if (isPublic && isStatic) {
434
+ return true;
435
+ }
436
+ }
437
+ else if (!includeTests && ['setUp', 'tearDown', 'beforeEach', 'afterEach'].includes(method.name)) {
438
+ return false; // Skip test lifecycle methods if not including tests
439
+ }
440
+ else {
441
+ return true;
442
+ }
443
+ }
444
+ // Check annotations
445
+ for (const annotation of methodAnnotations) {
446
+ if (ENTRY_POINT_ANNOTATIONS.has(annotation)) {
447
+ if (!includeTests && ['Test', 'BeforeEach', 'AfterEach', 'BeforeAll', 'AfterAll', 'Before', 'After'].includes(annotation)) {
448
+ return false;
449
+ }
450
+ return true;
451
+ }
452
+ }
453
+ // Check if class is an entry point class (all public methods are entry points)
454
+ if (isEntryPointClass && method.modifiers.includes('public')) {
455
+ return true;
456
+ }
457
+ // Check additional entry points
458
+ if (additionalEntryPoints.has(method.name)) {
459
+ return true;
460
+ }
461
+ // Check if public methods should be entry points
462
+ if (publicMethodsAsEntryPoints && method.modifiers.includes('public')) {
463
+ return true;
464
+ }
465
+ return false;
466
+ }
467
+ /**
468
+ * Find the method containing a given line.
469
+ */
470
+ findContainingMethod(file, ir, line) {
471
+ for (const type of ir.types) {
472
+ if (type.kind !== 'class' && type.kind !== 'interface')
473
+ continue;
474
+ for (const method of type.methods) {
475
+ if (line >= method.start_line && line <= method.end_line) {
476
+ return this.getMethodId(file, type.name, method.name);
477
+ }
478
+ }
479
+ }
480
+ return null;
481
+ }
482
+ /**
483
+ * Resolve a call to potential target methods.
484
+ */
485
+ resolveCallTarget(call, types, allFiles) {
486
+ const targets = [];
487
+ const methodName = call.method_name;
488
+ const receiver = call.receiver;
489
+ // Simple resolution: find all methods with the same name
490
+ // In a real implementation, this would use type inference
491
+ for (const { file, ir } of allFiles) {
492
+ for (const type of ir.types) {
493
+ if (type.kind !== 'class' && type.kind !== 'interface')
494
+ continue;
495
+ for (const method of type.methods) {
496
+ if (method.name === methodName) {
497
+ // If we have a receiver, try to match the class
498
+ if (receiver) {
499
+ // Check if receiver matches class name (simplified)
500
+ const receiverLower = receiver.toLowerCase();
501
+ const classLower = type.name.toLowerCase();
502
+ if (receiverLower.includes(classLower) || classLower.includes(receiverLower)) {
503
+ targets.push(this.getMethodId(file, type.name, method.name));
504
+ }
505
+ }
506
+ else {
507
+ targets.push(this.getMethodId(file, type.name, method.name));
508
+ }
509
+ }
510
+ }
511
+ }
512
+ }
513
+ return targets;
514
+ }
515
+ /**
516
+ * Detect dead code using reachability analysis.
517
+ */
518
+ detectDeadCode(files, options) {
519
+ const { maxDepth = 50 } = options;
520
+ const deadCode = [];
521
+ // Perform BFS from entry points
522
+ const queue = [];
523
+ for (const entryPoint of this.entryPoints) {
524
+ queue.push({ id: entryPoint, depth: 0 });
525
+ this.reachable.add(entryPoint);
526
+ }
527
+ while (queue.length > 0) {
528
+ const { id, depth } = queue.shift();
529
+ if (depth >= maxDepth)
530
+ continue;
531
+ const callees = this.callGraph.get(id);
532
+ if (callees) {
533
+ for (const callee of callees) {
534
+ if (!this.reachable.has(callee)) {
535
+ this.reachable.add(callee);
536
+ queue.push({ id: callee, depth: depth + 1 });
537
+ }
538
+ }
539
+ }
540
+ }
541
+ // Find unreachable methods
542
+ for (const [methodId, node] of this.methodMap) {
543
+ if (!this.reachable.has(methodId)) {
544
+ // Determine confidence
545
+ let confidence = 'high';
546
+ let reason = 'Not reachable from any entry point';
547
+ if (this.isJSTS(node.language)) {
548
+ // Skip synthetic <module-init> — not real dead code
549
+ if (node.methodName === '<module-init>')
550
+ continue;
551
+ // Underscore-prefixed = conventionally private
552
+ if (node.methodName.startsWith('_')) {
553
+ confidence = 'high';
554
+ reason = 'Private helper function not called from any entry point';
555
+ }
556
+ // Callback handler names — may be invoked by framework
557
+ else if (node.methodName.endsWith('_handler')) {
558
+ confidence = 'low';
559
+ reason = 'Callback handler (may be invoked by framework)';
560
+ }
561
+ // JS protocol methods
562
+ else if (['toString', 'valueOf', 'toJSON', 'constructor'].includes(node.methodName)) {
563
+ confidence = 'low';
564
+ reason = 'Standard protocol method (may be called implicitly)';
565
+ }
566
+ }
567
+ else if (this.isPython(node.language)) {
568
+ // Skip synthetic <module-init> — not real dead code
569
+ if (node.methodName === '<module-init>')
570
+ continue;
571
+ // Single underscore prefix = conventionally private
572
+ if (node.methodName.startsWith('_') && !node.methodName.startsWith('__')) {
573
+ confidence = 'high';
574
+ reason = 'Private helper function not called from any entry point';
575
+ }
576
+ // Dunder methods = special/magic methods, may be called implicitly
577
+ else if (node.methodName.startsWith('__') && node.methodName.endsWith('__')) {
578
+ confidence = 'low';
579
+ reason = 'Magic method (may be called implicitly by Python runtime)';
580
+ }
581
+ // Test methods (if not including tests)
582
+ else if (node.methodName.startsWith('test_')) {
583
+ confidence = 'low';
584
+ reason = 'Test method (may be called by test runner)';
585
+ }
586
+ // Common callback/handler patterns
587
+ else if (node.methodName.endsWith('_handler') || node.methodName.endsWith('_callback')) {
588
+ confidence = 'low';
589
+ reason = 'Callback/handler (may be invoked by framework)';
590
+ }
591
+ }
592
+ else if (this.isRust(node.language)) {
593
+ // Rust-specific confidence logic
594
+ // Test functions
595
+ if (node.methodName.startsWith('test_') || node.annotations.some(a => a.includes('test'))) {
596
+ confidence = 'low';
597
+ reason = 'Test function (may be called by test runner)';
598
+ }
599
+ // Trait implementations often called implicitly
600
+ else if (['new', 'default', 'from', 'into', 'clone', 'drop', 'deref'].includes(node.methodName)) {
601
+ confidence = 'low';
602
+ reason = 'Trait method (may be called implicitly)';
603
+ }
604
+ // Private functions (not pub)
605
+ else if (!node.modifiers.includes('pub')) {
606
+ confidence = 'high';
607
+ reason = 'Private function not called from any entry point';
608
+ }
609
+ // Public functions in library crates may be external API
610
+ else if (node.modifiers.includes('pub')) {
611
+ confidence = 'medium';
612
+ reason = 'Public function (may be library API)';
613
+ }
614
+ }
615
+ else {
616
+ // Java confidence logic
617
+ // Lower confidence for private methods (may be used via reflection)
618
+ if (node.modifiers.includes('private')) {
619
+ confidence = 'medium';
620
+ reason = 'Private method not called directly (could be reflection)';
621
+ }
622
+ // Lower confidence for methods with certain names
623
+ if (['equals', 'hashCode', 'toString', 'compareTo', 'clone'].includes(node.methodName)) {
624
+ confidence = 'low';
625
+ reason = 'Standard method override (may be called implicitly)';
626
+ }
627
+ }
628
+ deadCode.push({
629
+ type: 'method',
630
+ file: node.file,
631
+ name: node.methodName,
632
+ className: node.className,
633
+ startLine: node.startLine,
634
+ endLine: node.endLine,
635
+ lineCount: node.lineCount,
636
+ reason,
637
+ confidence,
638
+ });
639
+ }
640
+ }
641
+ // Sort by file and line
642
+ deadCode.sort((a, b) => {
643
+ if (a.file !== b.file)
644
+ return a.file.localeCompare(b.file);
645
+ return a.startLine - b.startLine;
646
+ });
647
+ return deadCode;
648
+ }
649
+ /**
650
+ * Generate final result.
651
+ */
652
+ generateResult(files, deadCode, options, startTime) {
653
+ // Calculate summary
654
+ let totalLOC = 0;
655
+ let totalMethods = 0;
656
+ let totalClasses = 0;
657
+ let deadLOC = 0;
658
+ for (const { ir, loc } of files) {
659
+ totalLOC += loc;
660
+ for (const type of ir.types) {
661
+ if (type.kind === 'class')
662
+ totalClasses++;
663
+ totalMethods += type.methods.length;
664
+ }
665
+ }
666
+ const byFile = new Map();
667
+ for (const item of deadCode) {
668
+ deadLOC += item.lineCount;
669
+ if (!byFile.has(item.file)) {
670
+ byFile.set(item.file, { deadMethods: 0, deadClasses: 0, deadLOC: 0 });
671
+ }
672
+ const fileStats = byFile.get(item.file);
673
+ if (item.type === 'method')
674
+ fileStats.deadMethods++;
675
+ if (item.type === 'class')
676
+ fileStats.deadClasses++;
677
+ fileStats.deadLOC += item.lineCount;
678
+ }
679
+ // Generate entry point list
680
+ const entryPointsList = [];
681
+ for (const entryPointId of this.entryPoints) {
682
+ const node = this.methodMap.get(entryPointId);
683
+ if (node) {
684
+ entryPointsList.push({
685
+ type: this.getEntryPointType(node),
686
+ file: node.file,
687
+ className: node.className,
688
+ methodName: node.methodName,
689
+ line: node.startLine,
690
+ reason: this.getEntryPointReason(node),
691
+ });
692
+ }
693
+ }
694
+ return {
695
+ meta: {
696
+ target: options.target,
697
+ timestamp: new Date().toISOString(),
698
+ durationMs: Date.now() - startTime,
699
+ filesAnalyzed: files.length,
700
+ totalMethods,
701
+ totalClasses,
702
+ },
703
+ entryPoints: entryPointsList,
704
+ deadCode,
705
+ summary: {
706
+ totalFiles: files.length,
707
+ totalLOC,
708
+ totalMethods,
709
+ totalClasses,
710
+ deadMethods: deadCode.filter(d => d.type === 'method').length,
711
+ deadClasses: deadCode.filter(d => d.type === 'class').length,
712
+ deadLOC,
713
+ deadPercentage: totalLOC > 0 ? Math.round((deadLOC / totalLOC) * 1000) / 10 : 0,
714
+ byFile: Array.from(byFile.entries()).map(([file, stats]) => ({ file, ...stats })),
715
+ },
716
+ };
717
+ }
718
+ /**
719
+ * Get entry point type.
720
+ */
721
+ getEntryPointType(node) {
722
+ if (this.isJSTS(node.language)) {
723
+ if (node.methodName === '<module-init>')
724
+ return 'export';
725
+ if (node.methodName.endsWith('_handler'))
726
+ return 'handler';
727
+ return 'export';
728
+ }
729
+ if (this.isPython(node.language)) {
730
+ if (node.methodName === '<module-init>')
731
+ return 'export';
732
+ // Route decorators
733
+ if (node.annotations.some(a => a.startsWith('route') || a.startsWith('app.route') ||
734
+ a === 'get' || a === 'post' || a === 'put' || a === 'delete')) {
735
+ return 'handler';
736
+ }
737
+ return 'export';
738
+ }
739
+ if (this.isRust(node.language)) {
740
+ if (node.methodName === 'main')
741
+ return 'main';
742
+ // Async runtime entry points
743
+ if (node.annotations.some(a => a.includes('tokio::main') || a.includes('actix_web::main') ||
744
+ a.includes('rocket::launch'))) {
745
+ return 'main';
746
+ }
747
+ // Route handlers
748
+ if (node.annotations.some(a => a.includes('get') || a.includes('post') || a.includes('put') ||
749
+ a.includes('delete') || a.includes('route'))) {
750
+ return 'handler';
751
+ }
752
+ // Test functions
753
+ if (node.annotations.some(a => a.includes('test'))) {
754
+ return 'annotation';
755
+ }
756
+ // Public functions in lib
757
+ if (node.modifiers.includes('pub')) {
758
+ return 'export';
759
+ }
760
+ return 'public';
761
+ }
762
+ if (node.methodName === 'main')
763
+ return 'main';
764
+ if (node.methodName === '<init>')
765
+ return 'constructor';
766
+ const handlerAnnotations = ['GetMapping', 'PostMapping', 'PutMapping', 'DeleteMapping', 'RequestMapping', 'GET', 'POST', 'PUT', 'DELETE'];
767
+ if (node.annotations.some(a => handlerAnnotations.includes(a)))
768
+ return 'handler';
769
+ if (node.annotations.some(a => ENTRY_POINT_ANNOTATIONS.has(a)))
770
+ return 'annotation';
771
+ return 'public';
772
+ }
773
+ /**
774
+ * Get entry point reason.
775
+ */
776
+ getEntryPointReason(node) {
777
+ if (this.isJSTS(node.language)) {
778
+ if (node.methodName === '<module-init>')
779
+ return 'Module top-level code';
780
+ if (node.methodName.endsWith('_handler')) {
781
+ const verb = node.methodName.replace('_handler', '').toUpperCase();
782
+ return `HTTP route handler (${verb})`;
783
+ }
784
+ return 'Exported function';
785
+ }
786
+ if (this.isPython(node.language)) {
787
+ if (node.methodName === '<module-init>')
788
+ return 'Module top-level code';
789
+ // Route decorators
790
+ if (node.annotations.some(a => a.startsWith('route') || a.startsWith('app.route'))) {
791
+ return 'Flask/Django route handler';
792
+ }
793
+ if (node.annotations.some(a => a === 'get' || a === 'post' || a === 'put' || a === 'delete')) {
794
+ return 'HTTP route handler';
795
+ }
796
+ return 'Exported function';
797
+ }
798
+ if (this.isRust(node.language)) {
799
+ if (node.methodName === 'main')
800
+ return 'Main function';
801
+ // Async runtime entry points
802
+ if (node.annotations.some(a => a.includes('tokio::main'))) {
803
+ return 'Tokio async main';
804
+ }
805
+ if (node.annotations.some(a => a.includes('actix_web::main') || a.includes('actix_rt::main'))) {
806
+ return 'Actix-web main';
807
+ }
808
+ if (node.annotations.some(a => a.includes('rocket::launch'))) {
809
+ return 'Rocket launch';
810
+ }
811
+ // Route handlers
812
+ if (node.annotations.some(a => a.includes('get')))
813
+ return 'HTTP GET handler';
814
+ if (node.annotations.some(a => a.includes('post')))
815
+ return 'HTTP POST handler';
816
+ if (node.annotations.some(a => a.includes('put')))
817
+ return 'HTTP PUT handler';
818
+ if (node.annotations.some(a => a.includes('delete')))
819
+ return 'HTTP DELETE handler';
820
+ if (node.annotations.some(a => a.includes('route')))
821
+ return 'HTTP route handler';
822
+ // Test functions
823
+ if (node.annotations.some(a => a.includes('test'))) {
824
+ return 'Test function';
825
+ }
826
+ // Public functions
827
+ if (node.modifiers.includes('pub')) {
828
+ return 'Public API function';
829
+ }
830
+ return 'Entry point';
831
+ }
832
+ if (node.methodName === 'main')
833
+ return 'Main method';
834
+ if (node.methodName === '<init>')
835
+ return 'Constructor';
836
+ const handlerAnnotations = ['GetMapping', 'PostMapping', 'PutMapping', 'DeleteMapping', 'RequestMapping'];
837
+ const handler = node.annotations.find(a => handlerAnnotations.includes(a));
838
+ if (handler)
839
+ return `HTTP handler (@${handler})`;
840
+ const annotation = node.annotations.find(a => ENTRY_POINT_ANNOTATIONS.has(a));
841
+ if (annotation)
842
+ return `Annotated with @${annotation}`;
843
+ return 'Public method';
844
+ }
845
+ /**
846
+ * Generate method ID.
847
+ */
848
+ getMethodId(file, className, methodName) {
849
+ return `${file}::${className}::${methodName}`;
850
+ }
851
+ /**
852
+ * Detect language from file extension.
853
+ */
854
+ detectLanguage(file) {
855
+ const ext = path.extname(file).toLowerCase();
856
+ switch (ext) {
857
+ case '.java': return 'java';
858
+ case '.c':
859
+ case '.h': return 'c';
860
+ case '.cpp':
861
+ case '.cc':
862
+ case '.cxx':
863
+ case '.hpp': return 'cpp';
864
+ case '.js':
865
+ case '.jsx':
866
+ case '.mjs':
867
+ case '.cjs': return 'javascript';
868
+ case '.ts':
869
+ case '.tsx':
870
+ case '.mts':
871
+ case '.cts': return 'typescript';
872
+ case '.py': return 'python';
873
+ case '.rs': return 'rust';
874
+ default: return 'java';
875
+ }
876
+ }
877
+ /**
878
+ * Check if language is JavaScript or TypeScript.
879
+ */
880
+ isJSTS(lang) {
881
+ return lang === 'javascript' || lang === 'typescript';
882
+ }
883
+ /**
884
+ * Check if language is Python.
885
+ */
886
+ isPython(lang) {
887
+ return lang === 'python';
888
+ }
889
+ /**
890
+ * Check if language is Rust.
891
+ */
892
+ isRust(lang) {
893
+ return lang === 'rust';
894
+ }
895
+ /**
896
+ * Check if language uses module-level entry points (JS/TS/Python).
897
+ */
898
+ isModuleBasedLanguage(lang) {
899
+ return this.isJSTS(lang) || this.isPython(lang);
900
+ }
901
+ /**
902
+ * Report progress.
903
+ */
904
+ reportProgress(progress) {
905
+ if (this.onProgress) {
906
+ this.onProgress(progress);
907
+ }
908
+ if (this.verbose) {
909
+ console.log(`[${progress.phase}] ${progress.filesProcessed}/${progress.totalFiles} ${progress.message || ''}`);
910
+ }
911
+ }
912
+ }
913
+ // ============================================================================
914
+ // Convenience Functions
915
+ // ============================================================================
916
+ /**
917
+ * Detect dead code in a directory or file.
918
+ */
919
+ export async function detectDeadCode(options) {
920
+ const detector = new DeadCodeDetector();
921
+ return detector.detect(options);
922
+ }
923
+ /**
924
+ * Quick dead code detection with default options.
925
+ */
926
+ export async function quickDeadCodeCheck(target) {
927
+ return detectDeadCode({
928
+ target,
929
+ verbose: false,
930
+ publicMethodsAsEntryPoints: false,
931
+ });
932
+ }
933
+ /**
934
+ * Generate a text report from dead code results.
935
+ */
936
+ export function formatDeadCodeReport(result) {
937
+ const lines = [
938
+ '='.repeat(70),
939
+ 'DEAD CODE ANALYSIS REPORT',
940
+ '='.repeat(70),
941
+ '',
942
+ `Target: ${result.meta.target}`,
943
+ `Timestamp: ${result.meta.timestamp}`,
944
+ `Duration: ${(result.meta.durationMs / 1000).toFixed(2)}s`,
945
+ '',
946
+ '-'.repeat(70),
947
+ 'SUMMARY',
948
+ '-'.repeat(70),
949
+ '',
950
+ `Files Analyzed: ${result.summary.totalFiles}`,
951
+ `Total LOC: ${result.summary.totalLOC.toLocaleString()}`,
952
+ `Total Methods: ${result.summary.totalMethods}`,
953
+ `Total Classes: ${result.summary.totalClasses}`,
954
+ '',
955
+ `Dead Methods: ${result.summary.deadMethods}`,
956
+ `Dead Classes: ${result.summary.deadClasses}`,
957
+ `Dead LOC: ${result.summary.deadLOC.toLocaleString()} (${result.summary.deadPercentage}%)`,
958
+ '',
959
+ ];
960
+ if (result.entryPoints.length > 0) {
961
+ lines.push('-'.repeat(70));
962
+ lines.push(`ENTRY POINTS (${result.entryPoints.length})`);
963
+ lines.push('-'.repeat(70));
964
+ lines.push('');
965
+ for (const ep of result.entryPoints.slice(0, 20)) {
966
+ const location = ep.className ? `${ep.className}.${ep.methodName}` : ep.methodName;
967
+ lines.push(` ${ep.type.toUpperCase().padEnd(12)} ${ep.file}:${ep.line} - ${location}`);
968
+ }
969
+ if (result.entryPoints.length > 20) {
970
+ lines.push(` ... and ${result.entryPoints.length - 20} more`);
971
+ }
972
+ lines.push('');
973
+ }
974
+ if (result.deadCode.length > 0) {
975
+ lines.push('-'.repeat(70));
976
+ lines.push(`DEAD CODE (${result.deadCode.length} items)`);
977
+ lines.push('-'.repeat(70));
978
+ lines.push('');
979
+ // Group by file
980
+ const byFile = new Map();
981
+ for (const item of result.deadCode) {
982
+ if (!byFile.has(item.file)) {
983
+ byFile.set(item.file, []);
984
+ }
985
+ byFile.get(item.file).push(item);
986
+ }
987
+ for (const [file, items] of byFile) {
988
+ lines.push(`${file} (${items.length} items, ${items.reduce((sum, i) => sum + i.lineCount, 0)} lines):`);
989
+ for (const item of items.slice(0, 10)) {
990
+ const name = item.className ? `${item.className}.${item.name}` : item.name;
991
+ const conf = item.confidence === 'high' ? '' : ` [${item.confidence}]`;
992
+ lines.push(` L${item.startLine}-${item.endLine}: ${item.type} ${name}${conf}`);
993
+ }
994
+ if (items.length > 10) {
995
+ lines.push(` ... and ${items.length - 10} more`);
996
+ }
997
+ lines.push('');
998
+ }
999
+ }
1000
+ lines.push('='.repeat(70));
1001
+ return lines.join('\n');
1002
+ }
1003
+ //# sourceMappingURL=detector.js.map