codereview-aia 0.1.0 → 0.1.2

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 (422) hide show
  1. package/dist/analysis/FindingsExtractor.d.ts +105 -0
  2. package/dist/analysis/FindingsExtractor.js +363 -0
  3. package/dist/analysis/FindingsExtractor.js.map +1 -0
  4. package/dist/analysis/ai-detection/analyzers/BaseAnalyzer.d.ts +111 -0
  5. package/dist/analysis/ai-detection/analyzers/BaseAnalyzer.js +215 -0
  6. package/dist/analysis/ai-detection/analyzers/BaseAnalyzer.js.map +1 -0
  7. package/dist/analysis/ai-detection/analyzers/DocumentationAnalyzer.d.ts +142 -0
  8. package/dist/analysis/ai-detection/analyzers/DocumentationAnalyzer.js +503 -0
  9. package/dist/analysis/ai-detection/analyzers/DocumentationAnalyzer.js.map +1 -0
  10. package/dist/analysis/ai-detection/analyzers/GitHistoryAnalyzer.d.ts +88 -0
  11. package/dist/analysis/ai-detection/analyzers/GitHistoryAnalyzer.js +343 -0
  12. package/dist/analysis/ai-detection/analyzers/GitHistoryAnalyzer.js.map +1 -0
  13. package/dist/analysis/ai-detection/core/AIDetectionEngine.d.ts +104 -0
  14. package/dist/analysis/ai-detection/core/AIDetectionEngine.js +369 -0
  15. package/dist/analysis/ai-detection/core/AIDetectionEngine.js.map +1 -0
  16. package/dist/analysis/ai-detection/types/DetectionTypes.d.ts +364 -0
  17. package/dist/analysis/ai-detection/types/DetectionTypes.js +32 -0
  18. package/dist/analysis/ai-detection/types/DetectionTypes.js.map +1 -0
  19. package/dist/analysis/ai-detection/utils/SubmissionConverter.d.ts +97 -0
  20. package/dist/analysis/ai-detection/utils/SubmissionConverter.js +339 -0
  21. package/dist/analysis/ai-detection/utils/SubmissionConverter.js.map +1 -0
  22. package/dist/analysis/context/ReviewContext.d.ts +184 -0
  23. package/dist/analysis/context/ReviewContext.js +294 -0
  24. package/dist/analysis/context/ReviewContext.js.map +1 -0
  25. package/dist/analysis/context/index.d.ts +6 -0
  26. package/dist/analysis/context/index.js +23 -0
  27. package/dist/analysis/context/index.js.map +1 -0
  28. package/dist/analysis/index.d.ts +7 -0
  29. package/dist/analysis/index.js +24 -0
  30. package/dist/analysis/index.js.map +1 -0
  31. package/dist/analysis/tokens/TokenAnalysisFormatter.d.ts +27 -0
  32. package/dist/analysis/tokens/TokenAnalysisFormatter.js +143 -0
  33. package/dist/analysis/tokens/TokenAnalysisFormatter.js.map +1 -0
  34. package/dist/analysis/tokens/TokenAnalyzer.d.ts +155 -0
  35. package/dist/analysis/tokens/TokenAnalyzer.js +502 -0
  36. package/dist/analysis/tokens/TokenAnalyzer.js.map +1 -0
  37. package/dist/analysis/tokens/index.d.ts +7 -0
  38. package/dist/analysis/tokens/index.js +24 -0
  39. package/dist/analysis/tokens/index.js.map +1 -0
  40. package/dist/clients/base/abstractClient.d.ts +99 -0
  41. package/dist/clients/base/abstractClient.js +98 -0
  42. package/dist/clients/base/abstractClient.js.map +1 -0
  43. package/dist/clients/base/httpClient.d.ts +24 -0
  44. package/dist/clients/base/httpClient.js +147 -0
  45. package/dist/clients/base/httpClient.js.map +1 -0
  46. package/dist/clients/base/index.d.ts +11 -0
  47. package/dist/clients/base/index.js +28 -0
  48. package/dist/clients/base/index.js.map +1 -0
  49. package/dist/clients/base/modelDetection.d.ts +41 -0
  50. package/dist/clients/base/modelDetection.js +88 -0
  51. package/dist/clients/base/modelDetection.js.map +1 -0
  52. package/dist/clients/base/responseProcessor.d.ts +45 -0
  53. package/dist/clients/base/responseProcessor.js +495 -0
  54. package/dist/clients/base/responseProcessor.js.map +1 -0
  55. package/dist/clients/factory/clientFactory.d.ts +23 -0
  56. package/dist/clients/factory/clientFactory.js +50 -0
  57. package/dist/clients/factory/clientFactory.js.map +1 -0
  58. package/dist/clients/factory/index.d.ts +7 -0
  59. package/dist/clients/factory/index.js +24 -0
  60. package/dist/clients/factory/index.js.map +1 -0
  61. package/dist/clients/implementations/index.d.ts +7 -0
  62. package/dist/clients/implementations/index.js +24 -0
  63. package/dist/clients/implementations/index.js.map +1 -0
  64. package/dist/clients/implementations/openRouterClient.d.ts +69 -0
  65. package/dist/clients/implementations/openRouterClient.js +294 -0
  66. package/dist/clients/implementations/openRouterClient.js.map +1 -0
  67. package/dist/clients/openRouterClient.d.ts +42 -0
  68. package/dist/clients/openRouterClient.js +738 -0
  69. package/dist/clients/openRouterClient.js.map +1 -0
  70. package/dist/clients/openRouterClientWrapper.d.ts +22 -0
  71. package/dist/clients/openRouterClientWrapper.js +64 -0
  72. package/dist/clients/openRouterClientWrapper.js.map +1 -0
  73. package/dist/clients/utils/directoryStructure.d.ts +14 -0
  74. package/dist/clients/utils/directoryStructure.js +48 -0
  75. package/dist/clients/utils/directoryStructure.js.map +1 -0
  76. package/dist/clients/utils/index.d.ts +10 -0
  77. package/dist/clients/utils/index.js +31 -0
  78. package/dist/clients/utils/index.js.map +1 -0
  79. package/dist/clients/utils/languageDetection.d.ts +13 -0
  80. package/dist/clients/utils/languageDetection.js +46 -0
  81. package/dist/clients/utils/languageDetection.js.map +1 -0
  82. package/dist/clients/utils/promptFormatter.d.ts +36 -0
  83. package/dist/clients/utils/promptFormatter.js +92 -0
  84. package/dist/clients/utils/promptFormatter.js.map +1 -0
  85. package/dist/clients/utils/promptLoader.d.ts +27 -0
  86. package/dist/clients/utils/promptLoader.js +49 -0
  87. package/dist/clients/utils/promptLoader.js.map +1 -0
  88. package/dist/clients/utils/tokenCounter.d.ts +81 -0
  89. package/dist/clients/utils/tokenCounter.js +209 -0
  90. package/dist/clients/utils/tokenCounter.js.map +1 -0
  91. package/dist/core/ApiClientSelector.d.ts +8 -0
  92. package/dist/core/ApiClientSelector.js +29 -0
  93. package/dist/core/ApiClientSelector.js.map +1 -0
  94. package/dist/core/ConfigurationService.d.ts +286 -0
  95. package/dist/core/ConfigurationService.js +477 -0
  96. package/dist/core/ConfigurationService.js.map +1 -0
  97. package/dist/core/ConsolidationService.d.ts +99 -0
  98. package/dist/core/ConsolidationService.js +341 -0
  99. package/dist/core/ConsolidationService.js.map +1 -0
  100. package/dist/core/InteractiveDisplayManager.d.ts +22 -0
  101. package/dist/core/InteractiveDisplayManager.js +70 -0
  102. package/dist/core/InteractiveDisplayManager.js.map +1 -0
  103. package/dist/core/OutputManager.d.ts +26 -0
  104. package/dist/core/OutputManager.js +217 -0
  105. package/dist/core/OutputManager.js.map +1 -0
  106. package/dist/core/ReviewGenerator.d.ts +13 -0
  107. package/dist/core/ReviewGenerator.js +102 -0
  108. package/dist/core/ReviewGenerator.js.map +1 -0
  109. package/dist/core/fileDiscovery.d.ts +35 -0
  110. package/dist/core/fileDiscovery.js +202 -0
  111. package/dist/core/fileDiscovery.js.map +1 -0
  112. package/dist/core/handlers/EstimationHandler.d.ts +18 -0
  113. package/dist/core/handlers/EstimationHandler.js +110 -0
  114. package/dist/core/handlers/EstimationHandler.js.map +1 -0
  115. package/dist/core/handlers/FileProcessingHandler.d.ts +31 -0
  116. package/dist/core/handlers/FileProcessingHandler.js +159 -0
  117. package/dist/core/handlers/FileProcessingHandler.js.map +1 -0
  118. package/dist/core/handlers/OutputHandler.d.ts +27 -0
  119. package/dist/core/handlers/OutputHandler.js +127 -0
  120. package/dist/core/handlers/OutputHandler.js.map +1 -0
  121. package/dist/core/handlers/ReviewExecutor.d.ts +32 -0
  122. package/dist/core/handlers/ReviewExecutor.js +111 -0
  123. package/dist/core/handlers/ReviewExecutor.js.map +1 -0
  124. package/dist/core/reviewOrchestrator.d.ts +24 -0
  125. package/dist/core/reviewOrchestrator.js +294 -0
  126. package/dist/core/reviewOrchestrator.js.map +1 -0
  127. package/dist/core/utils/ModelInfoUtils.d.ts +16 -0
  128. package/dist/core/utils/ModelInfoUtils.js +54 -0
  129. package/dist/core/utils/ModelInfoUtils.js.map +1 -0
  130. package/dist/formatters/outputFormatter.d.ts +31 -0
  131. package/dist/formatters/outputFormatter.js +65 -0
  132. package/dist/formatters/outputFormatter.js.map +1 -0
  133. package/dist/formatters/utils/IssueFormatters.d.ts +20 -0
  134. package/dist/formatters/utils/IssueFormatters.js +67 -0
  135. package/dist/formatters/utils/IssueFormatters.js.map +1 -0
  136. package/dist/formatters/utils/JsonFormatter.d.ts +13 -0
  137. package/dist/formatters/utils/JsonFormatter.js +57 -0
  138. package/dist/formatters/utils/JsonFormatter.js.map +1 -0
  139. package/dist/formatters/utils/MarkdownFormatters.d.ts +51 -0
  140. package/dist/formatters/utils/MarkdownFormatters.js +456 -0
  141. package/dist/formatters/utils/MarkdownFormatters.js.map +1 -0
  142. package/dist/formatters/utils/MetadataFormatter.d.ts +65 -0
  143. package/dist/formatters/utils/MetadataFormatter.js +219 -0
  144. package/dist/formatters/utils/MetadataFormatter.js.map +1 -0
  145. package/dist/formatters/utils/ModelInfoExtractor.d.ts +33 -0
  146. package/dist/formatters/utils/ModelInfoExtractor.js +111 -0
  147. package/dist/formatters/utils/ModelInfoExtractor.js.map +1 -0
  148. package/dist/index.d.ts +2 -0
  149. package/dist/index.js +1 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/plugins/PluginInterface.d.ts +44 -0
  152. package/dist/plugins/PluginInterface.js +9 -0
  153. package/dist/plugins/PluginInterface.js.map +1 -0
  154. package/dist/plugins/PluginManager.d.ts +51 -0
  155. package/dist/plugins/PluginManager.js +151 -0
  156. package/dist/plugins/PluginManager.js.map +1 -0
  157. package/dist/prompts/PromptManager.d.ts +30 -0
  158. package/dist/prompts/PromptManager.js +62 -0
  159. package/dist/prompts/PromptManager.js.map +1 -0
  160. package/dist/prompts/cache/PromptCache.d.ts +32 -0
  161. package/dist/prompts/cache/PromptCache.js +48 -0
  162. package/dist/prompts/cache/PromptCache.js.map +1 -0
  163. package/dist/runtime/auth/service.d.ts +2 -0
  164. package/dist/runtime/auth/service.js +41 -0
  165. package/dist/runtime/auth/service.js.map +1 -0
  166. package/dist/runtime/auth/session.d.ts +5 -0
  167. package/dist/runtime/auth/session.js +87 -0
  168. package/dist/runtime/auth/session.js.map +1 -0
  169. package/dist/runtime/auth/types.d.ts +9 -0
  170. package/dist/runtime/auth/types.js +3 -0
  171. package/dist/runtime/auth/types.js.map +1 -0
  172. package/dist/runtime/cliEntry.d.ts +1 -0
  173. package/dist/runtime/cliEntry.js +213 -0
  174. package/dist/runtime/cliEntry.js.map +1 -0
  175. package/dist/runtime/debug/logManager.d.ts +5 -0
  176. package/dist/runtime/debug/logManager.js +31 -0
  177. package/dist/runtime/debug/logManager.js.map +1 -0
  178. package/dist/runtime/errors.d.ts +5 -0
  179. package/dist/runtime/errors.js +15 -0
  180. package/dist/runtime/errors.js.map +1 -0
  181. package/dist/runtime/fileCollector.d.ts +5 -0
  182. package/dist/runtime/fileCollector.js +167 -0
  183. package/dist/runtime/fileCollector.js.map +1 -0
  184. package/dist/runtime/manifest.d.ts +1 -0
  185. package/dist/runtime/manifest.js +65 -0
  186. package/dist/runtime/manifest.js.map +1 -0
  187. package/dist/runtime/openrouterProxy.d.ts +4 -0
  188. package/dist/runtime/openrouterProxy.js +43 -0
  189. package/dist/runtime/openrouterProxy.js.map +1 -0
  190. package/dist/runtime/preprod/webCheck.d.ts +1 -0
  191. package/dist/runtime/preprod/webCheck.js +98 -0
  192. package/dist/runtime/preprod/webCheck.js.map +1 -0
  193. package/dist/runtime/proxyConfig.d.ts +6 -0
  194. package/dist/runtime/proxyConfig.js +86 -0
  195. package/dist/runtime/proxyConfig.js.map +1 -0
  196. package/dist/runtime/proxyEnvironment.d.ts +3 -0
  197. package/dist/runtime/proxyEnvironment.js +63 -0
  198. package/dist/runtime/proxyEnvironment.js.map +1 -0
  199. package/dist/runtime/reportMerge.d.ts +30 -0
  200. package/dist/runtime/reportMerge.js +70 -0
  201. package/dist/runtime/reportMerge.js.map +1 -0
  202. package/dist/runtime/reporting/markdownReportBuilder.d.ts +15 -0
  203. package/dist/runtime/reporting/markdownReportBuilder.js +97 -0
  204. package/dist/runtime/reporting/markdownReportBuilder.js.map +1 -0
  205. package/dist/runtime/reporting/reportDataCollector.d.ts +31 -0
  206. package/dist/runtime/reporting/reportDataCollector.js +170 -0
  207. package/dist/runtime/reporting/reportDataCollector.js.map +1 -0
  208. package/dist/runtime/reporting/summaryGenerator.d.ts +10 -0
  209. package/dist/runtime/reporting/summaryGenerator.js +67 -0
  210. package/dist/runtime/reporting/summaryGenerator.js.map +1 -0
  211. package/dist/runtime/reviewPipeline.d.ts +28 -0
  212. package/dist/runtime/reviewPipeline.js +122 -0
  213. package/dist/runtime/reviewPipeline.js.map +1 -0
  214. package/dist/runtime/runAiCodeReview.d.ts +10 -0
  215. package/dist/runtime/runAiCodeReview.js +138 -0
  216. package/dist/runtime/runAiCodeReview.js.map +1 -0
  217. package/dist/runtime/runtimeConfig.d.ts +4 -0
  218. package/dist/runtime/runtimeConfig.js +7 -0
  219. package/dist/runtime/runtimeConfig.js.map +1 -0
  220. package/dist/runtime/ui/Layout.d.ts +11 -0
  221. package/dist/runtime/ui/Layout.js +47 -0
  222. package/dist/runtime/ui/Layout.js.map +1 -0
  223. package/dist/runtime/ui/RuntimeApp.d.ts +6 -0
  224. package/dist/runtime/ui/RuntimeApp.js +161 -0
  225. package/dist/runtime/ui/RuntimeApp.js.map +1 -0
  226. package/dist/runtime/ui/inkModules.d.ts +10 -0
  227. package/dist/runtime/ui/inkModules.js +63 -0
  228. package/dist/runtime/ui/inkModules.js.map +1 -0
  229. package/dist/runtime/ui/screens/AuthScreen.d.ts +6 -0
  230. package/dist/runtime/ui/screens/AuthScreen.js +67 -0
  231. package/dist/runtime/ui/screens/AuthScreen.js.map +1 -0
  232. package/dist/runtime/ui/screens/ModeSelection.d.ts +10 -0
  233. package/dist/runtime/ui/screens/ModeSelection.js +100 -0
  234. package/dist/runtime/ui/screens/ModeSelection.js.map +1 -0
  235. package/dist/runtime/ui/screens/ProgressScreen.d.ts +7 -0
  236. package/dist/runtime/ui/screens/ProgressScreen.js +38 -0
  237. package/dist/runtime/ui/screens/ProgressScreen.js.map +1 -0
  238. package/dist/runtime/ui/screens/ResultsScreen.d.ts +7 -0
  239. package/dist/runtime/ui/screens/ResultsScreen.js +22 -0
  240. package/dist/runtime/ui/screens/ResultsScreen.js.map +1 -0
  241. package/dist/strategies/ArchitecturalReviewStrategy.d.ts +29 -0
  242. package/dist/strategies/ArchitecturalReviewStrategy.js +42 -0
  243. package/dist/strategies/ArchitecturalReviewStrategy.js.map +1 -0
  244. package/dist/strategies/CodingTestReviewStrategy.d.ts +194 -0
  245. package/dist/strategies/CodingTestReviewStrategy.js +681 -0
  246. package/dist/strategies/CodingTestReviewStrategy.js.map +1 -0
  247. package/dist/strategies/ConsolidatedReviewStrategy.d.ts +25 -0
  248. package/dist/strategies/ConsolidatedReviewStrategy.js +45 -0
  249. package/dist/strategies/ConsolidatedReviewStrategy.js.map +1 -0
  250. package/dist/strategies/ExtractPatternsReviewStrategy.d.ts +30 -0
  251. package/dist/strategies/ExtractPatternsReviewStrategy.js +51 -0
  252. package/dist/strategies/ExtractPatternsReviewStrategy.js.map +1 -0
  253. package/dist/strategies/MultiPassReviewStrategy.d.ts +86 -0
  254. package/dist/strategies/MultiPassReviewStrategy.js +590 -0
  255. package/dist/strategies/MultiPassReviewStrategy.js.map +1 -0
  256. package/dist/strategies/ReviewStrategy.d.ts +45 -0
  257. package/dist/strategies/ReviewStrategy.js +24 -0
  258. package/dist/strategies/ReviewStrategy.js.map +1 -0
  259. package/dist/strategies/StrategyFactory.d.ts +19 -0
  260. package/dist/strategies/StrategyFactory.js +72 -0
  261. package/dist/strategies/StrategyFactory.js.map +1 -0
  262. package/dist/strategies/index.d.ts +13 -0
  263. package/dist/strategies/index.js +30 -0
  264. package/dist/strategies/index.js.map +1 -0
  265. package/dist/tokenizers/baseTokenizer.d.ts +25 -0
  266. package/dist/tokenizers/baseTokenizer.js +48 -0
  267. package/dist/tokenizers/baseTokenizer.js.map +1 -0
  268. package/dist/tokenizers/gptTokenizer.d.ts +7 -0
  269. package/dist/tokenizers/gptTokenizer.js +28 -0
  270. package/dist/tokenizers/gptTokenizer.js.map +1 -0
  271. package/dist/tokenizers/index.d.ts +7 -0
  272. package/dist/tokenizers/index.js +24 -0
  273. package/dist/tokenizers/index.js.map +1 -0
  274. package/dist/types/apiResponses.d.ts +39 -0
  275. package/dist/types/apiResponses.js +9 -0
  276. package/dist/types/apiResponses.js.map +1 -0
  277. package/dist/types/cli.d.ts +22 -0
  278. package/dist/types/cli.js +3 -0
  279. package/dist/types/cli.js.map +1 -0
  280. package/dist/types/common.d.ts +22 -0
  281. package/dist/types/common.js +14 -0
  282. package/dist/types/common.js.map +1 -0
  283. package/dist/types/configuration.d.ts +682 -0
  284. package/dist/types/configuration.js +65 -0
  285. package/dist/types/configuration.js.map +1 -0
  286. package/dist/types/review.d.ts +258 -0
  287. package/dist/types/review.js +8 -0
  288. package/dist/types/review.js.map +1 -0
  289. package/dist/types/reviewSchema.d.ts +543 -0
  290. package/dist/types/reviewSchema.js +121 -0
  291. package/dist/types/reviewSchema.js.map +1 -0
  292. package/dist/types/structuredReview.d.ts +119 -0
  293. package/dist/types/structuredReview.js +6 -0
  294. package/dist/types/structuredReview.js.map +1 -0
  295. package/dist/types/tokenAnalysis.d.ts +44 -0
  296. package/dist/types/tokenAnalysis.js +4 -0
  297. package/dist/types/tokenAnalysis.js.map +1 -0
  298. package/dist/utils/FileReader.d.ts +33 -0
  299. package/dist/utils/FileReader.js +88 -0
  300. package/dist/utils/FileReader.js.map +1 -0
  301. package/dist/utils/FileWriter.d.ts +26 -0
  302. package/dist/utils/FileWriter.js +76 -0
  303. package/dist/utils/FileWriter.js.map +1 -0
  304. package/dist/utils/PathGenerator.d.ts +30 -0
  305. package/dist/utils/PathGenerator.js +82 -0
  306. package/dist/utils/PathGenerator.js.map +1 -0
  307. package/dist/utils/api/apiUtils.d.ts +3 -0
  308. package/dist/utils/api/apiUtils.js +20 -0
  309. package/dist/utils/api/apiUtils.js.map +1 -0
  310. package/dist/utils/api/index.d.ts +1 -0
  311. package/dist/utils/api/index.js +18 -0
  312. package/dist/utils/api/index.js.map +1 -0
  313. package/dist/utils/apiErrorHandler.d.ts +130 -0
  314. package/dist/utils/apiErrorHandler.js +256 -0
  315. package/dist/utils/apiErrorHandler.js.map +1 -0
  316. package/dist/utils/ciDataCollector.d.ts +51 -0
  317. package/dist/utils/ciDataCollector.js +197 -0
  318. package/dist/utils/ciDataCollector.js.map +1 -0
  319. package/dist/utils/codingTestConfigLoader.d.ts +66 -0
  320. package/dist/utils/codingTestConfigLoader.js +420 -0
  321. package/dist/utils/codingTestConfigLoader.js.map +1 -0
  322. package/dist/utils/dependencies/aiDependencyAnalyzer.d.ts +30 -0
  323. package/dist/utils/dependencies/aiDependencyAnalyzer.js +343 -0
  324. package/dist/utils/dependencies/aiDependencyAnalyzer.js.map +1 -0
  325. package/dist/utils/detection/frameworkDetector.d.ts +43 -0
  326. package/dist/utils/detection/frameworkDetector.js +795 -0
  327. package/dist/utils/detection/frameworkDetector.js.map +1 -0
  328. package/dist/utils/detection/index.d.ts +9 -0
  329. package/dist/utils/detection/index.js +28 -0
  330. package/dist/utils/detection/index.js.map +1 -0
  331. package/dist/utils/detection/projectTypeDetector.d.ts +27 -0
  332. package/dist/utils/detection/projectTypeDetector.js +469 -0
  333. package/dist/utils/detection/projectTypeDetector.js.map +1 -0
  334. package/dist/utils/diagramGenerator.d.ts +49 -0
  335. package/dist/utils/diagramGenerator.js +218 -0
  336. package/dist/utils/diagramGenerator.js.map +1 -0
  337. package/dist/utils/errorLogger.d.ts +24 -0
  338. package/dist/utils/errorLogger.js +59 -0
  339. package/dist/utils/errorLogger.js.map +1 -0
  340. package/dist/utils/estimationUtils.d.ts +139 -0
  341. package/dist/utils/estimationUtils.js +329 -0
  342. package/dist/utils/estimationUtils.js.map +1 -0
  343. package/dist/utils/fileFilters.d.ts +72 -0
  344. package/dist/utils/fileFilters.js +338 -0
  345. package/dist/utils/fileFilters.js.map +1 -0
  346. package/dist/utils/fileSystem.d.ts +22 -0
  347. package/dist/utils/fileSystem.js +45 -0
  348. package/dist/utils/fileSystem.js.map +1 -0
  349. package/dist/utils/index.d.ts +22 -0
  350. package/dist/utils/index.js +52 -0
  351. package/dist/utils/index.js.map +1 -0
  352. package/dist/utils/logger.d.ts +77 -0
  353. package/dist/utils/logger.js +271 -0
  354. package/dist/utils/logger.js.map +1 -0
  355. package/dist/utils/pathValidator.d.ts +40 -0
  356. package/dist/utils/pathValidator.js +98 -0
  357. package/dist/utils/pathValidator.js.map +1 -0
  358. package/dist/utils/priorityFilter.d.ts +34 -0
  359. package/dist/utils/priorityFilter.js +54 -0
  360. package/dist/utils/priorityFilter.js.map +1 -0
  361. package/dist/utils/projectDocs.d.ts +47 -0
  362. package/dist/utils/projectDocs.js +158 -0
  363. package/dist/utils/projectDocs.js.map +1 -0
  364. package/dist/utils/promptPaths.d.ts +6 -0
  365. package/dist/utils/promptPaths.js +33 -0
  366. package/dist/utils/promptPaths.js.map +1 -0
  367. package/dist/utils/promptTemplateManager.d.ts +34 -0
  368. package/dist/utils/promptTemplateManager.js +140 -0
  369. package/dist/utils/promptTemplateManager.js.map +1 -0
  370. package/dist/utils/review/consolidateReview.d.ts +15 -0
  371. package/dist/utils/review/consolidateReview.js +481 -0
  372. package/dist/utils/review/consolidateReview.js.map +1 -0
  373. package/dist/utils/review/fixDisplay.d.ts +20 -0
  374. package/dist/utils/review/fixDisplay.js +84 -0
  375. package/dist/utils/review/fixDisplay.js.map +1 -0
  376. package/dist/utils/review/fixImplementation.d.ts +28 -0
  377. package/dist/utils/review/fixImplementation.js +60 -0
  378. package/dist/utils/review/fixImplementation.js.map +1 -0
  379. package/dist/utils/review/index.d.ts +13 -0
  380. package/dist/utils/review/index.js +50 -0
  381. package/dist/utils/review/index.js.map +1 -0
  382. package/dist/utils/review/interactiveProcessing.d.ts +25 -0
  383. package/dist/utils/review/interactiveProcessing.js +251 -0
  384. package/dist/utils/review/interactiveProcessing.js.map +1 -0
  385. package/dist/utils/review/progressTracker.d.ts +106 -0
  386. package/dist/utils/review/progressTracker.js +227 -0
  387. package/dist/utils/review/progressTracker.js.map +1 -0
  388. package/dist/utils/review/reviewExtraction.d.ts +31 -0
  389. package/dist/utils/review/reviewExtraction.js +324 -0
  390. package/dist/utils/review/reviewExtraction.js.map +1 -0
  391. package/dist/utils/review/types.d.ts +45 -0
  392. package/dist/utils/review/types.js +18 -0
  393. package/dist/utils/review/types.js.map +1 -0
  394. package/dist/utils/reviewActionHandler.d.ts +16 -0
  395. package/dist/utils/reviewActionHandler.js +34 -0
  396. package/dist/utils/reviewActionHandler.js.map +1 -0
  397. package/dist/utils/reviewParser.d.ts +34 -0
  398. package/dist/utils/reviewParser.js +218 -0
  399. package/dist/utils/reviewParser.js.map +1 -0
  400. package/dist/utils/sanitizer.d.ts +82 -0
  401. package/dist/utils/sanitizer.js +239 -0
  402. package/dist/utils/sanitizer.js.map +1 -0
  403. package/dist/utils/smartFileSelector.d.ts +50 -0
  404. package/dist/utils/smartFileSelector.js +261 -0
  405. package/dist/utils/smartFileSelector.js.map +1 -0
  406. package/dist/utils/templateLoader.d.ts +44 -0
  407. package/dist/utils/templateLoader.js +431 -0
  408. package/dist/utils/templateLoader.js.map +1 -0
  409. package/dist/utils/treeGenerator.d.ts +12 -0
  410. package/dist/utils/treeGenerator.js +133 -0
  411. package/dist/utils/treeGenerator.js.map +1 -0
  412. package/package.json +11 -12
  413. package/src/index.ts +1 -0
  414. package/src/runtime/debug/logManager.ts +37 -0
  415. package/src/runtime/fileCollector.ts +58 -24
  416. package/src/runtime/preprod/webCheck.ts +104 -0
  417. package/src/runtime/reviewPipeline.ts +10 -4
  418. package/src/runtime/ui/RuntimeApp.tsx +96 -13
  419. package/src/runtime/ui/screens/ModeSelection.tsx +148 -15
  420. package/src/runtime/ui/screens/ProgressScreen.tsx +10 -3
  421. package/src/runtime/ui/screens/ResultsScreen.tsx +8 -1
  422. package/src/utils/logger.ts +64 -14
