codereview-aia 0.1.2 → 0.1.3

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 (427) hide show
  1. package/dist/index.js +0 -2
  2. package/docs/opt-in-full-context.md +27 -0
  3. package/package.json +11 -11
  4. package/reports/cr-cr-aia-17-11-2025-20-13.md +354 -0
  5. package/src/clients/implementations/openRouterClient.ts +2 -0
  6. package/src/clients/openRouterClient.ts +8 -1
  7. package/src/clients/utils/promptFormatter.ts +97 -20
  8. package/src/core/handlers/FileProcessingHandler.ts +6 -0
  9. package/src/index.ts +0 -3
  10. package/src/runtime/cliEntry.ts +21 -3
  11. package/src/runtime/fileCollector.ts +278 -5
  12. package/src/runtime/reviewPipeline.ts +46 -7
  13. package/src/runtime/runAiCodeReview.ts +161 -6
  14. package/src/runtime/ui/RuntimeApp.tsx +34 -5
  15. package/src/runtime/ui/screens/ProgressScreen.tsx +49 -1
  16. package/src/runtime/ui/screens/ResultsScreen.tsx +29 -9
  17. package/src/types/review.ts +18 -0
  18. package/dist/analysis/FindingsExtractor.d.ts +0 -105
  19. package/dist/analysis/FindingsExtractor.js +0 -363
  20. package/dist/analysis/FindingsExtractor.js.map +0 -1
  21. package/dist/analysis/ai-detection/analyzers/BaseAnalyzer.d.ts +0 -111
  22. package/dist/analysis/ai-detection/analyzers/BaseAnalyzer.js +0 -215
  23. package/dist/analysis/ai-detection/analyzers/BaseAnalyzer.js.map +0 -1
  24. package/dist/analysis/ai-detection/analyzers/DocumentationAnalyzer.d.ts +0 -142
  25. package/dist/analysis/ai-detection/analyzers/DocumentationAnalyzer.js +0 -503
  26. package/dist/analysis/ai-detection/analyzers/DocumentationAnalyzer.js.map +0 -1
  27. package/dist/analysis/ai-detection/analyzers/GitHistoryAnalyzer.d.ts +0 -88
  28. package/dist/analysis/ai-detection/analyzers/GitHistoryAnalyzer.js +0 -343
  29. package/dist/analysis/ai-detection/analyzers/GitHistoryAnalyzer.js.map +0 -1
  30. package/dist/analysis/ai-detection/core/AIDetectionEngine.d.ts +0 -104
  31. package/dist/analysis/ai-detection/core/AIDetectionEngine.js +0 -369
  32. package/dist/analysis/ai-detection/core/AIDetectionEngine.js.map +0 -1
  33. package/dist/analysis/ai-detection/types/DetectionTypes.d.ts +0 -364
  34. package/dist/analysis/ai-detection/types/DetectionTypes.js +0 -32
  35. package/dist/analysis/ai-detection/types/DetectionTypes.js.map +0 -1
  36. package/dist/analysis/ai-detection/utils/SubmissionConverter.d.ts +0 -97
  37. package/dist/analysis/ai-detection/utils/SubmissionConverter.js +0 -339
  38. package/dist/analysis/ai-detection/utils/SubmissionConverter.js.map +0 -1
  39. package/dist/analysis/context/ReviewContext.d.ts +0 -184
  40. package/dist/analysis/context/ReviewContext.js +0 -294
  41. package/dist/analysis/context/ReviewContext.js.map +0 -1
  42. package/dist/analysis/context/index.d.ts +0 -6
  43. package/dist/analysis/context/index.js +0 -23
  44. package/dist/analysis/context/index.js.map +0 -1
  45. package/dist/analysis/index.d.ts +0 -7
  46. package/dist/analysis/index.js +0 -24
  47. package/dist/analysis/index.js.map +0 -1
  48. package/dist/analysis/tokens/TokenAnalysisFormatter.d.ts +0 -27
  49. package/dist/analysis/tokens/TokenAnalysisFormatter.js +0 -143
  50. package/dist/analysis/tokens/TokenAnalysisFormatter.js.map +0 -1
  51. package/dist/analysis/tokens/TokenAnalyzer.d.ts +0 -155
  52. package/dist/analysis/tokens/TokenAnalyzer.js +0 -502
  53. package/dist/analysis/tokens/TokenAnalyzer.js.map +0 -1
  54. package/dist/analysis/tokens/index.d.ts +0 -7
  55. package/dist/analysis/tokens/index.js +0 -24
  56. package/dist/analysis/tokens/index.js.map +0 -1
  57. package/dist/clients/base/abstractClient.d.ts +0 -99
  58. package/dist/clients/base/abstractClient.js +0 -98
  59. package/dist/clients/base/abstractClient.js.map +0 -1
  60. package/dist/clients/base/httpClient.d.ts +0 -24
  61. package/dist/clients/base/httpClient.js +0 -147
  62. package/dist/clients/base/httpClient.js.map +0 -1
  63. package/dist/clients/base/index.d.ts +0 -11
  64. package/dist/clients/base/index.js +0 -28
  65. package/dist/clients/base/index.js.map +0 -1
  66. package/dist/clients/base/modelDetection.d.ts +0 -41
  67. package/dist/clients/base/modelDetection.js +0 -88
  68. package/dist/clients/base/modelDetection.js.map +0 -1
  69. package/dist/clients/base/responseProcessor.d.ts +0 -45
  70. package/dist/clients/base/responseProcessor.js +0 -495
  71. package/dist/clients/base/responseProcessor.js.map +0 -1
  72. package/dist/clients/factory/clientFactory.d.ts +0 -23
  73. package/dist/clients/factory/clientFactory.js +0 -50
  74. package/dist/clients/factory/clientFactory.js.map +0 -1
  75. package/dist/clients/factory/index.d.ts +0 -7
  76. package/dist/clients/factory/index.js +0 -24
  77. package/dist/clients/factory/index.js.map +0 -1
  78. package/dist/clients/implementations/index.d.ts +0 -7
  79. package/dist/clients/implementations/index.js +0 -24
  80. package/dist/clients/implementations/index.js.map +0 -1
  81. package/dist/clients/implementations/openRouterClient.d.ts +0 -69
  82. package/dist/clients/implementations/openRouterClient.js +0 -294
  83. package/dist/clients/implementations/openRouterClient.js.map +0 -1
  84. package/dist/clients/openRouterClient.d.ts +0 -42
  85. package/dist/clients/openRouterClient.js +0 -738
  86. package/dist/clients/openRouterClient.js.map +0 -1
  87. package/dist/clients/openRouterClientWrapper.d.ts +0 -22
  88. package/dist/clients/openRouterClientWrapper.js +0 -64
  89. package/dist/clients/openRouterClientWrapper.js.map +0 -1
  90. package/dist/clients/utils/directoryStructure.d.ts +0 -14
  91. package/dist/clients/utils/directoryStructure.js +0 -48
  92. package/dist/clients/utils/directoryStructure.js.map +0 -1
  93. package/dist/clients/utils/index.d.ts +0 -10
  94. package/dist/clients/utils/index.js +0 -31
  95. package/dist/clients/utils/index.js.map +0 -1
  96. package/dist/clients/utils/languageDetection.d.ts +0 -13
  97. package/dist/clients/utils/languageDetection.js +0 -46
  98. package/dist/clients/utils/languageDetection.js.map +0 -1
  99. package/dist/clients/utils/promptFormatter.d.ts +0 -36
  100. package/dist/clients/utils/promptFormatter.js +0 -92
  101. package/dist/clients/utils/promptFormatter.js.map +0 -1
  102. package/dist/clients/utils/promptLoader.d.ts +0 -27
  103. package/dist/clients/utils/promptLoader.js +0 -49
  104. package/dist/clients/utils/promptLoader.js.map +0 -1
  105. package/dist/clients/utils/tokenCounter.d.ts +0 -81
  106. package/dist/clients/utils/tokenCounter.js +0 -209
  107. package/dist/clients/utils/tokenCounter.js.map +0 -1
  108. package/dist/core/ApiClientSelector.d.ts +0 -8
  109. package/dist/core/ApiClientSelector.js +0 -29
  110. package/dist/core/ApiClientSelector.js.map +0 -1
  111. package/dist/core/ConfigurationService.d.ts +0 -286
  112. package/dist/core/ConfigurationService.js +0 -477
  113. package/dist/core/ConfigurationService.js.map +0 -1
  114. package/dist/core/ConsolidationService.d.ts +0 -99
  115. package/dist/core/ConsolidationService.js +0 -341
  116. package/dist/core/ConsolidationService.js.map +0 -1
  117. package/dist/core/InteractiveDisplayManager.d.ts +0 -22
  118. package/dist/core/InteractiveDisplayManager.js +0 -70
  119. package/dist/core/InteractiveDisplayManager.js.map +0 -1
  120. package/dist/core/OutputManager.d.ts +0 -26
  121. package/dist/core/OutputManager.js +0 -217
  122. package/dist/core/OutputManager.js.map +0 -1
  123. package/dist/core/ReviewGenerator.d.ts +0 -13
  124. package/dist/core/ReviewGenerator.js +0 -102
  125. package/dist/core/ReviewGenerator.js.map +0 -1
  126. package/dist/core/fileDiscovery.d.ts +0 -35
  127. package/dist/core/fileDiscovery.js +0 -202
  128. package/dist/core/fileDiscovery.js.map +0 -1
  129. package/dist/core/handlers/EstimationHandler.d.ts +0 -18
  130. package/dist/core/handlers/EstimationHandler.js +0 -110
  131. package/dist/core/handlers/EstimationHandler.js.map +0 -1
  132. package/dist/core/handlers/FileProcessingHandler.d.ts +0 -31
  133. package/dist/core/handlers/FileProcessingHandler.js +0 -159
  134. package/dist/core/handlers/FileProcessingHandler.js.map +0 -1
  135. package/dist/core/handlers/OutputHandler.d.ts +0 -27
  136. package/dist/core/handlers/OutputHandler.js +0 -127
  137. package/dist/core/handlers/OutputHandler.js.map +0 -1
  138. package/dist/core/handlers/ReviewExecutor.d.ts +0 -32
  139. package/dist/core/handlers/ReviewExecutor.js +0 -111
  140. package/dist/core/handlers/ReviewExecutor.js.map +0 -1
  141. package/dist/core/reviewOrchestrator.d.ts +0 -24
  142. package/dist/core/reviewOrchestrator.js +0 -294
  143. package/dist/core/reviewOrchestrator.js.map +0 -1
  144. package/dist/core/utils/ModelInfoUtils.d.ts +0 -16
  145. package/dist/core/utils/ModelInfoUtils.js +0 -54
  146. package/dist/core/utils/ModelInfoUtils.js.map +0 -1
  147. package/dist/formatters/outputFormatter.d.ts +0 -31
  148. package/dist/formatters/outputFormatter.js +0 -65
  149. package/dist/formatters/outputFormatter.js.map +0 -1
  150. package/dist/formatters/utils/IssueFormatters.d.ts +0 -20
  151. package/dist/formatters/utils/IssueFormatters.js +0 -67
  152. package/dist/formatters/utils/IssueFormatters.js.map +0 -1
  153. package/dist/formatters/utils/JsonFormatter.d.ts +0 -13
  154. package/dist/formatters/utils/JsonFormatter.js +0 -57
  155. package/dist/formatters/utils/JsonFormatter.js.map +0 -1
  156. package/dist/formatters/utils/MarkdownFormatters.d.ts +0 -51
  157. package/dist/formatters/utils/MarkdownFormatters.js +0 -456
  158. package/dist/formatters/utils/MarkdownFormatters.js.map +0 -1
  159. package/dist/formatters/utils/MetadataFormatter.d.ts +0 -65
  160. package/dist/formatters/utils/MetadataFormatter.js +0 -219
  161. package/dist/formatters/utils/MetadataFormatter.js.map +0 -1
  162. package/dist/formatters/utils/ModelInfoExtractor.d.ts +0 -33
  163. package/dist/formatters/utils/ModelInfoExtractor.js +0 -111
  164. package/dist/formatters/utils/ModelInfoExtractor.js.map +0 -1
  165. package/dist/index.d.ts +0 -2
  166. package/dist/index.js.map +0 -1
  167. package/dist/plugins/PluginInterface.d.ts +0 -44
  168. package/dist/plugins/PluginInterface.js +0 -9
  169. package/dist/plugins/PluginInterface.js.map +0 -1
  170. package/dist/plugins/PluginManager.d.ts +0 -51
  171. package/dist/plugins/PluginManager.js +0 -151
  172. package/dist/plugins/PluginManager.js.map +0 -1
  173. package/dist/prompts/PromptManager.d.ts +0 -30
  174. package/dist/prompts/PromptManager.js +0 -62
  175. package/dist/prompts/PromptManager.js.map +0 -1
  176. package/dist/prompts/cache/PromptCache.d.ts +0 -32
  177. package/dist/prompts/cache/PromptCache.js +0 -48
  178. package/dist/prompts/cache/PromptCache.js.map +0 -1
  179. package/dist/runtime/auth/service.d.ts +0 -2
  180. package/dist/runtime/auth/service.js +0 -41
  181. package/dist/runtime/auth/service.js.map +0 -1
  182. package/dist/runtime/auth/session.d.ts +0 -5
  183. package/dist/runtime/auth/session.js +0 -87
  184. package/dist/runtime/auth/session.js.map +0 -1
  185. package/dist/runtime/auth/types.d.ts +0 -9
  186. package/dist/runtime/auth/types.js +0 -3
  187. package/dist/runtime/auth/types.js.map +0 -1
  188. package/dist/runtime/cliEntry.d.ts +0 -1
  189. package/dist/runtime/cliEntry.js +0 -213
  190. package/dist/runtime/cliEntry.js.map +0 -1
  191. package/dist/runtime/debug/logManager.d.ts +0 -5
  192. package/dist/runtime/debug/logManager.js +0 -31
  193. package/dist/runtime/debug/logManager.js.map +0 -1
  194. package/dist/runtime/errors.d.ts +0 -5
  195. package/dist/runtime/errors.js +0 -15
  196. package/dist/runtime/errors.js.map +0 -1
  197. package/dist/runtime/fileCollector.d.ts +0 -5
  198. package/dist/runtime/fileCollector.js +0 -167
  199. package/dist/runtime/fileCollector.js.map +0 -1
  200. package/dist/runtime/manifest.d.ts +0 -1
  201. package/dist/runtime/manifest.js +0 -65
  202. package/dist/runtime/manifest.js.map +0 -1
  203. package/dist/runtime/openrouterProxy.d.ts +0 -4
  204. package/dist/runtime/openrouterProxy.js +0 -43
  205. package/dist/runtime/openrouterProxy.js.map +0 -1
  206. package/dist/runtime/preprod/webCheck.d.ts +0 -1
  207. package/dist/runtime/preprod/webCheck.js +0 -98
  208. package/dist/runtime/preprod/webCheck.js.map +0 -1
  209. package/dist/runtime/proxyConfig.d.ts +0 -6
  210. package/dist/runtime/proxyConfig.js +0 -86
  211. package/dist/runtime/proxyConfig.js.map +0 -1
  212. package/dist/runtime/proxyEnvironment.d.ts +0 -3
  213. package/dist/runtime/proxyEnvironment.js +0 -63
  214. package/dist/runtime/proxyEnvironment.js.map +0 -1
  215. package/dist/runtime/reportMerge.d.ts +0 -30
  216. package/dist/runtime/reportMerge.js +0 -70
  217. package/dist/runtime/reportMerge.js.map +0 -1
  218. package/dist/runtime/reporting/markdownReportBuilder.d.ts +0 -15
  219. package/dist/runtime/reporting/markdownReportBuilder.js +0 -97
  220. package/dist/runtime/reporting/markdownReportBuilder.js.map +0 -1
  221. package/dist/runtime/reporting/reportDataCollector.d.ts +0 -31
  222. package/dist/runtime/reporting/reportDataCollector.js +0 -170
  223. package/dist/runtime/reporting/reportDataCollector.js.map +0 -1
  224. package/dist/runtime/reporting/summaryGenerator.d.ts +0 -10
  225. package/dist/runtime/reporting/summaryGenerator.js +0 -67
  226. package/dist/runtime/reporting/summaryGenerator.js.map +0 -1
  227. package/dist/runtime/reviewPipeline.d.ts +0 -28
  228. package/dist/runtime/reviewPipeline.js +0 -122
  229. package/dist/runtime/reviewPipeline.js.map +0 -1
  230. package/dist/runtime/runAiCodeReview.d.ts +0 -10
  231. package/dist/runtime/runAiCodeReview.js +0 -138
  232. package/dist/runtime/runAiCodeReview.js.map +0 -1
  233. package/dist/runtime/runtimeConfig.d.ts +0 -4
  234. package/dist/runtime/runtimeConfig.js +0 -7
  235. package/dist/runtime/runtimeConfig.js.map +0 -1
  236. package/dist/runtime/ui/Layout.d.ts +0 -11
  237. package/dist/runtime/ui/Layout.js +0 -47
  238. package/dist/runtime/ui/Layout.js.map +0 -1
  239. package/dist/runtime/ui/RuntimeApp.d.ts +0 -6
  240. package/dist/runtime/ui/RuntimeApp.js +0 -161
  241. package/dist/runtime/ui/RuntimeApp.js.map +0 -1
  242. package/dist/runtime/ui/inkModules.d.ts +0 -10
  243. package/dist/runtime/ui/inkModules.js +0 -63
  244. package/dist/runtime/ui/inkModules.js.map +0 -1
  245. package/dist/runtime/ui/screens/AuthScreen.d.ts +0 -6
  246. package/dist/runtime/ui/screens/AuthScreen.js +0 -67
  247. package/dist/runtime/ui/screens/AuthScreen.js.map +0 -1
  248. package/dist/runtime/ui/screens/ModeSelection.d.ts +0 -10
  249. package/dist/runtime/ui/screens/ModeSelection.js +0 -100
  250. package/dist/runtime/ui/screens/ModeSelection.js.map +0 -1
  251. package/dist/runtime/ui/screens/ProgressScreen.d.ts +0 -7
  252. package/dist/runtime/ui/screens/ProgressScreen.js +0 -38
  253. package/dist/runtime/ui/screens/ProgressScreen.js.map +0 -1
  254. package/dist/runtime/ui/screens/ResultsScreen.d.ts +0 -7
  255. package/dist/runtime/ui/screens/ResultsScreen.js +0 -22
  256. package/dist/runtime/ui/screens/ResultsScreen.js.map +0 -1
  257. package/dist/strategies/ArchitecturalReviewStrategy.d.ts +0 -29
  258. package/dist/strategies/ArchitecturalReviewStrategy.js +0 -42
  259. package/dist/strategies/ArchitecturalReviewStrategy.js.map +0 -1
  260. package/dist/strategies/CodingTestReviewStrategy.d.ts +0 -194
  261. package/dist/strategies/CodingTestReviewStrategy.js +0 -681
  262. package/dist/strategies/CodingTestReviewStrategy.js.map +0 -1
  263. package/dist/strategies/ConsolidatedReviewStrategy.d.ts +0 -25
  264. package/dist/strategies/ConsolidatedReviewStrategy.js +0 -45
  265. package/dist/strategies/ConsolidatedReviewStrategy.js.map +0 -1
  266. package/dist/strategies/ExtractPatternsReviewStrategy.d.ts +0 -30
  267. package/dist/strategies/ExtractPatternsReviewStrategy.js +0 -51
  268. package/dist/strategies/ExtractPatternsReviewStrategy.js.map +0 -1
  269. package/dist/strategies/MultiPassReviewStrategy.d.ts +0 -86
  270. package/dist/strategies/MultiPassReviewStrategy.js +0 -590
  271. package/dist/strategies/MultiPassReviewStrategy.js.map +0 -1
  272. package/dist/strategies/ReviewStrategy.d.ts +0 -45
  273. package/dist/strategies/ReviewStrategy.js +0 -24
  274. package/dist/strategies/ReviewStrategy.js.map +0 -1
  275. package/dist/strategies/StrategyFactory.d.ts +0 -19
  276. package/dist/strategies/StrategyFactory.js +0 -72
  277. package/dist/strategies/StrategyFactory.js.map +0 -1
  278. package/dist/strategies/index.d.ts +0 -13
  279. package/dist/strategies/index.js +0 -30
  280. package/dist/strategies/index.js.map +0 -1
  281. package/dist/tokenizers/baseTokenizer.d.ts +0 -25
  282. package/dist/tokenizers/baseTokenizer.js +0 -48
  283. package/dist/tokenizers/baseTokenizer.js.map +0 -1
  284. package/dist/tokenizers/gptTokenizer.d.ts +0 -7
  285. package/dist/tokenizers/gptTokenizer.js +0 -28
  286. package/dist/tokenizers/gptTokenizer.js.map +0 -1
  287. package/dist/tokenizers/index.d.ts +0 -7
  288. package/dist/tokenizers/index.js +0 -24
  289. package/dist/tokenizers/index.js.map +0 -1
  290. package/dist/types/apiResponses.d.ts +0 -39
  291. package/dist/types/apiResponses.js +0 -9
  292. package/dist/types/apiResponses.js.map +0 -1
  293. package/dist/types/cli.d.ts +0 -22
  294. package/dist/types/cli.js +0 -3
  295. package/dist/types/cli.js.map +0 -1
  296. package/dist/types/common.d.ts +0 -22
  297. package/dist/types/common.js +0 -14
  298. package/dist/types/common.js.map +0 -1
  299. package/dist/types/configuration.d.ts +0 -682
  300. package/dist/types/configuration.js +0 -65
  301. package/dist/types/configuration.js.map +0 -1
  302. package/dist/types/review.d.ts +0 -258
  303. package/dist/types/review.js +0 -8
  304. package/dist/types/review.js.map +0 -1
  305. package/dist/types/reviewSchema.d.ts +0 -543
  306. package/dist/types/reviewSchema.js +0 -121
  307. package/dist/types/reviewSchema.js.map +0 -1
  308. package/dist/types/structuredReview.d.ts +0 -119
  309. package/dist/types/structuredReview.js +0 -6
  310. package/dist/types/structuredReview.js.map +0 -1
  311. package/dist/types/tokenAnalysis.d.ts +0 -44
  312. package/dist/types/tokenAnalysis.js +0 -4
  313. package/dist/types/tokenAnalysis.js.map +0 -1
  314. package/dist/utils/FileReader.d.ts +0 -33
  315. package/dist/utils/FileReader.js +0 -88
  316. package/dist/utils/FileReader.js.map +0 -1
  317. package/dist/utils/FileWriter.d.ts +0 -26
  318. package/dist/utils/FileWriter.js +0 -76
  319. package/dist/utils/FileWriter.js.map +0 -1
  320. package/dist/utils/PathGenerator.d.ts +0 -30
  321. package/dist/utils/PathGenerator.js +0 -82
  322. package/dist/utils/PathGenerator.js.map +0 -1
  323. package/dist/utils/api/apiUtils.d.ts +0 -3
  324. package/dist/utils/api/apiUtils.js +0 -20
  325. package/dist/utils/api/apiUtils.js.map +0 -1
  326. package/dist/utils/api/index.d.ts +0 -1
  327. package/dist/utils/api/index.js +0 -18
  328. package/dist/utils/api/index.js.map +0 -1
  329. package/dist/utils/apiErrorHandler.d.ts +0 -130
  330. package/dist/utils/apiErrorHandler.js +0 -256
  331. package/dist/utils/apiErrorHandler.js.map +0 -1
  332. package/dist/utils/ciDataCollector.d.ts +0 -51
  333. package/dist/utils/ciDataCollector.js +0 -197
  334. package/dist/utils/ciDataCollector.js.map +0 -1
  335. package/dist/utils/codingTestConfigLoader.d.ts +0 -66
  336. package/dist/utils/codingTestConfigLoader.js +0 -420
  337. package/dist/utils/codingTestConfigLoader.js.map +0 -1
  338. package/dist/utils/dependencies/aiDependencyAnalyzer.d.ts +0 -30
  339. package/dist/utils/dependencies/aiDependencyAnalyzer.js +0 -343
  340. package/dist/utils/dependencies/aiDependencyAnalyzer.js.map +0 -1
  341. package/dist/utils/detection/frameworkDetector.d.ts +0 -43
  342. package/dist/utils/detection/frameworkDetector.js +0 -795
  343. package/dist/utils/detection/frameworkDetector.js.map +0 -1
  344. package/dist/utils/detection/index.d.ts +0 -9
  345. package/dist/utils/detection/index.js +0 -28
  346. package/dist/utils/detection/index.js.map +0 -1
  347. package/dist/utils/detection/projectTypeDetector.d.ts +0 -27
  348. package/dist/utils/detection/projectTypeDetector.js +0 -469
  349. package/dist/utils/detection/projectTypeDetector.js.map +0 -1
  350. package/dist/utils/diagramGenerator.d.ts +0 -49
  351. package/dist/utils/diagramGenerator.js +0 -218
  352. package/dist/utils/diagramGenerator.js.map +0 -1
  353. package/dist/utils/errorLogger.d.ts +0 -24
  354. package/dist/utils/errorLogger.js +0 -59
  355. package/dist/utils/errorLogger.js.map +0 -1
  356. package/dist/utils/estimationUtils.d.ts +0 -139
  357. package/dist/utils/estimationUtils.js +0 -329
  358. package/dist/utils/estimationUtils.js.map +0 -1
  359. package/dist/utils/fileFilters.d.ts +0 -72
  360. package/dist/utils/fileFilters.js +0 -338
  361. package/dist/utils/fileFilters.js.map +0 -1
  362. package/dist/utils/fileSystem.d.ts +0 -22
  363. package/dist/utils/fileSystem.js +0 -45
  364. package/dist/utils/fileSystem.js.map +0 -1
  365. package/dist/utils/index.d.ts +0 -22
  366. package/dist/utils/index.js +0 -52
  367. package/dist/utils/index.js.map +0 -1
  368. package/dist/utils/logger.d.ts +0 -77
  369. package/dist/utils/logger.js +0 -271
  370. package/dist/utils/logger.js.map +0 -1
  371. package/dist/utils/pathValidator.d.ts +0 -40
  372. package/dist/utils/pathValidator.js +0 -98
  373. package/dist/utils/pathValidator.js.map +0 -1
  374. package/dist/utils/priorityFilter.d.ts +0 -34
  375. package/dist/utils/priorityFilter.js +0 -54
  376. package/dist/utils/priorityFilter.js.map +0 -1
  377. package/dist/utils/projectDocs.d.ts +0 -47
  378. package/dist/utils/projectDocs.js +0 -158
  379. package/dist/utils/projectDocs.js.map +0 -1
  380. package/dist/utils/promptPaths.d.ts +0 -6
  381. package/dist/utils/promptPaths.js +0 -33
  382. package/dist/utils/promptPaths.js.map +0 -1
  383. package/dist/utils/promptTemplateManager.d.ts +0 -34
  384. package/dist/utils/promptTemplateManager.js +0 -140
  385. package/dist/utils/promptTemplateManager.js.map +0 -1
  386. package/dist/utils/review/consolidateReview.d.ts +0 -15
  387. package/dist/utils/review/consolidateReview.js +0 -481
  388. package/dist/utils/review/consolidateReview.js.map +0 -1
  389. package/dist/utils/review/fixDisplay.d.ts +0 -20
  390. package/dist/utils/review/fixDisplay.js +0 -84
  391. package/dist/utils/review/fixDisplay.js.map +0 -1
  392. package/dist/utils/review/fixImplementation.d.ts +0 -28
  393. package/dist/utils/review/fixImplementation.js +0 -60
  394. package/dist/utils/review/fixImplementation.js.map +0 -1
  395. package/dist/utils/review/index.d.ts +0 -13
  396. package/dist/utils/review/index.js +0 -50
  397. package/dist/utils/review/index.js.map +0 -1
  398. package/dist/utils/review/interactiveProcessing.d.ts +0 -25
  399. package/dist/utils/review/interactiveProcessing.js +0 -251
  400. package/dist/utils/review/interactiveProcessing.js.map +0 -1
  401. package/dist/utils/review/progressTracker.d.ts +0 -106
  402. package/dist/utils/review/progressTracker.js +0 -227
  403. package/dist/utils/review/progressTracker.js.map +0 -1
  404. package/dist/utils/review/reviewExtraction.d.ts +0 -31
  405. package/dist/utils/review/reviewExtraction.js +0 -324
  406. package/dist/utils/review/reviewExtraction.js.map +0 -1
  407. package/dist/utils/review/types.d.ts +0 -45
  408. package/dist/utils/review/types.js +0 -18
  409. package/dist/utils/review/types.js.map +0 -1
  410. package/dist/utils/reviewActionHandler.d.ts +0 -16
  411. package/dist/utils/reviewActionHandler.js +0 -34
  412. package/dist/utils/reviewActionHandler.js.map +0 -1
  413. package/dist/utils/reviewParser.d.ts +0 -34
  414. package/dist/utils/reviewParser.js +0 -218
  415. package/dist/utils/reviewParser.js.map +0 -1
  416. package/dist/utils/sanitizer.d.ts +0 -82
  417. package/dist/utils/sanitizer.js +0 -239
  418. package/dist/utils/sanitizer.js.map +0 -1
  419. package/dist/utils/smartFileSelector.d.ts +0 -50
  420. package/dist/utils/smartFileSelector.js +0 -261
  421. package/dist/utils/smartFileSelector.js.map +0 -1
  422. package/dist/utils/templateLoader.d.ts +0 -44
  423. package/dist/utils/templateLoader.js +0 -431
  424. package/dist/utils/templateLoader.js.map +0 -1
  425. package/dist/utils/treeGenerator.d.ts +0 -12
  426. package/dist/utils/treeGenerator.js +0 -133
  427. package/dist/utils/treeGenerator.js.map +0 -1
package/src/index.ts CHANGED
@@ -1,10 +1,7 @@
1
- #!/usr/bin/env node
2
1
  import logger from './utils/logger';
3
2
  import { ensureProxyEnvironmentInitialized } from './runtime/proxyEnvironment';
4
3
  import { handleRuntimeCliEntry } from './runtime/cliEntry';
5
4
 
6
- // Minimal bootstrap that wires the runtime CLI into the proxy-enabled environment.
7
-
8
5
  async function bootstrap(): Promise<void> {
9
6
  try {
10
7
  ensureProxyEnvironmentInitialized(process.cwd());
@@ -164,12 +164,30 @@ async function runDirect(options: DirectOptions): Promise<void> {
164
164
  switch (stage) {
165
165
  case 'collecting':
166
166
  if (info?.filesFound !== undefined) {
167
- console.log(pc.green(`✓ Found ${info.filesFound} files`));
167
+ const uncommitted = info.uncommittedFiles ?? info.filesFound;
168
+ const context = info.contextFiles ?? 0;
169
+ const breakdown = context ? ` (${uncommitted} uncommitted + ${context} context)` : '';
170
+ console.log(pc.green(`✓ Found ${info.filesFound} files${breakdown}`));
168
171
  }
169
172
  break;
170
- case 'reviewing':
171
- console.log(pc.blue('Running AI review...'));
173
+ case 'reviewing': {
174
+ const context = info?.contextFiles ?? 0;
175
+ const base = info?.uncommittedFiles ?? info?.filesFound;
176
+ const suffix =
177
+ base || context
178
+ ? ` (scope: ${base ?? '?'} uncommitted${context ? ` + ${context} context` : ''})`
179
+ : '';
180
+ const defaultLine = `Running AI review${suffix ? suffix : ''}...`;
181
+ const detailLine =
182
+ typeof info?.fileIndex === 'number' &&
183
+ typeof info.totalFiles === 'number' &&
184
+ info.totalFiles > 0 &&
185
+ info.currentFile
186
+ ? `Running AI review ▸ ${info.fileIndex}/${info.totalFiles} ${info.currentFile}${suffix}`
187
+ : defaultLine;
188
+ console.log(pc.blue(detailLine));
172
189
  break;
190
+ }
173
191
  case 'merging':
174
192
  console.log(pc.blue('Merging reports...'));
175
193
  break;
@@ -1,15 +1,32 @@
1
- import { existsSync, statSync } from 'node:fs';
2
- import { relative as relativePath, resolve as resolvePath, isAbsolute as isAbsolutePath, join as joinPath } from 'node:path';
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import {
3
+ relative as relativePath,
4
+ resolve as resolvePath,
5
+ isAbsolute as isAbsolutePath,
6
+ join as joinPath,
7
+ dirname as dirnamePath,
8
+ } from 'node:path';
3
9
  import { execa } from 'execa';
4
10
  import { MissingCrIgnoreError } from './errors';
5
11
 
12
+ export interface FileCollectionStats {
13
+ uncommitted: number;
14
+ context: number;
15
+ }
16
+
17
+ export interface FileCollectionResult {
18
+ targets: string[];
19
+ context: string[];
20
+ stats: FileCollectionStats;
21
+ }
22
+
6
23
  export type FileCollectionMode = 'uncommitted' | 'preprod';
7
24
 
8
25
  export interface CollectFilesOptions {
9
26
  mode?: FileCollectionMode;
10
27
  }
11
28
 
12
- export async function collectFiles(options: CollectFilesOptions = {}): Promise<string[]> {
29
+ export async function collectFiles(options: CollectFilesOptions = {}): Promise<FileCollectionResult> {
13
30
  try {
14
31
  const { stdout: rootOut } = await execa('git', ['rev-parse', '--show-toplevel']);
15
32
  const repoRoot = resolvePath(rootOut.trim());
@@ -115,8 +132,22 @@ export async function collectFiles(options: CollectFilesOptions = {}): Promise<s
115
132
  .map((file) => normalize(file))
116
133
  .filter((file): file is string => Boolean(file));
117
134
 
118
- const gitFiltered = await excludeIgnored(repoRoot, resolved);
119
- return await excludeCrIgnored(workspaceRoot, crIgnorePath, gitFiltered);
135
+ const baseSet = new Set(resolved);
136
+ const { combinedFiles, extras } = await augmentWithContext(resolved, workspaceRoot);
137
+ const extraSet = new Set(extras);
138
+
139
+ const gitFiltered = await excludeIgnored(repoRoot, combinedFiles);
140
+ const finalFiles = await excludeCrIgnored(workspaceRoot, crIgnorePath, gitFiltered);
141
+
142
+ const targets = finalFiles.filter((file) => baseSet.has(file));
143
+ const contextFiles = finalFiles.filter((file) => extraSet.has(file) && !baseSet.has(file));
144
+
145
+ const stats: FileCollectionStats = {
146
+ uncommitted: targets.length,
147
+ context: contextFiles.length,
148
+ };
149
+
150
+ return { targets, context: contextFiles, stats };
120
151
  } catch (error: any) {
121
152
  if (error.message?.includes('not a git repository')) {
122
153
  throw new Error('Not a git repository. Please run this command from a git repository root.');
@@ -125,6 +156,248 @@ export async function collectFiles(options: CollectFilesOptions = {}): Promise<s
125
156
  }
126
157
  }
127
158
 
159
+ const CONTEXT_FILENAMES = [
160
+ 'README.md',
161
+ 'readme.md',
162
+ 'README',
163
+ 'README.mdx',
164
+ 'CHANGELOG.md',
165
+ 'changelog.md',
166
+ 'HISTORY.md',
167
+ 'history.md',
168
+ 'package.json',
169
+ '.env.example',
170
+ '.env.sample',
171
+ '.env.template',
172
+ '.env.local.example',
173
+ '.env.production.example',
174
+ ];
175
+
176
+ const DEPENDENCY_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts'];
177
+ const MAX_CONTEXT_FILE_BYTES = 200 * 1024; // 200KB guardrail
178
+
179
+ async function augmentWithContext(
180
+ files: string[],
181
+ workspaceRoot: string,
182
+ ): Promise<{ combinedFiles: string[]; extras: string[] }> {
183
+ if (files.length === 0) {
184
+ return { combinedFiles: files, extras: [] };
185
+ }
186
+
187
+ const baseSet = new Set(files);
188
+ const contextFiles = collectContextFiles(files, workspaceRoot);
189
+ const dependencyFiles = collectDependencyFiles(files, workspaceRoot);
190
+ const localMarkdownFiles = collectLocalMarkdownFiles(files);
191
+ const globalNamedFiles = await collectGlobalNamedContext(workspaceRoot);
192
+
193
+ const extras = Array.from(
194
+ new Set(
195
+ [...contextFiles, ...dependencyFiles, ...localMarkdownFiles, ...globalNamedFiles].filter(
196
+ (file) => !baseSet.has(file),
197
+ ),
198
+ ),
199
+ );
200
+
201
+ const combinedFiles = Array.from(new Set([...files, ...extras]));
202
+ return { combinedFiles, extras };
203
+ }
204
+
205
+ function collectContextFiles(files: string[], workspaceRoot: string): string[] {
206
+ const extras = new Set<string>();
207
+ const candidateDirs = new Set<string>();
208
+ files.forEach((file) => candidateDirs.add(dirnamePath(file)));
209
+ candidateDirs.add(workspaceRoot);
210
+
211
+ for (const dir of candidateDirs) {
212
+ for (const filename of CONTEXT_FILENAMES) {
213
+ const candidate = joinPath(dir, filename);
214
+ if (!candidate.startsWith(workspaceRoot)) {
215
+ continue;
216
+ }
217
+ try {
218
+ const stats = statSync(candidate);
219
+ if (stats.isFile() && stats.size <= MAX_CONTEXT_FILE_BYTES && isTextFile(candidate)) {
220
+ extras.add(candidate);
221
+ }
222
+ } catch {
223
+ // ignored
224
+ }
225
+ }
226
+ }
227
+
228
+ return Array.from(extras);
229
+ }
230
+
231
+ function collectDependencyFiles(files: string[], workspaceRoot: string): string[] {
232
+ const extras = new Set<string>();
233
+
234
+ for (const file of files) {
235
+ if (!isDependencyCandidate(file)) {
236
+ continue;
237
+ }
238
+
239
+ let content: string;
240
+ try {
241
+ content = readFileSync(file, 'utf-8');
242
+ } catch {
243
+ continue;
244
+ }
245
+
246
+ const specifiers = extractImportSpecifiers(content);
247
+ if (specifiers.length === 0) {
248
+ continue;
249
+ }
250
+
251
+ const baseDir = dirnamePath(file);
252
+ for (const specifier of specifiers) {
253
+ const resolved = resolveImportSpecifier(specifier, baseDir, workspaceRoot);
254
+ if (resolved) {
255
+ extras.add(resolved);
256
+ }
257
+ }
258
+ }
259
+
260
+ return Array.from(extras);
261
+ }
262
+
263
+ function isDependencyCandidate(filePath: string): boolean {
264
+ const lower = filePath.toLowerCase();
265
+ return DEPENDENCY_EXTENSIONS.some((ext) => lower.endsWith(ext));
266
+ }
267
+
268
+ function extractImportSpecifiers(content: string): string[] {
269
+ const specifiers = new Set<string>();
270
+ const patterns = [
271
+ /import\s+[^;]*?from\s+['"]([^'"\n]+)['"]/g,
272
+ /import\s+['"]([^'"\n]+)['"]/g,
273
+ /export\s+[^;]*?from\s+['"]([^'"\n]+)['"]/g,
274
+ /require\(\s*['"]([^'"\n]+)['"]\s*\)/g,
275
+ /import\(\s*['"]([^'"\n]+)['"]\s*\)/g,
276
+ ];
277
+
278
+ for (const pattern of patterns) {
279
+ let match: RegExpExecArray | null;
280
+ while ((match = pattern.exec(content)) !== null) {
281
+ const spec = match[1];
282
+ if (spec && spec.startsWith('.')) {
283
+ specifiers.add(spec);
284
+ }
285
+ }
286
+ }
287
+
288
+ return Array.from(specifiers);
289
+ }
290
+
291
+ function resolveImportSpecifier(
292
+ specifier: string,
293
+ baseDir: string,
294
+ workspaceRoot: string,
295
+ ): string | null {
296
+ const cleaned = specifier.replace(/[#?].*$/, '');
297
+ const resolvedBase = resolvePath(baseDir, cleaned);
298
+ const candidates = new Set<string>([resolvedBase]);
299
+
300
+ const hasExtension = DEPENDENCY_EXTENSIONS.some((ext) => resolvedBase.endsWith(ext));
301
+ if (!hasExtension) {
302
+ for (const ext of DEPENDENCY_EXTENSIONS) {
303
+ candidates.add(`${resolvedBase}${ext}`);
304
+ candidates.add(joinPath(resolvedBase, `index${ext}`));
305
+ }
306
+ }
307
+
308
+ for (const candidate of candidates) {
309
+ if (!candidate.startsWith(workspaceRoot)) {
310
+ continue;
311
+ }
312
+ try {
313
+ const stats = statSync(candidate);
314
+ if (stats.isFile()) {
315
+ return candidate;
316
+ }
317
+ } catch {
318
+ continue;
319
+ }
320
+ }
321
+
322
+ return null;
323
+ }
324
+
325
+ function collectLocalMarkdownFiles(files: string[]): string[] {
326
+ const extras = new Set<string>();
327
+ const dirs = new Set<string>();
328
+ files.forEach((file) => dirs.add(dirnamePath(file)));
329
+
330
+ for (const dir of dirs) {
331
+ let entries;
332
+ try {
333
+ entries = readdirSync(dir, { withFileTypes: true });
334
+ } catch {
335
+ continue;
336
+ }
337
+
338
+ for (const entry of entries) {
339
+ if (!entry.isFile()) {
340
+ continue;
341
+ }
342
+
343
+ const lower = entry.name.toLowerCase();
344
+ if (!lower.endsWith('.md') && !lower.endsWith('.mdx')) {
345
+ continue;
346
+ }
347
+
348
+ const fullPath = joinPath(dir, entry.name);
349
+ try {
350
+ const stats = statSync(fullPath);
351
+ if (stats.isFile() && stats.size <= MAX_CONTEXT_FILE_BYTES && isTextFile(fullPath)) {
352
+ extras.add(fullPath);
353
+ }
354
+ } catch {
355
+ continue;
356
+ }
357
+ }
358
+ }
359
+
360
+ return Array.from(extras);
361
+ }
362
+
363
+ async function collectGlobalNamedContext(workspaceRoot: string): Promise<string[]> {
364
+ try {
365
+ const pathspecs = CONTEXT_FILENAMES.map((name) => `:(glob)**/${name}`);
366
+ const { stdout } = await execa('git', ['ls-files', '-z', '--', ...pathspecs], {
367
+ cwd: workspaceRoot,
368
+ reject: false,
369
+ });
370
+ if (!stdout) {
371
+ return [];
372
+ }
373
+
374
+ return stdout
375
+ .split('\0')
376
+ .filter(Boolean)
377
+ .map((rel) => resolvePath(workspaceRoot, rel))
378
+ .filter((abs) => {
379
+ try {
380
+ const stats = statSync(abs);
381
+ return stats.isFile() && stats.size <= MAX_CONTEXT_FILE_BYTES && isTextFile(abs);
382
+ } catch {
383
+ return false;
384
+ }
385
+ });
386
+ } catch {
387
+ return [];
388
+ }
389
+ }
390
+
391
+ function isTextFile(filePath: string): boolean {
392
+ try {
393
+ const buffer = readFileSync(filePath);
394
+ const sample = buffer.subarray(0, 4096);
395
+ return !sample.includes(0);
396
+ } catch {
397
+ return false;
398
+ }
399
+ }
400
+
128
401
  async function listTrackedFiles(repoRoot: string, pathSpec: string): Promise<string[]> {
129
402
  const { stdout } = await execa('git', ['ls-files', '-z', '--', pathSpec], {
130
403
  cwd: repoRoot,
@@ -15,13 +15,22 @@ import logger from '../utils/logger';
15
15
  export type ReviewStage = 'preparing' | 'collecting' | 'reviewing' | 'merging';
16
16
  export type ReviewMode = FileCollectionMode;
17
17
 
18
+ export interface StageUpdate {
19
+ filesFound?: number;
20
+ currentFile?: string;
21
+ fileIndex?: number;
22
+ totalFiles?: number;
23
+ uncommittedFiles?: number;
24
+ contextFiles?: number;
25
+ }
26
+
18
27
  export interface ReviewOptions {
19
28
  model: string;
20
29
  outDir: string;
21
30
  debug?: boolean;
22
31
  mode?: ReviewMode;
23
32
  preprodTargetUrl?: string;
24
- onStage?: (stage: ReviewStage, info?: { filesFound?: number }) => void;
33
+ onStage?: (stage: ReviewStage, info?: StageUpdate) => void;
25
34
  }
26
35
 
27
36
  export interface ReviewTotals {
@@ -37,6 +46,8 @@ export interface ReviewResult {
37
46
  duration: number;
38
47
  repo: string;
39
48
  filesReviewed: number;
49
+ fileBreakdown?: { uncommitted: number; context: number };
50
+ reportSummary?: string;
40
51
  reportPath?: string;
41
52
  }
42
53
 
@@ -45,14 +56,18 @@ export async function executeReview(options: ReviewOptions): Promise<ReviewResul
45
56
 
46
57
  onStage?.('collecting');
47
58
  logger.info('Collecting files for review', { mode, workspace: process.cwd() });
48
- const files = await collectFiles({ mode });
49
- const fileCount = files.length;
59
+ const { targets, context, stats } = await collectFiles({ mode });
60
+ const fileCount = targets.length;
50
61
 
51
62
  if (fileCount === 0) {
52
63
  throw new Error('No files to review');
53
64
  }
54
65
 
55
- onStage?.('collecting', { filesFound: fileCount });
66
+ onStage?.('collecting', {
67
+ filesFound: fileCount,
68
+ uncommittedFiles: stats.uncommitted,
69
+ contextFiles: stats.context,
70
+ });
56
71
  logger.info('File collection complete', { fileCount });
57
72
 
58
73
  const workspaceRoot = process.cwd();
@@ -70,9 +85,15 @@ export async function executeReview(options: ReviewOptions): Promise<ReviewResul
70
85
 
71
86
  const start = Date.now();
72
87
 
88
+ const repoName = basename(workspaceRoot) || 'workspace';
73
89
  try {
74
- onStage?.('reviewing', { filesFound: fileCount });
75
- const reports = await runAiCodeReview(files, {
90
+ onStage?.('reviewing', {
91
+ filesFound: fileCount,
92
+ totalFiles: fileCount,
93
+ uncommittedFiles: stats.uncommitted,
94
+ contextFiles: stats.context,
95
+ });
96
+ const reports = await runAiCodeReview(targets, context, {
76
97
  provider: 'openrouter',
77
98
  type: 'comprehensive',
78
99
  outDir: rawOutDir,
@@ -80,6 +101,22 @@ export async function executeReview(options: ReviewOptions): Promise<ReviewResul
80
101
  model,
81
102
  configPath: manifestPath,
82
103
  debug,
104
+ runContext: {
105
+ repoName,
106
+ reviewMode: mode,
107
+ totalFiles: fileCount,
108
+ uncommittedFiles: stats.uncommitted,
109
+ contextFiles: stats.context,
110
+ },
111
+ onFileProgress: ({ file, index, total }) =>
112
+ onStage?.('reviewing', {
113
+ filesFound: fileCount,
114
+ currentFile: file,
115
+ fileIndex: index,
116
+ totalFiles: total,
117
+ uncommittedFiles: stats.uncommitted,
118
+ contextFiles: stats.context,
119
+ }),
83
120
  });
84
121
 
85
122
  onStage?.('merging');
@@ -88,7 +125,7 @@ export async function executeReview(options: ReviewOptions): Promise<ReviewResul
88
125
  (merged?.totals as ReviewTotals) || ({ critical: 0, high: 0, medium: 0, low: 0 } as ReviewTotals);
89
126
  const findings = (merged?.findings as any[]) || [];
90
127
 
91
- const repo = basename(workspaceRoot) || 'workspace';
128
+ const repo = repoName;
92
129
  const duration = Math.round((Date.now() - start) / 1000);
93
130
  const reportTimestamp = new Date();
94
131
 
@@ -125,6 +162,8 @@ export async function executeReview(options: ReviewOptions): Promise<ReviewResul
125
162
  duration,
126
163
  repo,
127
164
  filesReviewed: fileCount,
165
+ fileBreakdown: { uncommitted: stats.uncommitted, context: stats.context },
166
+ reportSummary: summary,
128
167
  reportPath,
129
168
  };
130
169
  } finally {
@@ -1,11 +1,35 @@
1
1
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import path from 'node:path';
2
3
  import { join, relative, resolve } from 'node:path';
3
4
  import { execa } from 'execa';
4
5
  import type { OutputFormat } from '../types/common';
5
- import type { ReviewOptions, ReviewType } from '../types/review';
6
+ import type { ReviewOptions, ReviewType, RunContext } from '../types/review';
6
7
  import { orchestrateReview } from '../core/reviewOrchestrator';
7
8
  import { RUNTIME_CONFIG } from './runtimeConfig';
8
9
 
10
+ interface FileProgressPayload {
11
+ file: string;
12
+ index: number;
13
+ total: number;
14
+ }
15
+
16
+ interface ReviewGroup {
17
+ label: string;
18
+ files: string[];
19
+ absoluteFiles: string[];
20
+ targetPath: string;
21
+ }
22
+
23
+ const MAX_FILES_PER_GROUP = 5;
24
+ const MAX_CONTEXT_DOCS_PER_GROUP = 5;
25
+ const MAX_CONTEXT_DOC_CHARS = 2000;
26
+
27
+ interface ContextDocEntry {
28
+ path: string;
29
+ relativePath: string;
30
+ snippet: string;
31
+ }
32
+
9
33
  export interface AiReviewOptions {
10
34
  provider: 'openrouter';
11
35
  type: string;
@@ -14,10 +38,16 @@ export interface AiReviewOptions {
14
38
  model?: string;
15
39
  configPath?: string;
16
40
  debug?: boolean;
41
+ onFileProgress?: (payload: FileProgressPayload) => void;
42
+ runContext?: RunContext;
17
43
  }
18
44
 
19
- export async function runAiCodeReview(files: string[], opts: AiReviewOptions): Promise<any[]> {
20
- if (files.length === 0) return [];
45
+ export async function runAiCodeReview(
46
+ targetFiles: string[],
47
+ contextFiles: string[],
48
+ opts: AiReviewOptions,
49
+ ): Promise<any[]> {
50
+ if (targetFiles.length === 0) return [];
21
51
 
22
52
  const workspaceRoot = process.cwd();
23
53
  let repoRoot: string;
@@ -68,7 +98,7 @@ export async function runAiCodeReview(files: string[], opts: AiReviewOptions): P
68
98
  }
69
99
 
70
100
  const expandedFiles: string[] = [];
71
- for (const file of files) {
101
+ for (const file of targetFiles) {
72
102
  const absPath = resolve(file);
73
103
  try {
74
104
  const stats = statSync(absPath);
@@ -144,10 +174,135 @@ export async function runAiCodeReview(files: string[], opts: AiReviewOptions): P
144
174
  baseOptions.config = opts.configPath;
145
175
  }
146
176
 
147
- for (const target of targets) {
148
- await orchestrateReview(target, baseOptions);
177
+ const groups = createReviewGroups(targets, workspaceRoot);
178
+ const contextDocEntries = prepareContextDocs(contextFiles, workspaceRoot);
179
+ const totalFiles = targets.length;
180
+ let processedCount = 0;
181
+
182
+ const groupCount = groups.length;
183
+ for (let groupIdx = 0; groupIdx < groups.length; groupIdx += 1) {
184
+ const group = groups[groupIdx];
185
+ const progressIndex = Math.min(processedCount + 1, totalFiles);
186
+ const displayName = formatGroupDisplay(group.files);
187
+ opts.onFileProgress?.({ file: displayName, index: progressIndex, total: totalFiles });
188
+
189
+ const selectedContextDocs = selectContextDocs(group.files, contextDocEntries);
190
+ const inheritedContext = opts.runContext;
191
+ const runContext = inheritedContext
192
+ ? {
193
+ ...inheritedContext,
194
+ groupIndex: groupIdx + 1,
195
+ groupCount,
196
+ groupLabel: group.label,
197
+ groupFiles: group.files,
198
+ docFiles: selectedContextDocs.map((doc) => doc.relativePath),
199
+ contextDocs: selectedContextDocs.map((doc) => ({
200
+ path: doc.relativePath,
201
+ snippet: doc.snippet,
202
+ })),
203
+ }
204
+ : undefined;
205
+
206
+ await orchestrateReview(group.targetPath, {
207
+ ...baseOptions,
208
+ targetFileList: group.absoluteFiles,
209
+ runContext,
210
+ });
211
+ processedCount += group.files.length;
149
212
  collectOutputs();
150
213
  }
151
214
 
152
215
  return outputs;
153
216
  }
217
+
218
+ function createReviewGroups(targets: string[], workspaceRoot: string): ReviewGroup[] {
219
+ const directoryMap = new Map<string, string[]>();
220
+ for (const target of targets) {
221
+ const dir = path.posix.dirname(target) || '.';
222
+ if (!directoryMap.has(dir)) {
223
+ directoryMap.set(dir, []);
224
+ }
225
+ directoryMap.get(dir)!.push(target);
226
+ }
227
+
228
+ const groups: ReviewGroup[] = [];
229
+ for (const [dir, files] of directoryMap) {
230
+ for (let i = 0; i < files.length; i += MAX_FILES_PER_GROUP) {
231
+ const chunk = files.slice(i, i + MAX_FILES_PER_GROUP);
232
+ const absoluteFiles = chunk.map((file) => resolve(workspaceRoot, file));
233
+ const targetPath = dir === '.' ? chunk[0] ?? '.' : dir;
234
+ groups.push({
235
+ label: dir,
236
+ files: chunk,
237
+ absoluteFiles,
238
+ targetPath,
239
+ });
240
+ }
241
+ }
242
+
243
+ return groups;
244
+ }
245
+
246
+ function formatGroupDisplay(files: string[]): string {
247
+ if (files.length === 0) {
248
+ return 'pending files';
249
+ }
250
+
251
+ if (files.length === 1) {
252
+ return files[0];
253
+ }
254
+
255
+ return `${files[0]} (+${files.length - 1} more)`;
256
+ }
257
+
258
+ function prepareContextDocs(contextFiles: string[], workspaceRoot: string): ContextDocEntry[] {
259
+ const docs: ContextDocEntry[] = [];
260
+ const seen = new Set<string>();
261
+
262
+ for (const file of contextFiles) {
263
+ const absPath = resolve(file);
264
+ if (seen.has(absPath)) continue;
265
+ seen.add(absPath);
266
+
267
+ try {
268
+ const stats = statSync(absPath);
269
+ if (!stats.isFile()) continue;
270
+ const buffer = readFileSync(absPath);
271
+ if (buffer.length === 0 || buffer.includes(0)) continue;
272
+ const snippet = buffer.toString('utf-8').slice(0, MAX_CONTEXT_DOC_CHARS);
273
+ const relativePath = relative(workspaceRoot, absPath).replace(/\\/g, '/');
274
+ if (!relativePath || relativePath.startsWith('..')) continue;
275
+ docs.push({ path: absPath, relativePath, snippet });
276
+ } catch {
277
+ continue;
278
+ }
279
+ }
280
+
281
+ return docs;
282
+ }
283
+
284
+ function selectContextDocs(
285
+ groupFiles: string[],
286
+ docs: ContextDocEntry[],
287
+ limit = MAX_CONTEXT_DOCS_PER_GROUP,
288
+ ): ContextDocEntry[] {
289
+ if (docs.length === 0 || limit <= 0) {
290
+ return [];
291
+ }
292
+
293
+ const groupDirs = new Set(groupFiles.map((file) => path.posix.dirname(file)));
294
+ const prioritized: ContextDocEntry[] = [];
295
+ const remaining: ContextDocEntry[] = [];
296
+
297
+ for (const doc of docs) {
298
+ const docDir = path.posix.dirname(doc.relativePath);
299
+ if (groupDirs.has(docDir)) {
300
+ prioritized.push(doc);
301
+ } else {
302
+ remaining.push(doc);
303
+ }
304
+ }
305
+
306
+ const ordered = [...prioritized, ...remaining];
307
+ return ordered.slice(0, limit);
308
+ }