@@ -0,0 +1,37 @@
1
+ import { mkdirSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { disableFileLogging, enableFileLogging } from '../../utils/logger';
4
+
5
+ export interface DebugLogSession {
6
+ filePath: string;
7
+ stop: () => void;
8
+ }
9
+
10
+ function formatTimestamp(date: Date): string {
11
+ const pad = (value: number) => value.toString().padStart(2, '0');
12
+ const year = date.getFullYear();
13
+ const month = pad(date.getMonth() + 1);
14
+ const day = pad(date.getDate());
15
+ const hours = pad(date.getHours());
16
+ const minutes = pad(date.getMinutes());
17
+ const seconds = pad(date.getSeconds());
18
+ return `${year}${month}${day}-${hours}${minutes}${seconds}`;
19
+ }
20
+
21
+ export function startDebugLogSession(workspaceRoot: string): DebugLogSession {
22
+ const logsDir = resolve(workspaceRoot, 'logs');
23
+ mkdirSync(logsDir, { recursive: true });
24
+
25
+ const timestamp = formatTimestamp(new Date());
26
+ const fileName = `cr-debug-${timestamp}.log`;
27
+ const filePath = join(logsDir, fileName);
28
+
29
+ enableFileLogging(filePath);
30
+
31
+ return {
32
+ filePath,
33
+ stop: () => {
34
+ disableFileLogging();
35
+ },
36
+ };
37
+ }
@@ -3,7 +3,13 @@ import { relative as relativePath, resolve as resolvePath, isAbsolute as isAbsol
3
3
  import { execa } from 'execa';
4
4
  import { MissingCrIgnoreError } from './errors';
5
5
 
6
- export async function collectFiles(): Promise<string[]> {
6
+ export type FileCollectionMode = 'uncommitted' | 'preprod';
7
+
8
+ export interface CollectFilesOptions {
9
+ mode?: FileCollectionMode;
10
+ }
11
+
12
+ export async function collectFiles(options: CollectFilesOptions = {}): Promise<string[]> {
7
13
  try {
8
14
  const { stdout: rootOut } = await execa('git', ['rev-parse', '--show-toplevel']);
9
15
  const repoRoot = resolvePath(rootOut.trim());
@@ -58,40 +64,54 @@ export async function collectFiles(): Promise<string[]> {
58
64
  return absolutePath;
59
65
  };
60
66
 
61
- const gitWorkspaceOptions = { cwd: workspaceRoot } as const;
62
- const gitPathSpec = ['--', '.'] as const;
67
+ const mode: FileCollectionMode = options.mode ?? 'uncommitted';
63
68
 
64
- const { stdout: statusOut } = await execa('git', ['status', '--porcelain=1', '-z', ...gitPathSpec], gitWorkspaceOptions);
65
- const { stdout: diffOut } = await execa('git', ['diff', '--name-only', '-z', ...gitPathSpec], gitWorkspaceOptions);
69
+ const collectUncommittedFiles = async (): Promise<string[]> => {
70
+ const gitWorkspaceOptions = { cwd: workspaceRoot } as const;
71
+ const gitPathSpec = ['--', '.'] as const;
66
72
 
67
- const statusEntries = statusOut.split('\0').filter(Boolean);
68
- const statusFiles: string[] = [];
73
+ const { stdout: statusOut } = await execa('git', ['status', '--porcelain=1', '-z', ...gitPathSpec], gitWorkspaceOptions);
74
+ const { stdout: diffOut } = await execa('git', ['diff', '--name-only', '-z', ...gitPathSpec], gitWorkspaceOptions);
69
75
 
70
- for (let i = 0; i < statusEntries.length; i += 1) {
71
- const entry = statusEntries[i];
72
- const statusPrefix = entry.slice(0, 3);
73
- const pathPart = entry.slice(3).trim();
76
+ const statusEntries = statusOut.split('\0').filter(Boolean);
77
+ const statusFiles: string[] = [];
74
78
 
75
- if (!pathPart) {
76
- continue;
77
- }
79
+ for (let i = 0; i < statusEntries.length; i += 1) {
80
+ const entry = statusEntries[i];
81
+ const statusPrefix = entry.slice(0, 3);
82
+ const pathPart = entry.slice(3).trim();
78
83
 
79
- if (statusPrefix.trim().startsWith('R')) {
80
- const renamedTarget = statusEntries[i + 1];
81
- if (renamedTarget) {
82
- statusFiles.push(renamedTarget);
83
- i += 1;
84
+ if (!pathPart) {
84
85
  continue;
85
86
  }
87
+
88
+ if (statusPrefix.trim().startsWith('R')) {
89
+ const renamedTarget = statusEntries[i + 1];
90
+ if (renamedTarget) {
91
+ statusFiles.push(renamedTarget);
92
+ i += 1;
93
+ continue;
94
+ }
95
+ }
96
+
97
+ statusFiles.push(pathPart);
86
98
  }
87
99
 
88
- statusFiles.push(pathPart);
89
- }
100
+ const diffFiles = diffOut.split('\0').filter(Boolean);
101
+ const unique = new Set([...statusFiles, ...diffFiles]);
102
+ return Array.from(unique);
103
+ };
90
104
 
91
- const diffFiles = diffOut.split('\0').filter(Boolean);
92
- const unique = new Set([...statusFiles, ...diffFiles]);
105
+ const collectWorkspaceFiles = async (): Promise<string[]> => {
106
+ const pathSpec = workspaceRelative === '' ? '.' : workspaceRelative;
107
+ const tracked = await listTrackedFiles(repoRoot, pathSpec || '.');
108
+ const untracked = await listUntrackedFiles(repoRoot, pathSpec || '.');
109
+ return Array.from(new Set([...tracked, ...untracked]));
110
+ };
93
111
 
94
- const resolved = Array.from(unique)
112
+ const pendingFiles = mode === 'preprod' ? await collectWorkspaceFiles() : await collectUncommittedFiles();
113
+
114
+ const resolved = pendingFiles
95
115
  .map((file) => normalize(file))
96
116
  .filter((file): file is string => Boolean(file));
97
117
 
@@ -105,6 +125,20 @@ export async function collectFiles(): Promise<string[]> {
105
125
  }
106
126
  }
107
127
 
128
+ async function listTrackedFiles(repoRoot: string, pathSpec: string): Promise<string[]> {
129
+ const { stdout } = await execa('git', ['ls-files', '-z', '--', pathSpec], {
130
+ cwd: repoRoot,
131
+ });
132
+ return stdout.split('\0').filter(Boolean);
133
+ }
134
+
135
+ async function listUntrackedFiles(repoRoot: string, pathSpec: string): Promise<string[]> {
136
+ const { stdout } = await execa('git', ['ls-files', '-z', '--others', '--exclude-standard', '--', pathSpec], {
137
+ cwd: repoRoot,
138
+ });
139
+ return stdout.split('\0').filter(Boolean);
140
+ }
141
+
108
142
  async function excludeIgnored(repoRoot: string, files: string[]): Promise<string[]> {
109
143
  if (files.length === 0) {
110
144
  return [];
@@ -0,0 +1,104 @@
1
+ const DEFAULT_AIA_BASE_URL = 'https://ai.enki.si';
2
+
3
+ function resolveAiaBaseUrl(): string {
4
+ const configured = process.env.AIA_BASE_URL || process.env.CR_AIA_AIA_BASE_URL;
5
+ const base = (configured || DEFAULT_AIA_BASE_URL).trim();
6
+ return base.replace(/\/$/, '');
7
+ }
8
+
9
+ function summarizeErrorBody(body: string): string {
10
+ if (!body.trim()) {
11
+ return 'No response body';
12
+ }
13
+
14
+ if (/<html/i.test(body)) {
15
+ const sanitized = body
16
+ .replace(/<script[\s\S]*?<\/script>/gi, ' ')
17
+ .replace(/<style[\s\S]*?<\/style>/gi, ' ')
18
+ .replace(/<[^>]+>/g, ' ')
19
+ .replace(/\s+/g, ' ')
20
+ .trim();
21
+ return sanitized ? `${sanitized.slice(0, 200)}${sanitized.length > 200 ? '…' : ''}` : 'HTML error response';
22
+ }
23
+
24
+ const normalized = body.replace(/\s+/g, ' ').trim();
25
+ if (!normalized) {
26
+ return 'Empty error body';
27
+ }
28
+ return normalized.length > 200 ? `${normalized.slice(0, 200)}…` : normalized;
29
+ }
30
+
31
+ class WebCheckRequestError extends Error {
32
+ status?: number;
33
+ detail?: string;
34
+
35
+ constructor(message: string, options?: { status?: number; detail?: string; cause?: unknown }) {
36
+ super(message, options?.cause ? { cause: options.cause } : undefined);
37
+ this.name = 'WebCheckRequestError';
38
+ this.status = options?.status;
39
+ this.detail = options?.detail;
40
+ }
41
+ }
42
+
43
+ async function extractErrorDetail(response: Response): Promise<string | undefined> {
44
+ const contentType = response.headers.get('content-type') || '';
45
+ if (contentType.includes('application/json')) {
46
+ try {
47
+ const payload = (await response.json()) as { error?: { message?: string }; message?: string };
48
+ return payload?.error?.message || payload?.message || JSON.stringify(payload);
49
+ } catch {
50
+ return undefined;
51
+ }
52
+ }
53
+
54
+ try {
55
+ const textBody = await response.text();
56
+ return summarizeErrorBody(textBody);
57
+ } catch {
58
+ return undefined;
59
+ }
60
+ }
61
+
62
+ async function sendWebCheckRequest(endpoint: string, payload: Record<string, unknown>): Promise<void> {
63
+ let response: Response;
64
+ try {
65
+ response = await fetch(endpoint, {
66
+ method: 'POST',
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ },
70
+ body: JSON.stringify(payload),
71
+ });
72
+ } catch (networkError) {
73
+ const message =
74
+ networkError instanceof Error ? networkError.message : 'Website check request failed due to an unknown error';
75
+ throw new WebCheckRequestError(`Website check request failed: ${message}`, { cause: networkError });
76
+ }
77
+
78
+ if (!response.ok) {
79
+ const detail = await extractErrorDetail(response);
80
+ const suffix = detail ? ` ${detail}` : '';
81
+ throw new WebCheckRequestError(`Website check failed (${response.status}).${suffix}`, {
82
+ status: response.status,
83
+ detail,
84
+ });
85
+ }
86
+ }
87
+
88
+ export async function triggerManualWebCheck(targetUrl: string): Promise<void> {
89
+ const baseUrl = resolveAiaBaseUrl();
90
+ const manualEndpoint = `${baseUrl}/api/manual/check`;
91
+ const legacyEndpoint = `${baseUrl}/api/check-website`;
92
+ const missingEndpointStatuses = new Set([404, 405, 501]);
93
+
94
+ try {
95
+ await sendWebCheckRequest(manualEndpoint, { url: targetUrl });
96
+ return;
97
+ } catch (error) {
98
+ if (!(error instanceof WebCheckRequestError) || !error.status || !missingEndpointStatuses.has(error.status)) {
99
+ throw error;
100
+ }
101
+ }
102
+
103
+ await sendWebCheckRequest(legacyEndpoint, { url: targetUrl, options: {} });
104
+ }
@@ -2,7 +2,7 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
2
2
  import { basename, isAbsolute, join, resolve } from 'node:path';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { execa } from 'execa';
5
- import { collectFiles } from './fileCollector';
5
+ import { collectFiles, type FileCollectionMode } from './fileCollector';
6
6
  import { loadManifest } from './manifest';
7
7
  import { runAiCodeReview } from './runAiCodeReview';
8
8
  import { ensureProxyEnvironmentInitialized } from './proxyEnvironment';
@@ -10,13 +10,17 @@ import { mergeReports } from './reportMerge';
10
10
  import { collectReportData } from './reporting/reportDataCollector';
11
11
  import { buildMarkdownReport, injectSummary } from './reporting/markdownReportBuilder';
12
12
  import { generateReportSummary } from './reporting/summaryGenerator';
13
+ import logger from '../utils/logger';
13
14
 
14
- export type ReviewStage = 'collecting' | 'reviewing' | 'merging';
15
+ export type ReviewStage = 'preparing' | 'collecting' | 'reviewing' | 'merging';
16
+ export type ReviewMode = FileCollectionMode;
15
17
 
16
18
  export interface ReviewOptions {
17
19
  model: string;
18
20
  outDir: string;
19
21
  debug?: boolean;
22
+ mode?: ReviewMode;
23
+ preprodTargetUrl?: string;
20
24
  onStage?: (stage: ReviewStage, info?: { filesFound?: number }) => void;
21
25
  }
22
26
 
@@ -37,10 +41,11 @@ export interface ReviewResult {
37
41
  }
38
42
 
39
43
  export async function executeReview(options: ReviewOptions): Promise<ReviewResult> {
40
- const { model, outDir, debug = false, onStage } = options;
44
+ const { model, outDir, debug = false, onStage, mode = 'uncommitted' } = options;
41
45
 
42
46
  onStage?.('collecting');
43
- const files = await collectFiles();
47
+ logger.info('Collecting files for review', { mode, workspace: process.cwd() });
48
+ const files = await collectFiles({ mode });
44
49
  const fileCount = files.length;
45
50
 
46
51
  if (fileCount === 0) {
@@ -48,6 +53,7 @@ export async function executeReview(options: ReviewOptions): Promise<ReviewResul
48
53
  }
49
54
 
50
55
  onStage?.('collecting', { filesFound: fileCount });
56
+ logger.info('File collection complete', { fileCount });
51
57
 
52
58
  const workspaceRoot = process.cwd();
53
59
  const repoRoot = await resolveRepoRoot();
@@ -1,16 +1,19 @@
1
- import React, { useCallback, useEffect, useState } from 'react';
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import { LayoutProvider, useLayout } from './Layout';
3
3
  import { AuthScreen } from './screens/AuthScreen';
4
4
  import { ModeSelection } from './screens/ModeSelection';
5
5
  import { ProgressScreen } from './screens/ProgressScreen';
6
6
  import { ResultsScreen } from './screens/ResultsScreen';
7
7
  import { getInk, getInkSpinner } from './inkModules';
8
- import type { ReviewResult, ReviewStage } from '../reviewPipeline';
8
+ import type { ReviewMode, ReviewResult, ReviewStage } from '../reviewPipeline';
9
9
  import { executeReview } from '../reviewPipeline';
10
10
  import { loadSession, getSessionToken } from '../auth/session';
11
11
  import type { SessionUser } from '../auth/types';
12
12
  import { RUNTIME_CONFIG } from '../runtimeConfig';
13
13
  import { MissingCrIgnoreError } from '../errors';
14
+ import { triggerManualWebCheck } from '../preprod/webCheck';
15
+ import { startDebugLogSession, type DebugLogSession } from '../debug/logManager';
16
+ import logger from '../../utils/logger';
14
17
 
15
18
  type ScreenState = 'auth' | 'mode' | 'progress' | 'results';
16
19
 
@@ -24,6 +27,10 @@ interface ProgressState {
24
27
  }
25
28
 
26
29
  const defaultProgress: ProgressState = { stage: 'collecting' };
30
+ const GENERIC_ERROR_MESSAGE =
31
+ 'Something went wrong. Press D to enable debug mode and rerun to capture logs.';
32
+ const PREPROD_ERROR_MESSAGE =
33
+ 'Could not start the website check. Double-check the URL or try again later.';
27
34
 
28
35
  function AppBody({ debug = false }: RuntimeAppProps) {
29
36
  const { Box, Text, useApp, useInput } = getInk();
@@ -33,8 +40,11 @@ function AppBody({ debug = false }: RuntimeAppProps) {
33
40
  const [user, setUser] = useState<SessionUser | null>(null);
34
41
  const [progress, setProgress] = useState<ProgressState>(defaultProgress);
35
42
  const [results, setResults] = useState<ReviewResult | null>(null);
43
+ const [debugEnabled, setDebugEnabled] = useState(false);
44
+ const [lastDebugLogPath, setLastDebugLogPath] = useState<string | null>(null);
36
45
  type ErrorInfo = { type: 'generic' | 'crignore'; message: string; hint?: string };
37
46
  const [error, setError] = useState<ErrorInfo | null>(null);
47
+ const combinedDebugFlag = useMemo(() => debug || debugEnabled, [debug, debugEnabled]);
38
48
 
39
49
  useEffect(() => {
40
50
  const sessionUser = loadSession();
@@ -68,23 +78,85 @@ function AppBody({ debug = false }: RuntimeAppProps) {
68
78
  setScreen('mode');
69
79
  }, []);
70
80
 
71
- const handleRunReview = useCallback(async (_mode: string) => {
81
+ const handleToggleDebug = useCallback(() => {
82
+ setDebugEnabled((prev) => {
83
+ if (prev) {
84
+ setLastDebugLogPath(null);
85
+ }
86
+ return !prev;
87
+ });
88
+ }, []);
89
+
90
+ const handleRunReview = useCallback(async (mode: ReviewMode, extras?: { targetUrl?: string }) => {
91
+ const trimmedUrl = extras?.targetUrl?.trim();
92
+
93
+ if (mode === 'preprod' && !trimmedUrl) {
94
+ setError({ type: 'generic', message: 'Pre-production mode requires a website URL.' });
95
+ return;
96
+ }
97
+
72
98
  setScreen('progress');
73
99
  setResults(null);
74
100
  setError(null);
75
- setProgress(defaultProgress);
101
+ setProgress(mode === 'preprod' ? { stage: 'preparing' } : defaultProgress);
102
+ setLastDebugLogPath(null);
103
+
104
+ let debugSession: DebugLogSession | null = null;
105
+ const finalizeDebugLogging = () => {
106
+ if (debugSession) {
107
+ debugSession.stop();
108
+ setLastDebugLogPath(debugSession.filePath);
109
+ } else {
110
+ setLastDebugLogPath(null);
111
+ }
112
+ };
113
+
114
+ if (debugEnabled) {
115
+ try {
116
+ debugSession = startDebugLogSession(process.cwd());
117
+ } catch (logInitError) {
118
+ const message =
119
+ logInitError instanceof Error
120
+ ? logInitError.message
121
+ : 'Unable to initialize debug logging.';
122
+ setError({ type: 'generic', message: `Debug logging disabled: ${message}` });
123
+ }
124
+ }
125
+
126
+ if (mode === 'preprod' && trimmedUrl) {
127
+ try {
128
+ logger.info('Triggering manual website check', { url: trimmedUrl });
129
+ await triggerManualWebCheck(trimmedUrl);
130
+ } catch (webError) {
131
+ logger.error('Pre-production web check failed', webError);
132
+ setError({ type: 'generic', message: PREPROD_ERROR_MESSAGE });
133
+ setScreen('mode');
134
+ finalizeDebugLogging();
135
+ return;
136
+ }
137
+ }
76
138
 
77
139
  try {
140
+ logger.info('Starting code review run', { mode, workspace: process.cwd(), preprodTarget: trimmedUrl });
141
+ setProgress({ stage: 'collecting' });
78
142
  const reviewResult = await executeReview({
79
143
  model: process.env.AI_CODE_REVIEW_MODEL || RUNTIME_CONFIG.DEFAULT_MODEL,
80
144
  outDir: './reports',
81
- debug,
145
+ debug: combinedDebugFlag,
146
+ mode,
147
+ preprodTargetUrl: trimmedUrl,
82
148
  onStage: (stage, info) => setProgress({ stage, filesFound: info?.filesFound }),
83
149
  });
84
150
 
151
+ logger.info('Code review run complete', {
152
+ mode,
153
+ durationSeconds: reviewResult.duration,
154
+ filesReviewed: reviewResult.filesReviewed,
155
+ });
85
156
  setResults(reviewResult);
86
157
  setScreen('results');
87
158
  } catch (reviewError) {
159
+ logger.error('Code review run failed', reviewError);
88
160
  if (reviewError instanceof MissingCrIgnoreError) {
89
161
  setError({
90
162
  type: 'crignore',
@@ -92,22 +164,28 @@ function AppBody({ debug = false }: RuntimeAppProps) {
92
164
  hint: `Create ${reviewError.crIgnorePath} (can be empty, gitignore syntax) and rerun.`,
93
165
  });
94
166
  } else {
95
- const message =
96
- reviewError instanceof Error
97
- ? reviewError.message
98
- : 'Failed to run review. Check proxy/auth configuration.';
99
- setError({ type: 'generic', message });
167
+ setError({ type: 'generic', message: GENERIC_ERROR_MESSAGE });
100
168
  }
101
169
  setScreen('mode');
170
+ } finally {
171
+ finalizeDebugLogging();
102
172
  }
103
- }, [debug]);
173
+ }, [combinedDebugFlag, debugEnabled]);
104
174
 
105
175
  return (
106
176
  <Box width={layout.frameWidth} flexDirection="column" gap={1}>
107
177
  {screen === 'auth' && <AuthScreen onAuth={handleAuth} />}
108
- {screen === 'mode' && user && <ModeSelection onSelect={(mode) => handleRunReview(mode)} />}
178
+ {screen === 'mode' && user && (
179
+ <ModeSelection
180
+ onSelect={(mode, payload) => handleRunReview(mode, payload)}
181
+ debugEnabled={debugEnabled}
182
+ onToggleDebug={handleToggleDebug}
183
+ />
184
+ )}
109
185
  {screen === 'progress' && <ProgressScreen stage={progress.stage} filesFound={progress.filesFound} />}
110
- {screen === 'results' && results && <ResultsScreen result={results} />}
186
+ {screen === 'results' && results && (
187
+ <ResultsScreen result={results} debugLogPath={lastDebugLogPath} />
188
+ )}
111
189
  {error && (
112
190
  <Box
113
191
  borderStyle="round"
@@ -121,6 +199,11 @@ function AppBody({ debug = false }: RuntimeAppProps) {
121
199
  </Text>
122
200
  </Box>
123
201
  )}
202
+ {lastDebugLogPath && screen !== 'results' && (
203
+ <Box>
204
+ <Text dimColor>Debug logs saved to: {lastDebugLogPath}</Text>
205
+ </Box>
206
+ )}
124
207
  <Box justifyContent="space-between">
125
208
  <Text dimColor>{user ? `Logged in as ${user.username}` : 'Authenticate to start reviewing'}</Text>
126
209
  <Text dimColor>Ctrl+C to exit</Text>
@@ -1,23 +1,154 @@
1
- import React from 'react';
2
- import { getInk, getInkSelectInput } from '../inkModules';
1
+ import React, { useCallback, useState } from 'react';
2
+ import { getInk, getInkSelectInput, getInkTextInput } from '../inkModules';
3
3
  import { useLayout } from '../Layout';
4
+ import type { ReviewMode } from '../../reviewPipeline';
4
5
 
5
6
  interface ModeSelectionProps {
6
- onSelect: (mode: string) => void;
7
+ onSelect: (mode: ReviewMode, extras?: { targetUrl?: string }) => void;
8
+ debugEnabled: boolean;
9
+ onToggleDebug: () => void;
7
10
  }
8
11
 
9
- const OPTIONS = [
12
+ interface ModeOption {
13
+ label: string;
14
+ value: ReviewMode;
15
+ description: string;
16
+ requiresUrl?: boolean;
17
+ }
18
+
19
+ const OPTIONS: ModeOption[] = [
10
20
  {
11
21
  label: 'Review uncommitted changes',
12
22
  value: 'uncommitted',
13
23
  description: 'Scan staged and unstaged changes only',
14
24
  },
25
+ {
26
+ label: 'Pre-production review',
27
+ value: 'preprod',
28
+ description: 'Scan the entire workspace and trigger website checks',
29
+ requiresUrl: true,
30
+ },
15
31
  ];
16
32
 
17
- export function ModeSelection({ onSelect }: ModeSelectionProps) {
18
- const { Box, Text } = getInk();
33
+ export function ModeSelection({ onSelect, debugEnabled, onToggleDebug }: ModeSelectionProps) {
34
+ const { Box, Text, useInput } = getInk();
19
35
  const SelectInput = getInkSelectInput();
36
+ const TextInput = getInkTextInput();
20
37
  const { frameWidth } = useLayout();
38
+ const [phase, setPhase] = useState<'list' | 'preprodUrl'>('list');
39
+ const [pendingMode, setPendingMode] = useState<ReviewMode>('preprod');
40
+ const [highlighted, setHighlighted] = useState<ReviewMode>('uncommitted');
41
+ const [urlValue, setUrlValue] = useState('');
42
+ const [urlError, setUrlError] = useState<string | null>(null);
43
+
44
+ const resetUrlState = useCallback(() => {
45
+ setUrlValue('');
46
+ setUrlError(null);
47
+ }, []);
48
+
49
+ const handleModeSelect = useCallback(
50
+ (mode: ReviewMode) => {
51
+ const option = OPTIONS.find((opt) => opt.value === mode);
52
+ if (!option) {
53
+ return;
54
+ }
55
+
56
+ if (option.requiresUrl) {
57
+ setPendingMode(option.value);
58
+ resetUrlState();
59
+ setPhase('preprodUrl');
60
+ return;
61
+ }
62
+
63
+ onSelect(option.value);
64
+ },
65
+ [onSelect, resetUrlState],
66
+ );
67
+
68
+ const submitUrl = useCallback(() => {
69
+ if (phase !== 'preprodUrl') {
70
+ return;
71
+ }
72
+
73
+ const trimmed = urlValue.trim();
74
+ if (!trimmed) {
75
+ setUrlError('URL is required');
76
+ return;
77
+ }
78
+
79
+ try {
80
+ const parsed = new URL(trimmed);
81
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
82
+ throw new Error('invalid');
83
+ }
84
+ setUrlError(null);
85
+ onSelect(pendingMode, { targetUrl: parsed.toString() });
86
+ } catch {
87
+ setUrlError('Enter a valid URL starting with http:// or https://');
88
+ }
89
+ }, [onSelect, pendingMode, phase, urlValue]);
90
+
91
+ useInput((input, key) => {
92
+ const normalizedInput = input.toLowerCase();
93
+ if (normalizedInput === 'd' && !key.ctrl && !key.meta) {
94
+ onToggleDebug();
95
+ return;
96
+ }
97
+
98
+ if (phase !== 'preprodUrl') {
99
+ return;
100
+ }
101
+
102
+ if (key.escape) {
103
+ setPhase('list');
104
+ resetUrlState();
105
+ return;
106
+ }
107
+
108
+ if (key.return) {
109
+ submitUrl();
110
+ }
111
+ });
112
+
113
+ if (phase === 'preprodUrl') {
114
+ return (
115
+ <Box
116
+ width={frameWidth}
117
+ flexDirection="column"
118
+ borderStyle="round"
119
+ borderColor="cyan"
120
+ paddingX={2}
121
+ paddingY={1}
122
+ gap={1}
123
+ >
124
+ <Text color="cyan" bold>
125
+ Pre-production review
126
+ </Text>
127
+ <Text dimColor>Enter the full website URL. We will trigger ai.enki.si and scan every file here.</Text>
128
+ <Box flexDirection="column">
129
+ <Text dimColor>Target URL</Text>
130
+ <TextInput
131
+ value={urlValue}
132
+ onChange={(value) => {
133
+ setUrlValue(value);
134
+ if (urlError) {
135
+ setUrlError(null);
136
+ }
137
+ }}
138
+ placeholder="https://example.com"
139
+ focus
140
+ />
141
+ </Box>
142
+ {urlError && (
143
+ <Text color="red">{urlError}</Text>
144
+ )}
145
+ <Box justifyContent="space-between">
146
+ <Text dimColor>Press Enter to start · Esc to go back</Text>
147
+ <Text dimColor>Debug: {debugEnabled ? 'On' : 'Off'} (press D)</Text>
148
+ </Box>
149
+ </Box>
150
+ );
151
+ }
21
152
 
22
153
  return (
23
154
  <Box
@@ -29,23 +160,25 @@ export function ModeSelection({ onSelect }: ModeSelectionProps) {
29
160
  paddingY={1}
30
161
  gap={1}
31
162
  >
32
- <Text color="green" bold>
33
- Choose review mode
34
- </Text>
163
+ <Box justifyContent="space-between" alignItems="center">
164
+ <Text color="green" bold>
165
+ Choose review mode
166
+ </Text>
167
+ <Text dimColor>Debug: {debugEnabled ? 'On' : 'Off'} (press D)</Text>
168
+ </Box>
35
169
  <Text dimColor>Use arrow keys, press Enter to start.</Text>
36
170
  <SelectInput
37
171
  items={OPTIONS.map((option) => ({
38
172
  label: option.label,
39
173
  value: option.value,
40
174
  }))}
41
- onSelect={(item) => onSelect(String(item.value))}
175
+ onHighlight={(item) => setHighlighted(item.value as ReviewMode)}
176
+ onSelect={(item) => handleModeSelect(item.value as ReviewMode)}
42
177
  />
43
178
  <Box flexDirection="column" marginTop={1}>
44
- {OPTIONS.map((option) => (
45
- <Text key={option.value} dimColor>
46
- · {option.description}
47
- </Text>
48
- ))}
179
+ <Text dimColor>
180
+ · {OPTIONS.find((option) => option.value === highlighted)?.description}
181
+ </Text>
49
182
  </Box>
50
183
  </Box>
51
184
  );